changeset 14885:000c283d7b71

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 30 Mar 2014 16:08:33 +0200
parents 1617b1e25d31 (current diff) 1415a62ac8b2 (diff)
children f02fc7294a1d
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ExternalCompilationResult.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java graal/findbugsExcludeFilter.xml src/gpu/hsail/vm/hsailKernelArguments.cpp
diffstat 500 files changed, 21300 insertions(+), 6555 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Wed Mar 19 11:43:57 2014 +0100
+++ b/.hgtags	Sun Mar 30 16:08:33 2014 +0200
@@ -408,3 +408,4 @@
 050a626a88951140df874f7b163e304d07b6c296 jdk9-b01
 b188446de75bda5fc52d102cddf242c3ef5ecbdf jdk9-b02
 b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03
+483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2
--- a/CHANGELOG.md	Wed Mar 19 11:43:57 2014 +0100
+++ b/CHANGELOG.md	Sun Mar 30 16:08:33 2014 +0200
@@ -2,24 +2,42 @@
 
 ## `tip`
 ### Graal
-* New methods for querying memory usage of individual objects and object graphs in Graal API (MetaAccessProvider#getMemorySize, MetaUtil#getMemorySizeRecursive).
-* New (tested) invariant that equality comparisons for JavaType/JavaMethod/JavaField values use .equals() instead of '=='.
+* ...
+### Truffle
+* ...
+
+## Version 0.2
+25-Mar-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.2)
+
+### Graal
+* Use HotSpot stubs for certain array copy operations.
+* New methods for querying memory usage of individual objects and object graphs in Graal API (`MetaAccessProvider#getMemorySize`, `MetaUtil#getMemorySizeRecursive`).
+* Added tiered configuration (C1 + Graal).
+* Initial security model for Graal [GRAAL-22](https://bugs.openjdk.java.net/browse/GRAAL-22).
+* New (tested) invariant that equality comparisons for `JavaType`/`JavaMethod`/`JavaField` values use `.equals()` instead of `==`.
 * Made graph caching compilation-local.
+* Added AllocSpy tool for analyzing allocation in Graal using the [Java Allocation Instrumenter](https://code.google.com/p/java-allocation-instrumenter/).
+* Initial support for memory arithmetic operations on x86
 
 ### Truffle
-* New API TruffleRuntime#createCallNode to create call nodes and to give the runtime system control over its implementation.
-* New API RootNode#getCachedCallNodes to get a weak set of CallNodes that have registered to call the RootNode.
-* New API to split the AST of a call-site context sensitively. CallNode#split, CallNode#isSplittable, CallNode#getSplitCallTarget, CallNode#getCurrentCallTarget, RootNode#isSplittable, RootNode#split.
-* New API to inline a call-site into the call-graph. CallNode#isInlinable, CallNode#inline, CallNode#isInlined.
-* New API for the runtime environment to register CallTargets as caller to the RootNode. CallNode#registerCallTarget.
-* Improved API for counting nodes in Truffle ASTS. NodeUtil#countNodes can be used with a NodeFilter filter Nodes.
-* New API to declare the cost of a Node for use in runtime environment specific heuristics. See NodeCost, Node#getCost() and NodeInfo#cost().
-* Removed old API for NodeInfo#Kind and NodeInfo#kind(). As a replacement the new Node cost API can be used.
-
+* New API `TruffleRuntime#createCallNode` to create call nodes and to give the runtime system control over its implementation.
+* New API `RootNode#getCachedCallNodes` to get a weak set of `CallNode`s that have registered to call the `RootNode`.
+* New API to split the AST of a call-site context sensitively. `CallNode#split`, `CallNode#isSplittable`, `CallNode#getSplitCallTarget`, `CallNode#getCurrentCallTarget`, `RootNode#isSplittable`, `RootNode#split`.
+* New API to inline a call-site into the call-graph. `CallNode#isInlinable`, `CallNode#inline`, `CallNode#isInlined`.
+* New API for the runtime environment to register `CallTarget`s as caller to the `RootNode`. `CallNode#registerCallTarget`.
+* Improved API for counting nodes in Truffle ASTs. `NodeUtil#countNodes` can be used with a `NodeFilter`.
+* New API to declare the cost of a Node for use in runtime environment specific heuristics. See `NodeCost`, `Node#getCost` and `NodeInfo#cost`.
+* Removed old API for `NodeInfo#Kind` and `NodeInfo#kind`. As a replacement the new `NodeCost` API can be used.
+* Changed `Node#replace` reason parameter type to `CharSequence` (to enable lazy string building)
+* Deprecated `Node#adoptChild` and `Node#adoptChild`, no longer needed in node constructor
+* New `Node#insert` method for inserting new nodes into the tree (formerly `adoptChild`)
+* New `Node#adoptChildren` helper method that adopts all (direct and indirect) children of a node
+* New API `Node#atomic` for atomic tree operations
+* Made `Node#replace` thread-safe
 
 
 ## Version 0.1
-5-Feb-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/b124e22eb772)
+5-Feb-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.1)
 
 ### Graal
 
--- a/README.md	Wed Mar 19 11:43:57 2014 +0100
+++ b/README.md	Sun Mar 30 16:08:33 2014 +0200
@@ -23,10 +23,11 @@
    Compilation with Graal is only done by explicit requests to the
    Graal API. This is how Truffle uses Graal.
    
-2. The 'graal' configuration is a VM where all compilation is performed
-   by Graal and no other compilers are built into the VM binary. This
-   VM will bootstrap Graal itself at startup unless the -XX:-BootstrapGraal
-   VM option is given.   
+2. The 'graal' configuration is a VM where normal compilations are performed
+   by Graal. This VM will bootstrap Graal itself at startup unless the
+   -XX:-BootstrapGraal. Note that if tiered compilation is enabled, Graal
+   will be used at the last tier while C1 will be used for the first compiled
+   tiers.
 
 Unless you use the --vm option with the build command, you will be presented
 with a dialogue to choose one of the above VM configurations for the build
@@ -78,5 +79,3 @@
 
 These configurations aim to match as closely as possible the
 VM(s) included in the OpenJDK binaries one can download.
- No newline at end of file
-
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,7 +26,6 @@
 import java.util.*;
 
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
 
 /**
  * Computes an ordering of the block that can be used by the linear scan register allocator and the
@@ -67,11 +66,11 @@
      * 
      * @return sorted list of blocks
      */
-    public static <T extends AbstractBlock<T>> List<T> computeLinearScanOrder(int blockCount, T startBlock, NodesToDoubles nodeProbabilities) {
+    public static <T extends AbstractBlock<T>> List<T> computeLinearScanOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) {
         List<T> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
-        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities);
-        computeLinearScanOrder(order, worklist, visitedBlocks, nodeProbabilities);
+        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities);
+        computeLinearScanOrder(order, worklist, visitedBlocks, blockProbabilities);
         assert checkOrder(order, blockCount);
         return order;
     }
@@ -81,11 +80,11 @@
      * 
      * @return sorted list of blocks
      */
-    public static <T extends AbstractBlock<T>> List<T> computeCodeEmittingOrder(int blockCount, T startBlock, NodesToDoubles nodeProbabilities) {
+    public static <T extends AbstractBlock<T>> List<T> computeCodeEmittingOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) {
         List<T> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
-        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities);
-        computeCodeEmittingOrder(order, worklist, visitedBlocks, nodeProbabilities);
+        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities);
+        computeCodeEmittingOrder(order, worklist, visitedBlocks, blockProbabilities);
         assert checkOrder(order, blockCount);
         return order;
     }
@@ -93,28 +92,28 @@
     /**
      * Iteratively adds paths to the code emission block order.
      */
-    private static <T extends AbstractBlock<T>> void computeCodeEmittingOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
+    private static <T extends AbstractBlock<T>> void computeCodeEmittingOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
         while (!worklist.isEmpty()) {
             T nextImportantPath = worklist.poll();
-            addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities);
+            addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities);
         }
     }
 
     /**
      * Iteratively adds paths to the linear scan block order.
      */
-    private static <T extends AbstractBlock<T>> void computeLinearScanOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
+    private static <T extends AbstractBlock<T>> void computeLinearScanOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
         while (!worklist.isEmpty()) {
             T nextImportantPath = worklist.poll();
-            addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities);
+            addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities);
         }
     }
 
     /**
      * Initializes the priority queue used for the work list of blocks and adds the start block.
      */
-    private static <T extends AbstractBlock<T>> PriorityQueue<T> initializeWorklist(T startBlock, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
-        PriorityQueue<T> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<T>(nodeProbabilities));
+    private static <T extends AbstractBlock<T>> PriorityQueue<T> initializeWorklist(T startBlock, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+        PriorityQueue<T> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<T>(blockProbabilities));
         result.add(startBlock);
         visitedBlocks.set(startBlock.getId());
         return result;
@@ -123,10 +122,10 @@
     /**
      * Add a linear path to the linear scan order greedily following the most likely successor.
      */
-    private static <T extends AbstractBlock<T>> void addPathToLinearScanOrder(T block, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
+    private static <T extends AbstractBlock<T>> void addPathToLinearScanOrder(T block, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
         block.setLinearScanNumber(order.size());
         order.add(block);
-        T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, nodeProbabilities);
+        T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities);
         enqueueSuccessors(block, worklist, visitedBlocks);
         if (mostLikelySuccessor != null) {
             if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) {
@@ -135,17 +134,17 @@
                 double unscheduledSum = 0.0;
                 for (T pred : mostLikelySuccessor.getPredecessors()) {
                     if (pred.getLinearScanNumber() == -1) {
-                        unscheduledSum += nodeProbabilities.get(pred.getBeginNode());
+                        unscheduledSum += blockProbabilities.get(pred);
                     }
                 }
 
-                if (unscheduledSum > nodeProbabilities.get(block.getBeginNode()) / PENALTY_VERSUS_UNSCHEDULED) {
+                if (unscheduledSum > blockProbabilities.get(block) / PENALTY_VERSUS_UNSCHEDULED) {
                     // Add this merge only after at least one additional predecessor gets scheduled.
                     visitedBlocks.clear(mostLikelySuccessor.getId());
                     return;
                 }
             }
-            addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks, nodeProbabilities);
+            addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks, blockProbabilities);
         }
     }
 
@@ -153,7 +152,7 @@
      * Add a linear path to the code emission order greedily following the most likely successor.
      */
     @SuppressWarnings("unchecked")
-    private static <T extends AbstractBlock<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
+    private static <T extends AbstractBlock<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
         T block = initialBlock;
         while (block != null) {
             // Skip loop headers if there is only a single loop end block to
@@ -184,7 +183,7 @@
                 }
             }
 
-            T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, nodeProbabilities);
+            T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities);
             enqueueSuccessors(block, worklist, visitedBlocks);
             block = mostLikelySuccessor;
         }
@@ -201,12 +200,11 @@
     /**
      * Find the highest likely unvisited successor block of a given block.
      */
-    private static <T extends AbstractBlock<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
+    private static <T extends AbstractBlock<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
         T result = null;
         for (T successor : block.getSuccessors()) {
-            assert nodeProbabilities.get(successor.getBeginNode()) >= 0.0 : "Probabilities must be positive";
-            if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() &&
-                            (result == null || nodeProbabilities.get(successor.getBeginNode()) >= nodeProbabilities.get(result.getBeginNode()))) {
+            assert blockProbabilities.get(successor) >= 0.0 : "Probabilities must be positive";
+            if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || blockProbabilities.get(successor) >= blockProbabilities.get(result))) {
                 result = successor;
             }
         }
@@ -249,9 +247,9 @@
      */
     private static class BlockOrderComparator<T extends AbstractBlock<T>> implements Comparator<T> {
 
-        private final NodesToDoubles probabilities;
+        private final BlocksToDoubles probabilities;
 
-        public BlockOrderComparator(NodesToDoubles probabilities) {
+        public BlockOrderComparator(BlocksToDoubles probabilities) {
             this.probabilities = probabilities;
         }
 
@@ -264,7 +262,7 @@
             }
 
             // Blocks with high probability before blocks with low probability.
-            if (probabilities.get(a.getBeginNode()) > probabilities.get(b.getBeginNode())) {
+            if (probabilities.get(a) > probabilities.get(b)) {
                 return -1;
             } else {
                 return 1;
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Sun Mar 30 16:08:33 2014 +0200
@@ -160,68 +160,79 @@
         public abstract void emit(TargetDescription target, ByteBuffer buffer);
     }
 
+    public abstract static class ConstantData extends Data {
+
+        private final Constant constant;
+
+        protected ConstantData(Constant constant, int alignment) {
+            super(alignment);
+            this.constant = constant;
+        }
+
+        public Constant getConstant() {
+            return constant;
+        }
+    }
+
     /**
      * Represents a Java primitive value used in a {@link DataPatch}. This implementation uses
      * {@link Kind#getByteCount()} bytes to encode each value.
      */
-    public static final class PrimitiveData extends Data {
-
-        public final Constant constant;
+    public static final class PrimitiveData extends ConstantData {
 
         public PrimitiveData(Constant constant, int alignment) {
-            super(alignment);
+            super(constant, alignment);
             assert constant.getKind().isPrimitive();
-            this.constant = constant;
         }
 
         @Override
         public int getSize(TargetDescription target) {
-            return constant.getKind().getByteCount();
+            return getConstant().getKind().getByteCount();
         }
 
         @Override
         public Kind getKind() {
-            return constant.getKind();
+            return getConstant().getKind();
         }
 
         @Override
         public void emit(TargetDescription target, ByteBuffer buffer) {
-            switch (constant.getKind()) {
+            switch (getConstant().getKind()) {
                 case Boolean:
-                    buffer.put(constant.asBoolean() ? (byte) 1 : (byte) 0);
+                    buffer.put(getConstant().asBoolean() ? (byte) 1 : (byte) 0);
                     break;
                 case Byte:
-                    buffer.put((byte) constant.asInt());
+                    buffer.put((byte) getConstant().asInt());
                     break;
                 case Char:
-                    buffer.putChar((char) constant.asInt());
+                    buffer.putChar((char) getConstant().asInt());
                     break;
                 case Short:
-                    buffer.putShort((short) constant.asInt());
+                    buffer.putShort((short) getConstant().asInt());
                     break;
                 case Int:
-                    buffer.putInt(constant.asInt());
+                    buffer.putInt(getConstant().asInt());
                     break;
                 case Long:
-                    buffer.putLong(constant.asLong());
+                    buffer.putLong(getConstant().asLong());
                     break;
                 case Float:
-                    buffer.putFloat(constant.asFloat());
+                    buffer.putFloat(getConstant().asFloat());
                     break;
                 case Double:
-                    buffer.putDouble(constant.asDouble());
+                    buffer.putDouble(getConstant().asDouble());
                     break;
             }
         }
 
         @Override
         public String toString() {
-            return constant.toString();
+            return getConstant().toString();
         }
 
         @Override
         public int hashCode() {
-            return constant.hashCode();
+            return getConstant().hashCode();
         }
 
         @Override
@@ -231,7 +242,7 @@
             }
             if (obj instanceof PrimitiveData) {
                 PrimitiveData other = (PrimitiveData) obj;
-                return constant.equals(other.constant);
+                return getConstant().equals(other.getConstant());
             } else {
                 return false;
             }
@@ -591,7 +602,15 @@
         addInfopoint(new Infopoint(codePos, debugInfo, reason));
     }
 
-    private void addInfopoint(Infopoint infopoint) {
+    /**
+     * Records a custom infopoint in the code section.
+     * 
+     * Compiler implementations can use this method to record non-standard infopoints, which are not
+     * handled by the dedicated methods like {@link #recordCall}.
+     * 
+     * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint}
+     */
+    public void addInfopoint(Infopoint infopoint) {
         // The infopoints list must always be sorted
         if (!infopoints.isEmpty() && infopoints.get(infopoints.size() - 1).pcOffset >= infopoint.pcOffset) {
             // This re-sorting should be very rare
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ExternalCompilationResult.java	Wed Mar 19 11:43:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.api.code;
-
-/**
- * Represents the output from compiling a method generated by Graal, but executing in a memory and
- * computational subsystem outside the Graal host system.
- * 
- * Output may include the compiled machine code, associated data and references, relocation
- * information, deoptimization information, as this result is generated from a structure graph on
- * the Graal host system.
- */
-public class ExternalCompilationResult extends CompilationResult {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * Address of the point of entry to the external compilation result.
-     */
-    private long entryPoint;
-
-    public ExternalCompilationResult() {
-        super();
-    }
-
-    /**
-     * Set the address for the point of entry to the external compilation result.
-     * 
-     * @param addr the address of the entry point
-     */
-    public void setEntryPoint(long addr) {
-        entryPoint = addr;
-    }
-
-    /**
-     * Return the address for the point of entry to the external compilation result.
-     * 
-     * @return address value
-     */
-    public long getEntryPoint() {
-        return entryPoint;
-    }
-
-    /**
-     * Gets the {@linkplain #getTargetCode() code} in this compilation result as a string.
-     */
-    public String getCodeString() {
-        return new String(getTargetCode(), 0, getTargetCodeSize());
-    }
-}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,6 +29,8 @@
 
     void setRegister(int idx, PlatformKind kind);
 
+    PlatformKind getRegister(int idx);
+
     void setStackSlot(int offset, PlatformKind kind);
 
     boolean hasRegisterRefMap();
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java	Sun Mar 30 16:08:33 2014 +0200
@@ -102,4 +102,10 @@
      * @return the register playing the role specified by {@code id}
      */
     Register getRegisterForRole(int id);
+
+    /**
+     * Determines if all {@link #getAllocatableRegisters() allocatable} registers are
+     * {@link #getCallerSaveRegisters() caller saved}.
+     */
+    boolean areAllAllocatableRegistersCallerSaved();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/KindInterface.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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.api.meta;
+
+public interface KindInterface {
+
+    Kind getKind();
+
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Sun Mar 30 16:08:33 2014 +0200
@@ -28,7 +28,7 @@
  * Abstract base class for values manipulated by the compiler. All values have a {@linkplain Kind
  * kind} and are immutable.
  */
-public abstract class Value implements Serializable {
+public abstract class Value implements Serializable, KindInterface {
 
     private static final long serialVersionUID = -6909397188697766469L;
 
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -1213,6 +1213,7 @@
         emitByte(0xD0 | encode);
     }
 
+    @Override
     public final void ensureUniquePC() {
         nop();
     }
@@ -1669,6 +1670,13 @@
         emitInt(imm32);
     }
 
+    public final void testl(AMD64Address dst, int imm32) {
+        prefixq(dst);
+        emitByte(0xF7);
+        emitOperandHelper(0, dst);
+        emitInt(imm32);
+    }
+
     public final void testl(Register dst, Register src) {
         prefixAndEncode(dst.encoding, src.encoding);
         emitArith(0x85, 0xC0, dst, src);
@@ -2064,6 +2072,13 @@
         emitOperandHelper(dst, src);
     }
 
+    public final void cmpq(AMD64Address dst, int imm32) {
+        prefixq(dst);
+        emitByte(0x81);
+        emitOperandHelper(7, dst);
+        emitInt(imm32);
+    }
+
     public final void cmpq(Register dst, int imm32) {
         prefixqAndEncode(dst.encoding);
         emitArith(0x81, 0xF8, dst, imm32);
@@ -2410,6 +2425,13 @@
         emitOperandHelper(dst, src);
     }
 
+    public final void testq(AMD64Address dst, int imm32) {
+        prefixq(dst);
+        emitByte(0xF7);
+        emitOperandHelper(0, dst);
+        emitInt(imm32);
+    }
+
     public final void xorq(Register dst, int imm32) {
         prefixqAndEncode(dst.encoding);
         emitArith(0x81, 0xF0, dst, imm32);
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -47,7 +47,11 @@
 
     @Override
     public void jmp(Label l) {
-        emitString("brn " + nameOf(l) + ";");
+        emitJumpToLabelName(nameOf(l));
+    }
+
+    public void emitJumpToLabelName(String labelName) {
+        emitString("brn " + labelName + ";");
     }
 
     @Override
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -20,20 +20,17 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package com.oracle.graal.asm.hsail;
 
-import java.lang.reflect.*;
-
-import com.oracle.graal.api.code.*;
-
 import static com.oracle.graal.api.code.MemoryBarriers.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hsail.*;
 import com.oracle.graal.graph.GraalInternalError;
 import com.amd.okra.OkraUtil;
+import java.lang.reflect.Array;
 
 /**
  * This class contains routines to emit HSAIL assembly code.
@@ -68,6 +65,11 @@
         return null;
     }
 
+    @Override
+    public final void ensureUniquePC() {
+        throw GraalInternalError.unimplemented();
+    }
+
     public final void undefined(String str) {
         emitString("undefined operation " + str);
     }
@@ -158,6 +160,10 @@
         emitAddrOp("lda_global_u64", dest, addr);
     }
 
+    public final void emitLoadKernelArg(Value dest, String kernArgName, String argTypeStr) {
+        emitString("ld_kernarg_" + argTypeStr + " " + HSAIL.mapRegister(dest) + ", [" + kernArgName + "];");
+    }
+
     public final void emitStore(Kind kind, Value src, HSAILAddress addr) {
         emitStore(src, addr, getArgTypeFromKind(kind));
     }
@@ -314,6 +320,12 @@
         emitString(prefix + destType + "_" + srcType + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";");
     }
 
+    public void emitConvert(Value dest, Value src, Kind destKind, Kind srcKind) {
+        String destType = getArgTypeFromKind(destKind);
+        String srcType = getArgTypeFromKind(srcKind);
+        emitConvert(dest, src, destType, srcType);
+    }
+
     /**
      * Emits a convert instruction that uses unsigned prefix, regardless of the type of dest and
      * src.
@@ -335,6 +347,7 @@
         } else {
             Constant consrc = asConstant(src);
             switch (src.getKind()) {
+                case Boolean:
                 case Int:
                     return Integer.toString(consrc.asInt());
                 case Float:
@@ -416,9 +429,13 @@
                 // Emit an instruction with two source operands.
                 emitString(String.format("%s %s, %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0]), mapRegOrConstToString(sources[1])));
                 break;
+            case 1:
+                // Emit an instruction with one source operand.
+                emitString(String.format("%s %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0])));
+                break;
             default:
                 // Emit an instruction with one source operand.
-                emitString(String.format("%s %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0])));
+                emitString(String.format("%s %s;", instr, HSAIL.mapRegister(dest)));
                 break;
         }
     }
@@ -518,9 +535,20 @@
      * @param newValue the new value that will be written to the memory location if the cmpValue
      *            comparison matches
      */
-    public void emitAtomicCas(AllocatableValue result, HSAILAddress address, AllocatableValue cmpValue, AllocatableValue newValue) {
-        emitString(String.format("atomic_cas_global_b%d   %s, %s, %s, %s;", getArgSize(cmpValue), HSAIL.mapRegister(result), mapAddress(address), HSAIL.mapRegister(cmpValue),
-                        HSAIL.mapRegister(newValue)));
+    public void emitAtomicCas(AllocatableValue result, HSAILAddress address, Value cmpValue, Value newValue) {
+        emitString(String.format("atomic_cas_global_b%d   %s, %s, %s, %s;", getArgSize(cmpValue), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(cmpValue),
+                        mapRegOrConstToString(newValue)));
+    }
+
+    /**
+     * Emits an atomic_add_global instruction.
+     * 
+     * @param result result operand that gets the original contents of the memory location
+     * @param address the memory location
+     * @param deltaValue the amount to add
+     */
+    public void emitAtomicAdd(AllocatableValue result, HSAILAddress address, Value deltaValue) {
+        emitString(String.format("atomic_add_global_u%d   %s, %s, %s;", getArgSize(result), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(deltaValue)));
     }
 
     /**
@@ -532,7 +560,52 @@
         emitString(comment);
     }
 
+    public String getDeoptInfoName() {
+        return "%_deoptInfo";
+    }
+
+    public String getDeoptLabelName() {
+        return "@L_Deopt";
+    }
+
+    public void emitWorkItemAbsId(Value dest) {
+        emitString(String.format("workitemabsid_u32 %s, 0;", HSAIL.mapRegister(dest)));
+    }
+
+    public void emitCuId(Value dest) {
+        emitString(String.format("cuid_u32 %s;", HSAIL.mapRegister(dest)));
+    }
+
+    public void emitLaneId(Value dest) {
+        emitString(String.format("laneid_u32 %s;", HSAIL.mapRegister(dest)));
+    }
+
+    public void emitWaveId(Value dest) {
+        emitString(String.format("waveid_u32 %s;", HSAIL.mapRegister(dest)));
+    }
+
+    public void emitMaxWaveId(Value dest) {
+        // emitString(String.format("maxwaveid_u32 %s;", HSAIL.mapRegister(dest)));
+        int hardCodedMaxWaveId = 36;
+        emitComment("// Hard-coded maxwaveid=" + hardCodedMaxWaveId + " until it works");
+        emitMov(dest, Constant.forInt(hardCodedMaxWaveId));
+    }
+
+    public void emitMultiplyByWavesize(Value dest) {
+        String regName = HSAIL.mapRegister(dest);
+        emitString(String.format("mul_u%d %s, %s, WAVESIZE;", getArgSize(dest), regName, regName));
+    }
+
+    public void emitGetWavesize(Value dest) {
+        String regName = HSAIL.mapRegister(dest);
+        emitString(String.format("mov_b%d %s, WAVESIZE;", getArgSize(dest), regName));
+    }
+
+    public void emitLoadAcquire(Value dest, HSAILAddress address) {
+        emitString(String.format("ld_global_acq_u%d %s, %s;", getArgSize(dest), HSAIL.mapRegister(dest), mapAddress(address)));
+    }
+
     public void emitStoreRelease(Value src, HSAILAddress address) {
-        emitAddrOp("st_global_rel_u" + getArgSize(src), src, address);
+        emitString(String.format("st_global_rel_u%d %s, %s;", getArgSize(src), HSAIL.mapRegister(src), mapAddress(address)));
     }
 }
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -696,6 +696,11 @@
     }
 
     @Override
+    public final void ensureUniquePC() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
     public void jmp(Label l) {
         String str = nameOf(l);
         bra(str);
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -74,6 +74,7 @@
         return Placeholder;
     }
 
+    @Override
     public final void ensureUniquePC() {
         new Nop().emit(this);
     }
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -183,4 +183,9 @@
      * Returns a target specific placeholder address that can be used for code patching.
      */
     public abstract AbstractAddress getPlaceholder();
+
+    /**
+     * Emits a NOP instruction to advance the current PC.
+     */
+    public abstract void ensureUniquePC();
 }
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,43 +23,41 @@
 package com.oracle.graal.baseline;
 
 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.phases.GraalOptions.*;
 import static java.lang.reflect.Modifier.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
+import com.oracle.graal.alloc.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
 import com.oracle.graal.bytecode.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.alloc.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
-import com.oracle.graal.java.BciBlockMapping.Block;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
-import com.oracle.graal.java.GraphBuilderPhase.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.nodes.java.*;
 
 /**
  * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
  */
 @SuppressWarnings("all")
-public class BaselineCompiler {
+public class BaselineCompiler implements BytecodeParser<BciBlock> {
 
     public BaselineCompiler(GraphBuilderConfiguration graphBuilderConfig, MetaAccessProvider metaAccess) {
         this.graphBuilderConfig = graphBuilderConfig;
@@ -73,13 +71,19 @@
     private ProfilingInfo profilingInfo;
     private BytecodeStream stream;           // the bytecode stream
 
-    private Block currentBlock;
+    private Backend backend;
+    private LIRGenerator lirGen;
+    private LIRFrameStateBuilder frameState;
+    private LIRGenerationResult lirGenRes;
+
+    private BciBlock currentBlock;
 
     private ValueNode methodSynchronizedObject;
     private ExceptionDispatchBlock unwindBlock;
 
     private final GraphBuilderConfiguration graphBuilderConfig;
-    private Block[] loopHeaders;
+    private BciBlock[] loopHeaders;
+    private BytecodeParseHelper<Value> parserHelper;
 
     /**
      * Meters the number of actual bytecodes parsed.
@@ -90,9 +94,11 @@
         return method;
     }
 
-    public LIR generate(ResolvedJavaMethod method, int entryBCI) {
+    public CompilationResult generate(ResolvedJavaMethod method, int entryBCI, Backend backend, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
+                    CompilationResultBuilderFactory factory) {
         this.method = method;
         this.entryBCI = entryBCI;
+        this.backend = backend;
         profilingInfo = method.getProfilingInfo();
         assert method.getCode() != null : "method must contain bytecodes: " + method;
         this.stream = new BytecodeStream(method.getCode());
@@ -100,12 +106,22 @@
         unwindBlock = null;
         methodSynchronizedObject = null;
         TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
+
+        frameState = new LIRFrameStateBuilder(method);
+        parserHelper = new BytecodeParseHelper<>(frameState);
+
+        // build blocks and LIR instructions
         try {
             build();
         } finally {
             filter.remove();
         }
-        return null;
+
+        // emitCode
+        Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
+        GraalCompiler.emitCode(backend, assumptions, lirGenRes, compilationResult, installedCodeOwner, factory);
+
+        return compilationResult;
     }
 
     protected void build() {
@@ -114,12 +130,19 @@
             TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), "  "));
         }
 
-        Indent indent = Debug.logAndIndent("build graph for %s", method);
+        // Indent indent = Debug.logAndIndent("build graph for %s", method);
 
         // compute the block map, setup exception handlers and get the entrypoint(s)
         BciBlockMapping blockMap = BciBlockMapping.create(method);
         loopHeaders = blockMap.loopHeaders;
 
+        // add predecessors
+        for (BciBlock block : blockMap.blocks) {
+            for (BciBlock successor : block.getSuccessors()) {
+                successor.getPredecessors().add(block);
+            }
+        }
+
         if (isSynchronized(method.getModifiers())) {
             throw GraalInternalError.unimplemented("Handle synchronized methods");
         }
@@ -131,11 +154,56 @@
             throw GraalInternalError.unimplemented("Handle start block as loop header");
         }
 
-        for (Block block : blockMap.blocks) {
-            processBlock(block);
+        // add loops ? how do we add looks when we haven't parsed the bytecode?
+
+        // create the control flow graph
+        LIRControlFlowGraph cfg = new LIRControlFlowGraph(blockMap.blocks.toArray(new BciBlock[0]), new Loop[0]);
+
+        BlocksToDoubles blockProbabilities = new BlocksToDoubles(blockMap.blocks.size());
+        for (BciBlock b : blockMap.blocks) {
+            blockProbabilities.put(b, 1);
         }
 
-        indent.outdent();
+        // create the LIR
+        List<? extends AbstractBlock<?>> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.blocks.size(), blockMap.startBlock, blockProbabilities);
+        List<? extends AbstractBlock<?>> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.blocks.size(), blockMap.startBlock, blockProbabilities);
+        LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder);
+
+        FrameMap frameMap = backend.newFrameMap();
+        TargetDescription target = backend.getTarget();
+        CallingConvention cc = CodeUtil.getCallingConvention(backend.getProviders().getCodeCache(), CallingConvention.Type.JavaCallee, method, false);
+        this.lirGenRes = backend.newLIRGenerationResult(lir, frameMap, null);
+        this.lirGen = backend.newLIRGenerator(cc, lirGenRes);
+
+        try (Scope ds = Debug.scope("BackEnd", lir)) {
+            try (Scope s = Debug.scope("LIRGen", lirGen)) {
+
+                // possibly add all the arguments to slots in the local variable array
+
+                for (BciBlock block : blockMap.blocks) {
+
+                    // lirGen.doBlock(block, method, this);
+                }
+                // indent.outdent();
+
+                lirGen.beforeRegisterAllocation();
+                Debug.dump(lir, "After LIR generation");
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+
+            // try (Scope s = Debug.scope("Allocator", nodeLirGen)) {
+            try (Scope s = Debug.scope("Allocator")) {
+
+                if (backend.shouldAllocateRegisters()) {
+                    new LinearScan(target, lir, frameMap).allocate();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     public BytecodeStream stream() {
@@ -147,11 +215,11 @@
     }
 
     private void loadLocal(int index, Kind kind) {
-        throw GraalInternalError.unimplemented();
+        parserHelper.loadLocal(index, kind);
     }
 
     private void storeLocal(Kind kind, int index) {
-        throw GraalInternalError.unimplemented();
+        parserHelper.storeLocal(kind, index);
     }
 
     /**
@@ -250,7 +318,10 @@
     }
 
     private void genArithmeticOp(Kind result, int opcode) {
-        throw GraalInternalError.unimplemented();
+        Value a = frameState.ipop();
+        Value b = frameState.ipop();
+        Value r = lirGen.emitAdd(a, b);
+        frameState.ipush(r);
     }
 
     private void genIntegerDivOp(Kind result, int opcode) {
@@ -434,18 +505,18 @@
         throw GraalInternalError.unimplemented();
     }
 
-    private void processBlock(Block block) {
-        Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, block.firstInstruction, block.isLoopHeader);
-        currentBlock = block;
-        iterateBytecodesForBlock(block);
-        indent.outdent();
+    public void processBlock(BciBlock block) {
+        try (Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, block.firstInstruction, block.isLoopHeader)) {
+            currentBlock = block;
+            iterateBytecodesForBlock(block);
+        }
     }
 
     private void createExceptionDispatch(ExceptionDispatchBlock block) {
         throw GraalInternalError.unimplemented();
     }
 
-    private void iterateBytecodesForBlock(Block block) {
+    private void iterateBytecodesForBlock(BciBlock block) {
 
         int endBCI = stream.endBCI();
 
@@ -646,12 +717,12 @@
             case RET            : genRet(stream.readLocalIndex()); break;
             case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(stream(), bci())); break;
             case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(stream(), bci())); break;
-//            case IRETURN        : genReturn(frameState.ipop()); break;
-//            case LRETURN        : genReturn(frameState.lpop()); break;
-//            case FRETURN        : genReturn(frameState.fpop()); break;
-//            case DRETURN        : genReturn(frameState.dpop()); break;
-//            case ARETURN        : genReturn(frameState.apop()); break;
-//            case RETURN         : genReturn(null); break;
+            case IRETURN        : genReturn(frameState.ipop()); break;
+            case LRETURN        : genReturn(frameState.lpop()); break;
+            case FRETURN        : genReturn(frameState.fpop()); break;
+            case DRETURN        : genReturn(frameState.dpop()); break;
+            case ARETURN        : genReturn(frameState.apop()); break;
+            case RETURN         : genReturn(null); 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;
@@ -700,11 +771,31 @@
             if (!currentBlock.jsrScope.isEmpty()) {
                 sb.append(' ').append(currentBlock.jsrScope);
             }
-            Debug.log(sb.toString());
+            Debug.log("%s", sb);
         }
     }
 
     private void genArrayLength() {
         throw GraalInternalError.unimplemented();
     }
+
+    private void genReturn(Value x) {
+        // frameState.setRethrowException(false);
+        frameState.clearStack();
+        // if (graphBuilderConfig.eagerInfopointMode()) {
+        // append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci())));
+        // }
+
+        // synchronizedEpilogue(FrameState.AFTER_BCI, x);
+        // if (frameState.lockDepth() != 0) {
+        // throw new BailoutException("unbalanced monitors");
+        // }
+
+        // lirGen.visitReturn(x);
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void setParameter(int i, Variable emitMove) {
+        frameState.storeLocal(i, emitMove);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.baseline;
+
+import java.util.*;
+
+import com.oracle.graal.nodes.cfg.*;
+
+public class LIRBlock extends AbstractBlockBase<LIRBlock> {
+
+    public LIRBlock(int id) {
+        this.id = id;
+        predecessors = Collections.emptyList();
+        successors = Collections.emptyList();
+    }
+
+    public Loop getLoop() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public int getLoopDepth() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public boolean isLoopEnd() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public boolean isLoopHeader() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public boolean isExceptionEntry() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.baseline;
+
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.nodes.cfg.*;
+
+public class LIRControlFlowGraph implements AbstractControlFlowGraph<BciBlock> {
+
+    private BciBlock[] blocks;
+    private Loop[] loops;
+
+    public LIRControlFlowGraph(BciBlock[] blocks, Loop[] loops) {
+        this.blocks = blocks;
+        this.loops = loops;
+    }
+
+    public BciBlock[] getBlocks() {
+        return blocks;
+    }
+
+    public Loop[] getLoops() {
+        return loops;
+    }
+
+    public BciBlock getStartBlock() {
+        if (blocks.length > 0) {
+            return blocks[0];
+        }
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRFrameStateBuilder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.baseline;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.*;
+
+public class LIRFrameStateBuilder extends AbstractFrameStateBuilder<Value> {
+
+    private final Value[] locals;
+    private final Value[] stack;
+    private Value[] lockedObjects;
+
+    public LIRFrameStateBuilder(ResolvedJavaMethod method) {
+        super(method);
+
+        this.locals = new Value[method.getMaxLocals()];
+        // we always need at least one stack slot (for exceptions)
+        this.stack = new Value[Math.max(1, method.getMaxStackSize())];
+    }
+
+    protected LIRFrameStateBuilder(LIRFrameStateBuilder other) {
+        super(other);
+        // TODO Auto-generated constructor stub
+        locals = other.locals;
+        stack = other.stack;
+        lockedObjects = other.lockedObjects;
+    }
+
+    @Override
+    public int localsSize() {
+        return locals.length;
+    }
+
+    @Override
+    public Value localAt(int i) {
+        return locals[i];
+    }
+
+    @Override
+    public Value stackAt(int i) {
+        return stack[i];
+    }
+
+    @Override
+    public Value loadLocal(int i) {
+        Value x = locals[i];
+        assert !isTwoSlot(x.getKind()) || locals[i + 1] == null;
+        assert i == 0 || locals[i - 1] == null || !isTwoSlot(locals[i - 1].getKind());
+        return x;
+    }
+
+    @Override
+    public void storeLocal(int i, Value x) {
+        assert x == null || x.getKind() != Kind.Void && x.getKind() != Kind.Illegal : "unexpected value: " + x;
+        locals[i] = x;
+        if (x != null && isTwoSlot(x.getKind())) {
+            // if this is a double word, then kill i+1
+            locals[i + 1] = null;
+        }
+        if (x != null && i > 0) {
+            Value p = locals[i - 1];
+            if (p != null && isTwoSlot(p.getKind())) {
+                // if there was a double word at i - 1, then kill it
+                locals[i - 1] = null;
+            }
+        }
+    }
+
+    @Override
+    public void storeStack(int i, Value 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;
+    }
+
+    @Override
+    public void push(Kind kind, Value x) {
+        assert x.getKind() != Kind.Void && x.getKind() != Kind.Illegal;
+        xpush(assertKind(kind, x));
+        if (isTwoSlot(kind)) {
+            xpush(null);
+        }
+    }
+
+    @Override
+    public void xpush(Value x) {
+        assert x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        stack[stackSize++] = x;
+    }
+
+    @Override
+    public void ipush(Value x) {
+        xpush(assertInt(x));
+    }
+
+    @Override
+    public void fpush(Value x) {
+        xpush(assertFloat(x));
+    }
+
+    @Override
+    public void apush(Value x) {
+        xpush(assertObject(x));
+    }
+
+    @Override
+    public void lpush(Value x) {
+        xpush(assertLong(x));
+    }
+
+    @Override
+    public void dpush(Value x) {
+        xpush(assertDouble(x));
+
+    }
+
+    @Override
+    public void pushReturn(Kind kind, Value x) {
+        if (kind != Kind.Void) {
+            push(kind.getStackKind(), x);
+        }
+    }
+
+    @Override
+    public Value pop(Kind kind) {
+        assert kind != Kind.Void;
+        if (isTwoSlot(kind)) {
+            xpop();
+        }
+        return assertKind(kind, xpop());
+    }
+
+    @Override
+    public Value xpop() {
+        Value result = stack[--stackSize];
+        return result;
+    }
+
+    @Override
+    public Value ipop() {
+        return assertInt(xpop());
+    }
+
+    @Override
+    public Value fpop() {
+        return assertFloat(xpop());
+    }
+
+    @Override
+    public Value apop() {
+        return assertObject(xpop());
+    }
+
+    @Override
+    public Value lpop() {
+        assertHigh(xpop());
+        return assertLong(xpop());
+    }
+
+    @Override
+    public Value dpop() {
+        assertHigh(xpop());
+        return assertDouble(xpop());
+    }
+
+    @Override
+    public Value[] popArguments(int slotSize, int argSize) {
+        int base = stackSize - slotSize;
+        Value[] r = new Value[argSize];
+        int argIndex = 0;
+        int stackindex = 0;
+        while (stackindex < slotSize) {
+            Value element = stack[base + stackindex];
+            assert element != null;
+            r[argIndex++] = element;
+            stackindex += stackSlots(element.getKind());
+        }
+        stackSize = base;
+        return r;
+    }
+
+    @Override
+    public Value peek(int argumentNumber) {
+        int idx = stackSize() - 1;
+        for (int i = 0; i < argumentNumber; i++) {
+            if (stackAt(idx) == null) {
+                idx--;
+                assert isTwoSlot(stackAt(idx).getKind());
+            }
+            idx--;
+        }
+        return stackAt(idx);
+    }
+
+    private static Value assertKind(Kind kind, Value x) {
+        assert x != null && x.getKind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
+        return x;
+    }
+
+    private static Value assertLong(Value x) {
+        assert x != null && (x.getKind() == Kind.Long);
+        return x;
+    }
+
+    private static Value assertInt(Value x) {
+        assert x != null && (x.getKind() == Kind.Int);
+        return x;
+    }
+
+    private static Value assertFloat(Value x) {
+        assert x != null && (x.getKind() == Kind.Float);
+        return x;
+    }
+
+    private static Value assertObject(Value x) {
+        assert x != null && (x.getKind() == Kind.Object);
+        return x;
+    }
+
+    private static Value assertDouble(Value x) {
+        assert x != null && (x.getKind() == Kind.Double);
+        return x;
+    }
+
+    private static void assertHigh(Value x) {
+        assert x == null;
+    }
+}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -41,6 +41,7 @@
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryMemory;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack;
@@ -48,7 +49,9 @@
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2MemoryOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op;
+import com.oracle.graal.lir.amd64.AMD64Compare.CompareMemoryOp;
 import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
@@ -57,11 +60,13 @@
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.ReturnOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp;
+import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MembarOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp;
+import com.oracle.graal.lir.amd64.AMD64Move.ZeroExtendLoadOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
@@ -87,9 +92,9 @@
         }
     }
 
-    public AMD64LIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
-        lir.setSpillMoveFactory(new AMD64SpillMoveFactory());
+    public AMD64LIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
+        lirGenRes.getLIR().setSpillMoveFactory(new AMD64SpillMoveFactory());
     }
 
     @Override
@@ -153,6 +158,10 @@
         append(createMove(dst, src));
     }
 
+    public void emitData(AllocatableValue dst, byte[] data) {
+        append(new LeaDataOp(dst, data));
+    }
+
     @Override
     public AMD64AddressValue emitAddress(Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
@@ -215,7 +224,7 @@
         return new AMD64AddressValue(target().wordKind, baseRegister, indexRegister, scaleEnum, displacementInt);
     }
 
-    protected AMD64AddressValue asAddressValue(Value address) {
+    public AMD64AddressValue asAddressValue(Value address) {
         if (address instanceof AMD64AddressValue) {
             return (AMD64AddressValue) address;
         } else {
@@ -256,13 +265,6 @@
     }
 
     @Override
-    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        AllocatableValue targetAddress = AMD64.rax.asValue();
-        emitMove(targetAddress, operand(callTarget.computedAddress()));
-        append(new AMD64Call.IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState));
-    }
-
-    @Override
     public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) {
         append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability));
     }
@@ -334,10 +336,46 @@
         }
     }
 
+    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue left, Value right, LIRFrameState state) {
+        assert kind == right.getKind();
+        switch (kind) {
+            case Int:
+                append(new CompareMemoryOp(ICMP, left, right, state));
+                break;
+            case Long:
+                append(new CompareMemoryOp(LCMP, left, right, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    protected void emitCompareRegMemoryOp(Kind kind, Value left, AMD64AddressValue right, LIRFrameState state) {
+        switch (kind) {
+            case Int:
+                append(new CompareMemoryOp(ICMP, left, right, state));
+                break;
+            case Long:
+                append(new CompareMemoryOp(LCMP, left, right, state));
+                break;
+            case Object:
+                append(new CompareMemoryOp(ACMP, left, right, state));
+                break;
+            case Float:
+                append(new CompareMemoryOp(FCMP, left, right, state));
+                break;
+            case Double:
+                append(new CompareMemoryOp(DCMP, left, right, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     /**
      * This method emits the compare instruction, and may reorder the operands. It returns true if
      * it did so.
-     * 
+     *
      * @param a the left operand of the comparison
      * @param b the right operand of the comparison
      * @return true if the left and right operands were switched, false otherwise
@@ -360,12 +398,6 @@
     }
 
     @Override
-    public void emitNullCheck(ValueNode v, DeoptimizingNode deopt) {
-        assert v.kind() == Kind.Object : v + " - " + v.stamp() + " @ " + deopt;
-        append(new AMD64Move.NullCheckOp(load(operand(v)), state(deopt)));
-    }
-
-    @Override
     public Variable emitNegate(Value inputVal) {
         AllocatableValue input = asAllocatable(inputVal);
         Variable result = newVariable(input.getKind());
@@ -505,31 +537,24 @@
         }
     }
 
-    @Override
-    protected boolean peephole(ValueNode valueNode) {
-        if ((valueNode instanceof IntegerDivNode) || (valueNode instanceof IntegerRemNode)) {
-            FixedBinaryNode divRem = (FixedBinaryNode) valueNode;
-            FixedNode node = divRem.next();
-            while (node instanceof FixedWithNextNode) {
-                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
-                if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
-                    FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
-                    if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && operand(otherDivRem) == null) {
-                        Value[] results = emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode);
-                        if (divRem instanceof IntegerDivNode) {
-                            setResult(divRem, results[0]);
-                            setResult(otherDivRem, results[1]);
-                        } else {
-                            setResult(divRem, results[1]);
-                            setResult(otherDivRem, results[0]);
-                        }
-                        return true;
-                    }
-                }
-                node = fixedWithNextNode.next();
-            }
-        }
-        return false;
+    protected Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+        Variable result = newVariable(a.getKind());
+        append(new BinaryMemory(op, kind, result, a, location, state));
+        return result;
+    }
+
+    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, AMD64AddressValue address, LIRFrameState state) {
+        Variable result = newVariable(kind);
+        append(new Unary2MemoryOp(op, result, address, state));
+        return result;
+    }
+
+    protected Value emitZeroExtendMemory(Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) {
+        // Issue a zero extending load of the proper bit size and set the result to
+        // the proper kind.
+        Variable result = newVariable(resultBits == 32 ? Kind.Int : Kind.Long);
+        append(new ZeroExtendLoadOp(memoryKind, result, address, state));
+        return result;
     }
 
     private void emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) {
@@ -959,7 +984,7 @@
     }
 
     @Override
-    protected void emitReturn(Value input) {
+    public void emitReturn(Value input) {
         append(new ReturnOp(input));
     }
 
@@ -975,19 +1000,4 @@
         append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(target().wordKind), newVariable(key.getPlatformKind())));
     }
 
-    @Override
-    public void visitBreakpointNode(BreakpointNode node) {
-        JavaType[] sig = new JavaType[node.arguments().size()];
-        for (int i = 0; i < sig.length; i++) {
-            sig[i] = node.arguments().get(i).stamp().javaType(getMetaAccess());
-        }
-
-        Value[] parameters = visitInvokeArguments(frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false), node.arguments());
-        append(new AMD64BreakpointOp(parameters));
-    }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        append(new InfopointOp(stateFor(i.getState()), i.reason));
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.amd64;
+
+import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
+import static com.oracle.graal.phases.GraalOptions.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public class AMD64MemoryPeephole implements MemoryArithmeticLIRLowerer {
+    protected final AMD64NodeLIRGenerator gen;
+    protected List<ValueNode> deferredNodes;
+
+    protected AMD64MemoryPeephole(AMD64NodeLIRGenerator gen) {
+        this.gen = gen;
+    }
+
+    public Value setResult(ValueNode x, Value operand) {
+        return gen.setResult(x, operand);
+    }
+
+    @Override
+    public boolean memoryPeephole(Access access, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred) {
+        this.deferredNodes = deferred;
+        boolean result = operation.generate(this, access);
+        if (result) {
+            Debug.log("merge %s %s with %1s %s %s", access, access.asNode().stamp(), operation, result, access.asNode().graph().method());
+        } else {
+            Debug.log("can't merge %s %s with %1s", access, access.asNode().stamp(), operation);
+        }
+        this.deferredNodes = null;
+        return result;
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return gen.getLIRGenerator().state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected AMD64AddressValue makeAddress(Access access) {
+        return (AMD64AddressValue) access.nullCheckLocation().generateAddress(gen, gen.operand(access.object()));
+    }
+
+    protected Value emitBinaryMemory(AMD64Arithmetic op, boolean commutative, ValueNode x, ValueNode y, Access access) {
+        ValueNode other = x;
+        if (other == access) {
+            if (commutative) {
+                other = y;
+            } else {
+                return null;
+            }
+        }
+        ensureEvaluated(other);
+        return gen.getLIRGenerator().emitBinaryMemory(op, access.nullCheckLocation().getValueKind(), gen.getLIRGeneratorTool().asAllocatable(gen.operand(other)), makeAddress(access), getState(access));
+    }
+
+    /**
+     * Constants with multiple users need to be evaluated in the right location so that later users
+     * can pick up the operand. Make sure that happens when it needs to.
+     */
+    protected void ensureEvaluated(ValueNode node) {
+        evaluateDeferred(node);
+        evaluateDeferred();
+    }
+
+    protected void evaluateDeferred(ValueNode node) {
+        // Ensure the other input value has a generated value.
+        if (ConstantNodeRecordsUsages) {
+            if (!gen.hasOperand(node)) {
+                assert node instanceof ConstantNode : node;
+                ((ConstantNode) node).generate(gen);
+            }
+        }
+    }
+
+    protected void evaluateDeferred() {
+        if (deferredNodes != null) {
+            for (ValueNode node : deferredNodes) {
+                evaluateDeferred(node);
+            }
+        }
+    }
+
+    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
+        AMD64AddressValue address = makeAddress(access);
+        LIRFrameState state = getState(access);
+        evaluateDeferred();
+        return gen.getLIRGenerator().emitConvert2MemoryOp(kind, op, address, state);
+    }
+
+    @Override
+    public Value emitAddMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IADD, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LADD, true, x, y, access);
+            case Float:
+                return emitBinaryMemory(FADD, true, x, y, access);
+            case Double:
+                return emitBinaryMemory(DADD, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitSubMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(ISUB, false, x, y, access);
+            case Long:
+                return emitBinaryMemory(LSUB, false, x, y, access);
+            case Float:
+                return emitBinaryMemory(FSUB, false, x, y, access);
+            case Double:
+                return emitBinaryMemory(DSUB, false, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitMulMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IMUL, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LMUL, true, x, y, access);
+            case Float:
+                return emitBinaryMemory(FMUL, true, x, y, access);
+            case Double:
+                return emitBinaryMemory(DMUL, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitDivMemory(ValueNode x, ValueNode y, Access access) {
+        return null;
+    }
+
+    @Override
+    public Value emitRemMemory(ValueNode x, ValueNode y, Access access) {
+        return null;
+    }
+
+    @Override
+    public Value emitAndMemory(ValueNode x, ValueNode y, Access access) {
+        Kind kind = access.nullCheckLocation().getValueKind();
+        switch (kind) {
+            case Int:
+                return emitBinaryMemory(IAND, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LAND, true, x, y, access);
+            case Short: {
+                ValueNode other = x == access ? y : x;
+                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
+                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
+                    // Convert to unsigned load
+                    ensureEvaluated(other);
+                    return emitZeroExtendMemory(16, 32, access);
+                }
+                return null;
+            }
+            case Byte: {
+                if (OptFoldMemory.getValue()) {
+                    return null;
+                }
+                ValueNode other = x == access ? y : x;
+                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
+                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
+                    // Convert to unsigned load
+                    ensureEvaluated(other);
+                    return emitConvert2MemoryOp(Kind.Int, MOV_B2UI, access);
+                }
+                return null;
+            }
+
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitOrMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IOR, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LOR, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitXorMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IXOR, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LXOR, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitReinterpretMemory(Stamp stamp, Access access) {
+        PlatformKind to = gen.getLIRGenerator().getPlatformKind(stamp);
+        Kind from = access.nullCheckLocation().getValueKind();
+        assert to != from : "should have been eliminated";
+
+        /*
+         * Conversions between integer to floating point types require moves between CPU and FPU
+         * registers.
+         */
+        switch ((Kind) to) {
+            case Int:
+                switch (from) {
+                    case Float:
+                        return emitConvert2MemoryOp(to, MOV_F2I, access);
+                }
+                break;
+            case Long:
+                switch (from) {
+                    case Double:
+                        return emitConvert2MemoryOp(to, MOV_D2L, access);
+                }
+                break;
+            case Float:
+                switch (from) {
+                    case Int:
+                        return emitConvert2MemoryOp(to, MOV_I2F, access);
+                }
+                break;
+            case Double:
+                switch (from) {
+                    case Long:
+                        return emitConvert2MemoryOp(to, MOV_L2D, access);
+                }
+                break;
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Value emitFloatConvertMemory(FloatConvert op, Access access) {
+        switch (op) {
+            case D2F:
+                return emitConvert2MemoryOp(Kind.Float, D2F, access);
+            case D2I:
+                return emitConvert2MemoryOp(Kind.Int, D2I, access);
+            case D2L:
+                return emitConvert2MemoryOp(Kind.Long, D2L, access);
+            case F2D:
+                return emitConvert2MemoryOp(Kind.Double, F2D, access);
+            case F2I:
+                return emitConvert2MemoryOp(Kind.Int, F2I, access);
+            case F2L:
+                return emitConvert2MemoryOp(Kind.Long, F2L, access);
+            case I2D:
+                return emitConvert2MemoryOp(Kind.Double, I2D, access);
+            case I2F:
+                return emitConvert2MemoryOp(Kind.Float, I2F, access);
+            case L2D:
+                return emitConvert2MemoryOp(Kind.Double, L2D, access);
+            case L2F:
+                return emitConvert2MemoryOp(Kind.Float, L2F, access);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    return emitConvert2MemoryOp(Kind.Long, B2L, access);
+                case 16:
+                    return emitConvert2MemoryOp(Kind.Long, S2L, access);
+                case 32:
+                    return emitConvert2MemoryOp(Kind.Long, I2L, access);
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    return emitConvert2MemoryOp(Kind.Int, B2I, access);
+                case 16:
+                    return emitConvert2MemoryOp(Kind.Int, S2I, access);
+                case 32:
+                    return null;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+    }
+
+    @Override
+    public Value emitNarrowMemory(int resultBits, Access access) {
+        // TODO
+        return null;
+    }
+
+    @Override
+    public Value emitZeroExtendMemory(int inputBits, int resultBits, Access access) {
+        assert resultBits == 32 || resultBits == 64;
+        Kind memoryKind = access.nullCheckLocation().getValueKind();
+        if (memoryKind.getBitCount() != inputBits && !memoryKind.isUnsigned()) {
+            // The memory being read from is signed and smaller than the result size so
+            // this is a sign extension to inputBits followed by a zero extension to resultBits
+            // which can't be expressed in a memory operation.
+            return null;
+        }
+        if (memoryKind == Kind.Short) {
+            memoryKind = Kind.Char;
+        }
+        evaluateDeferred();
+        return gen.getLIRGenerator().emitZeroExtendMemory(memoryKind, resultBits, makeAddress(access), getState(access));
+    }
+
+    public boolean emitIfMemory(IfNode x, Access access) {
+        return emitBranchMemory(x.condition(), access, gen.getLIRBlock(x.trueSuccessor()), gen.getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
+    }
+
+    private boolean emitBranchMemory(LogicNode node, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        if (node instanceof IsNullNode) {
+            // can't do anything interesting.
+            return false;
+        } else if (node instanceof CompareNode) {
+            CompareNode compare = (CompareNode) node;
+            return emitCompareBranchMemory(compare, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else if (node instanceof LogicConstantNode) {
+            return false;
+        } else if (node instanceof IntegerTestNode) {
+            return emitIntegerTestBranchMemory((IntegerTestNode) node, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else {
+            throw GraalInternalError.unimplemented(node.toString());
+        }
+    }
+
+    public boolean emitCompareBranchMemory(CompareNode compare, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        return emitCompareBranchMemory(compare.x(), compare.y(), access, compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public boolean emitIntegerTestBranchMemory(IntegerTestNode test, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        return emitIntegerTestBranchMemory(test.x(), test.y(), access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    private boolean emitIntegerTestBranchMemory(ValueNode left, ValueNode right, Access access, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
+        assert left == access || right == access;
+        ValueNode other = left == access ? right : left;
+        Kind kind = access.nullCheckLocation().getValueKind();
+        if (other.isConstant()) {
+            Constant constant = other.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return false;
+            }
+            ensureEvaluated(other);
+            gen.append(new AMD64TestMemoryOp(makeAddress(access), constant, getState(access)));
+        } else {
+            evaluateDeferred();
+            gen.append(new AMD64TestMemoryOp(makeAddress(access), gen.operand(other), getState(access)));
+        }
+
+        gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+        return true;
+    }
+
+    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        assert left == access || right == access;
+        ValueNode other = left == access ? right : left;
+        Kind kind = access.nullCheckLocation().getValueKind();
+        boolean mirrored = false;
+
+        if (other.isConstant()) {
+            Constant constant = other.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return false;
+            }
+            if (kind.isNumericFloat()) {
+                Debug.log("Skipping constant compares for float kinds");
+                return false;
+            }
+            if (kind == Kind.Object) {
+                if (!constant.isNull()) {
+                    Debug.log("Skipping constant compares for Object kinds");
+                    return false;
+                }
+            }
+            if (kind != kind.getStackKind()) {
+                Debug.log("Skipping constant compares for stack kinds");
+                return false;
+            }
+            ensureEvaluated(other);
+            gen.getLIRGenerator().emitCompareMemoryConOp(kind, makeAddress(access), constant, getState(access));
+            mirrored = right == access;
+        } else {
+            if (kind != kind.getStackKind()) {
+                // Register compares only work for stack kinds
+                Debug.log("Register compares only work for stack kinds");
+                return false;
+            } else if (kind == Kind.Object) {
+                // Can't compare against objects since they require encode/decode
+                Debug.log("Skipping compares for Object kinds");
+                return false;
+            }
+
+            evaluateDeferred();
+            gen.getLIRGenerator().emitCompareRegMemoryOp(kind, gen.operand(other), makeAddress(access), getState(access));
+            mirrored = left == access;
+        }
+
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        switch (kind.getStackKind()) {
+            case Long:
+            case Int:
+            case Object:
+                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+                return true;
+            case Float:
+            case Double:
+                gen.append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+                return true;
+            default:
+                throw GraalInternalError.shouldNotReachHere("" + kind.getStackKind());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.amd64;
+
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class AMD64NodeLIRGenerator extends NodeLIRGenerator {
+
+    public AMD64NodeLIRGenerator(StructuredGraph graph, LIRGenerationResult res, LIRGenerator gen) {
+        super(graph, res, gen);
+    }
+
+    protected MemoryArithmeticLIRLowerer memoryPeephole;
+
+    @Override
+    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
+        if (memoryPeephole == null) {
+            // Use the generic one
+            memoryPeephole = new AMD64MemoryPeephole(this);
+        }
+        return memoryPeephole;
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        AllocatableValue targetAddress = AMD64.rax.asValue();
+        gen.emitMove(targetAddress, operand(callTarget.computedAddress()));
+        append(new AMD64Call.IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState));
+    }
+
+    @Override
+    public void emitNullCheck(ValueNode v, DeoptimizingNode deopt) {
+        assert v.getKind() == Kind.Object : v + " - " + v.stamp() + " @ " + deopt;
+        append(new AMD64Move.NullCheckOp(gen.load(operand(v)), gen.state(deopt)));
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        if ((valueNode instanceof IntegerDivNode) || (valueNode instanceof IntegerRemNode)) {
+            FixedBinaryNode divRem = (FixedBinaryNode) valueNode;
+            FixedNode node = divRem.next();
+            while (node instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
+                if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
+                    FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
+                    if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && operand(otherDivRem) == null) {
+                        Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode);
+                        if (divRem instanceof IntegerDivNode) {
+                            setResult(divRem, results[0]);
+                            setResult(otherDivRem, results[1]);
+                        } else {
+                            setResult(divRem, results[1]);
+                            setResult(otherDivRem, results[0]);
+                        }
+                        return true;
+                    }
+                }
+                node = fixedWithNextNode.next();
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        JavaType[] sig = new JavaType[node.arguments().size()];
+        for (int i = 0; i < sig.length; i++) {
+            sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
+        }
+
+        Value[] parameters = visitInvokeArguments(res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, gen.target(), false), node.arguments());
+        append(new AMD64BreakpointOp(parameters));
+    }
+
+    @Override
+    public void visitInfopointNode(InfopointNode i) {
+        append(new InfopointOp(gen.stateFor(i.getState()), i.reason));
+    }
+
+    @Override
+    public AMD64LIRGenerator getLIRGenerator() {
+        return (AMD64LIRGenerator) gen;
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,6 +39,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.gpu.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.hsail.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -131,16 +132,21 @@
 
     // Special overrides for the testGeneratedxxx routines which set
     // required graal options that we need to run any junit test
+
+    private OverrideScope getOverrideScope() {
+        return OptionValue.override(GraalOptions.InlineEverything, true, accessibleRemoveNeverExecutedCode, false);
+    }
+
     @Override
     public void testGeneratedHsail() {
-        try (OverrideScope s = OptionValue.override(GraalOptions.InlineEverything, true, accessibleRemoveNeverExecutedCode, false)) {
+        try (OverrideScope s = getOverrideScope()) {
             super.testGeneratedHsail();
         }
     }
 
     @Override
     public void testGeneratedHsailUsingLambdaMethod() {
-        try (OverrideScope s = OptionValue.override(GraalOptions.InlineEverything, true, accessibleRemoveNeverExecutedCode, false)) {
+        try (OverrideScope s = getOverrideScope()) {
             super.testGeneratedHsailUsingLambdaMethod();
         }
     }
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java	Sun Mar 30 16:08:33 2014 +0200
@@ -118,6 +118,8 @@
         dispatchMode = DispatchMode.SEQ;
         hsailMode = HsailMode.COMPILED;
         useLambdaMethod = false;
+        // Control which okra instances can run the tests (is Simulator is static).
+        onSimulator = OkraContext.isSimulator();
         this.okraLibExists = okraLibExists;
     }
 
@@ -609,8 +611,12 @@
             fail("wrong arguments invoking " + testMethod + ", check number and type of args passed to dispatchMethodKernel");
         } catch (InvocationTargetException e) {
             Throwable cause = e.getCause();
-            String errstr = testMethod + " threw an exception on gid=" + rangeIndex + ", exception was " + cause;
-            fail(errstr);
+            if (cause instanceof RuntimeException) {
+                throw ((RuntimeException) cause);
+            } else {
+                String errstr = testMethod + " threw a checked exception on gid=" + rangeIndex + ", exception was " + cause;
+                fail(errstr);
+            }
         } catch (Exception e) {
             fail("Unknown exception " + e + " invoking " + testMethod);
         }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,11 +26,11 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.gpu.*;
 import com.oracle.graal.hotspot.hsail.*;
 import com.oracle.graal.hsail.*;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchBase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+
+/**
+ * Base Class for tests that deopt but then catch the exception in the run routine itself.
+ */
+public abstract class BoundsCatchBase extends GraalKernelTester {
+
+    abstract int getGlobalSize();
+
+    final int num = getGlobalSize();
+    @Result int[] outArray = new int[num];
+
+    void setupArrays() {
+        for (int i = 0; i < num; i++) {
+            outArray[i] = -i;
+        }
+    }
+
+    // Note: could not push the whole run routine here because
+    // problems with indirect call to getDeoptGid
+    int getOutval(int gid) {
+        int adjustment = 0;
+        int tmp = gid + 10;
+        while (tmp > gid) {
+            adjustment += tmp;
+            tmp--;
+        }
+        int outval = (outArray[gid] * -1) + adjustment;
+        return outval;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        // we should not get an exception escaping from the kernel
+        dispatchMethodKernel(num);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany16384Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 16384, deopt on many gids but then catch the exception in the run routine itself.
+ */
+public class BoundsCatchMany16384Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 16384;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany20000Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 20000, deopt on many gids but then catch the exception in the run routine itself.
+ */
+public class BoundsCatchMany20000Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 20000;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany5000Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 5000, deopt on many gids but then catch the exception in the run routine itself.
+ */
+public class BoundsCatchMany5000Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 5000;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany8192Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 8192, deopt on many gids but then catch the exception in the run routine itself.
+ */
+public class BoundsCatchMany8192Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 8192;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany987654HighTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 987654, deopt on many gids but then catch the exception in the run routine itself
+ * deopt ids are at the high end.
+ */
+public class BoundsCatchMany987654HighTest extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 987654;
+    }
+
+    boolean isMyDeoptGid(int gid) {
+        return (gid > getGlobalSize() - 4096 && gid % 512 == 1);
+    }
+
+    // copied run routine here because otherwise polymorphic calls to isDeoptGid
+    @Override
+    public void run(int gid) {
+        int outval = getOutval(gid);
+        try {
+            int index = (isMyDeoptGid(gid) ? num + 1 : gid);
+            outArray[index] = outval;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // set up so we can detect if we go thru here twice
+            outArray[gid] += outval;
+            // note: cannot record the exceptiongid here for many deopts in parallel
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany987654Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 987654, deopt on many gids but then catch the exception in the run routine itself.
+ */
+public class BoundsCatchMany987654Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 987654;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany99999Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 99999, deopt on many gids but then catch the exception in the run routine itself.
+ */
+public class BoundsCatchMany99999Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 99999;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+/**
+ * Base Class for tests that deopt on multiple gids gid but then catches the exception in the run
+ * routine itself.
+ */
+public abstract class BoundsCatchManyBase extends BoundsCatchBase {
+
+    boolean isDeoptGid(int gid) {
+        return (gid < 4096 && gid % 512 == 1);
+    }
+
+    @Override
+    public int getMisMatchLimit() {
+        return 1000;
+    }
+
+    public void run(int gid) {
+        int outval = getOutval(gid);
+        try {
+            int index = (isDeoptGid(gid) ? num + 1 : gid);
+            outArray[index] = outval;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // set up so we can detect if we go thru here twice
+            outArray[gid] += outval;
+            // note: cannot record the exceptiongid here for many deopts in parallel
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMost1000Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 1000, deopt on almost all gids but then catch the exception in the run routine
+ * itself.
+ */
+public class BoundsCatchMost1000Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 1000;
+    }
+
+    boolean isMyDeoptGid(int gid) {
+        return (gid % 100 != 1);
+    }
+
+    // copied run routine here because otherwise polymorphic calls to isDeoptGid
+    @Override
+    public void run(int gid) {
+        int outval = getOutval(gid);
+        try {
+            int index = (isMyDeoptGid(gid) ? num + 1 : gid);
+            outArray[index] = outval;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // set up so we can detect if we go thru here twice
+            outArray[gid] += outval;
+            // note: cannot record the exceptiongid here for many deopts in parallel
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMost20000Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 20000, deopt on almost all gids but then catch the exception in the run routine
+ * itself.
+ */
+public class BoundsCatchMost20000Test extends BoundsCatchManyBase {
+
+    @Override
+    int getGlobalSize() {
+        return 20000;
+    }
+
+    boolean isMyDeoptGid(int gid) {
+        return (gid % 100 != 1);
+    }
+
+    // copied run routine here because otherwise polymorphic calls to isDeoptGid
+    @Override
+    public void run(int gid) {
+        int outval = getOutval(gid);
+        try {
+            int index = (isMyDeoptGid(gid) ? num + 1 : gid);
+            outArray[index] = outval;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // set up so we can detect if we go thru here twice
+            outArray[gid] += outval;
+            // note: cannot record the exceptiongid here for many deopts in parallel
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle16384Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 16384, deopt on a single gid but then catch the exception in the run routine
+ * itself.
+ */
+public class BoundsCatchSingle16384Test extends BoundsCatchSingleBase {
+
+    @Override
+    int getGlobalSize() {
+        return 16384;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle20000Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 20000, deopt on a single gid but then catch the exception in the run routine
+ * itself.
+ */
+public class BoundsCatchSingle20000Test extends BoundsCatchSingleBase {
+
+    @Override
+    int getGlobalSize() {
+        return 20000;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle5000Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 5000, deopt on a single gid but then catch the exception in the run routine
+ * itself.
+ */
+public class BoundsCatchSingle5000Test extends BoundsCatchSingleBase {
+
+    @Override
+    int getGlobalSize() {
+        return 5000;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle8192Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * For globalsize 8192, deopt on a single gid but then catch the exception in the run routine
+ * itself.
+ */
+public class BoundsCatchSingle8192Test extends BoundsCatchSingleBase {
+
+    @Override
+    int getGlobalSize() {
+        return 8192;
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingleBase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+/**
+ * Base Class for tests that deopt on a single gid but then catch the exception in the run routine
+ * itself.
+ */
+public abstract class BoundsCatchSingleBase extends BoundsCatchBase {
+
+    int getDeoptGid() {
+        return 512;
+    }
+
+    boolean isDeoptGid(int gid) {
+        return (gid == getDeoptGid());
+    }
+
+    @Result public int exceptionGid;
+
+    public void run(int gid) {
+        int outval = getOutval(gid);
+        try {
+            int index = (isDeoptGid(gid) ? num + 1 : gid);
+            outArray[index] = outval;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // set up so we can detect if we go thru here twice
+            outArray[gid] -= outval;
+            exceptionGid = gid;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckDoubleNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception
+ * back to the java code.
+ */
+public class BoundsCheckDoubleNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    double[] outArray = new double[num];
+
+    void setupArrays(double[] in1, double[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -i;
+        }
+    }
+
+    static double dummyDouble = 10;
+
+    public static void run(double[] out, double[] ina, double[] inb, int gid) {
+        // This will fail when gid+1==num
+        double adjustment = 0;
+        double tmp = dummyDouble;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        out[gid + 1] = ina[gid] + inb[gid] + adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        double[] inArray1 = new double[num];
+        double[] inArray2 = new double[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckFailsInMiddleTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception
+ * back to the java code, in the middle of the array.
+ */
+public class BoundsCheckFailsInMiddleTest extends SingleExceptionTestBase {
+    static final int num = 128; // * 256;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    int[] outArray = new int[num];
+    static final int abortingGid = (new java.util.Random()).nextInt(num / 4);
+
+    void setupArrays(int[] in1, int[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -99;
+        }
+    }
+
+    public static void run(int[] out, int[] ina, int[] inb, int gid) {
+        // Throw in the middle of doing the work
+        out[gid == abortingGid ? (gid + num) : gid] = ina[gid] + inb[gid];
+    }
+
+    @Override
+    public void runTest() {
+        int[] inArray1 = new int[num];
+        int[] inArray2 = new int[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckFloatNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception
+ * back to the java code.
+ */
+public class BoundsCheckFloatNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    float[] outArray = new float[num];
+
+    void setupArrays(float[] in1, float[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -i;
+        }
+    }
+
+    static float dummyFloat = 10;
+
+    public static void run(float[] out, float[] ina, float[] inb, int gid) {
+        // This will fail when gid+1==num
+        float adjustment = 0;
+        float tmp = dummyFloat;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        out[gid + 1] = ina[gid] + inb[gid] + adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        float[] inArray1 = new float[num];
+        float[] inArray2 = new float[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckInlineTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * 
+ * @author ecaspole
+ */
+public class BoundsCheckInlineTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    int[] outArray = new int[num];
+
+    void setupArrays(int[] in1, int[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -i;
+        }
+    }
+
+    static volatile int dummy;
+
+    static void writesum(int[] out, int gid, int val) {
+        out[gid + 1] = val;
+    }
+
+    public static void run(int[] out, int[] ina, int[] inb, int gid) {
+        // This will fail when gid+1==num
+        writesum(out, gid, ina[gid] + inb[gid]);
+    }
+
+    @Override
+    public void runTest() {
+        int[] inArray1 = new int[num];
+        int[] inArray2 = new int[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckLongNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception
+ * back to the java code.
+ */
+public class BoundsCheckLongNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    long[] outArray = new long[num];
+
+    void setupArrays(long[] in1, long[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -i;
+        }
+    }
+
+    static long dummyLong = 10;
+
+    public static void run(long[] out, long[] ina, long[] inb, int gid) {
+        // This will fail when gid+1==num
+        long adjustment = 0x1234567890abcdefL;
+        long tmp = dummyLong;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        out[gid + 1] = ina[gid] + inb[gid] + adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        long[] inArray1 = new long[num];
+        long[] inArray2 = new long[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckNonZeroBciInstanceTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception
+ * back to the java code.
+ */
+public class BoundsCheckNonZeroBciInstanceTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    int[] outArray = new int[num];
+    int[] inArray1 = new int[num];
+    int[] inArray2 = new int[num];
+
+    void setupArrays(int[] in1, int[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -i;
+        }
+    }
+
+    int dummyInt = 10;
+
+    public void run(int gid) {
+        // This will fail when gid+1==num
+        int adjustment = 0;
+        int tmp = dummyInt;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        outArray[gid + 1] = inArray1[gid] + inArray2[gid] + adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception
+ * back to the java code.
+ */
+public class BoundsCheckNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    int[] outArray = new int[num];
+
+    void setupArrays(int[] in1, int[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -i;
+        }
+    }
+
+    static int dummyInt = 10;
+
+    public static void run(int[] out, int[] ina, int[] inb, int gid) {
+        // This will fail when gid+1==num
+        int adjustment = 0;
+        int tmp = dummyInt;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        out[gid + 1] = ina[gid] + inb[gid] + adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        int[] inArray1 = new int[num];
+        int[] inArray2 = new int[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception
+ * back to the java code.
+ */
+public class BoundsCheckTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    // note: outArray not marked as @Result because we can't predict
+    // which workitems will get done in parallel execution
+    int[] outArray = new int[num];
+
+    void setupArrays(int[] in1, int[] in2) {
+        for (int i = 0; i < num; i++) {
+            in1[i] = i;
+            in2[i] = i + 1;
+            outArray[i] = -i;
+        }
+    }
+
+    public static void run(int[] out, int[] ina, int[] inb, int gid) {
+        // This will fail when gid+1==num
+        out[gid + 1] = ina[gid] + inb[gid];
+    }
+
+    @Override
+    public void runTest() {
+        int[] inArray1 = new int[num];
+        int[] inArray2 = new int[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ClassCastNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes a ClassCastException to test throwing the exception back to the
+ * java code.
+ */
+public class ClassCastNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+
+    static class BasePoint {
+        int x;
+        int y;
+
+        public BasePoint(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+    }
+
+    static class MyPoint extends BasePoint {
+        public MyPoint(int x, int y) {
+            super(x, y);
+        }
+    }
+
+    BasePoint[] inputs = new BasePoint[num];
+    MyPoint[] outputs = new MyPoint[num];
+
+    void setupArrays() {
+        for (int i = 0; i < num; i++) {
+            inputs[i] = new MyPoint(i, i + 1);
+        }
+        inputs[2] = new BasePoint(1, 1);
+    }
+
+    public void run(int gid) {
+        // gid 2 should always throw ClassCastException
+        int adjustment = 0;
+        int tmp = gid;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        MyPoint mp = (MyPoint) inputs[gid];
+        mp.x = mp.y + adjustment;
+        outputs[gid] = mp;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(num);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ClassCastTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test deliberately causes a ClassCastException to test throwing the exception back to the
+ * java code.
+ */
+public class ClassCastTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+
+    static class BasePoint {
+        int x;
+        int y;
+
+        public BasePoint(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+    }
+
+    static class MyPoint extends BasePoint {
+        public MyPoint(int x, int y) {
+            super(x, y);
+        }
+    }
+
+    BasePoint[] inputs = new BasePoint[num];
+    MyPoint[] outputs = new MyPoint[num];
+
+    void setupArrays() {
+        for (int i = 0; i < num; i++) {
+            inputs[i] = new MyPoint(i, i + 1);
+        }
+        inputs[2] = new BasePoint(1, 1);
+    }
+
+    public void run(int gid) {
+        // gid 2 should always throw ClassCastException
+        MyPoint mp = (MyPoint) inputs[gid];
+        mp.x = mp.y + 2;
+        outputs[gid] = mp;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(num);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCatchNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test tests an int stream where we deliberately cause a NPE to test throwing the exception
+ * back to the java code. In addition, it is set up so the bci of the exception point is not zero.
+ */
+public class IntStreamNullCatchNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+
+    static class BasePoint {
+        int x;
+        int y;
+
+        public BasePoint(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+    }
+
+    static class MyPoint extends BasePoint {
+        public MyPoint(int x, int y) {
+            super(x, y);
+        }
+    }
+
+    BasePoint[] inputs = new BasePoint[num];
+    MyPoint[] outputs = new MyPoint[num];
+
+    void setupArrays() {
+        for (int i = 0; i < num; i++) {
+            inputs[i] = new MyPoint(i, i + 1);
+        }
+        inputs[10] = null;
+    }
+
+    @Result public int nullSeenGid;
+    @Result public int nullSeenAdjustment;
+
+    public void run(int gid) {
+        // gid 10 should always throw NPE
+        MyPoint mp = (MyPoint) inputs[gid];
+        int adjustment = 0;
+        int tmp = gid;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        try {
+            mp.x = mp.y + adjustment;
+        } catch (NullPointerException e) {
+            nullSeenGid = gid;
+            nullSeenAdjustment = adjustment;
+        }
+        outputs[gid] = mp;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(num);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCheckNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test tests an int stream where we deliberately cause a NPE to test throwing the exception
+ * back to the java code. In addition, it is set up so the bci of the exception point is not zero.
+ */
+public class IntStreamNullCheckNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+
+    static class BasePoint {
+        int x;
+        int y;
+
+        public BasePoint(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+    }
+
+    static class MyPoint extends BasePoint {
+        public MyPoint(int x, int y) {
+            super(x, y);
+        }
+    }
+
+    BasePoint[] inputs = new BasePoint[num];
+    MyPoint[] outputs = new MyPoint[num];
+
+    void setupArrays() {
+        for (int i = 0; i < num; i++) {
+            inputs[i] = new MyPoint(i, i + 1);
+        }
+        inputs[10] = null;
+    }
+
+    public void run(int gid) {
+        // gid 10 should always throw NPE
+        MyPoint mp = (MyPoint) inputs[gid];
+        int adjustment = 0;
+        int tmp = gid;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        mp.x = mp.y + adjustment;
+        outputs[gid] = mp;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(num);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCheckTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * This test tests an int stream where we deliberately cause a NPE to test throwing the exception
+ * back to the java code.
+ */
+public class IntStreamNullCheckTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+
+    static class BasePoint {
+        int x;
+        int y;
+
+        public BasePoint(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public int getY() {
+            return y;
+        }
+    }
+
+    static class MyPoint extends BasePoint {
+        public MyPoint(int x, int y) {
+            super(x, y);
+        }
+    }
+
+    BasePoint[] inputs = new BasePoint[num];
+    MyPoint[] outputs = new MyPoint[num];
+
+    void setupArrays() {
+        for (int i = 0; i < num; i++) {
+            inputs[i] = new MyPoint(i, i + 1);
+        }
+        inputs[10] = null;
+    }
+
+    public void run(int gid) {
+        // gid 10 should always throw NPE
+        MyPoint mp = (MyPoint) inputs[gid];
+        mp.x = mp.y + 2;
+        outputs[gid] = mp;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(num);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullNonArrayParamCheckTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * Tests one of the kernel parameters being null.
+ */
+public class IntStreamNullNonArrayParamCheckTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    @Result protected int[] outArray = new int[num];
+
+    static class MyObj {
+        public int val;
+    }
+
+    public static void run(int[] out, int[] ina, MyObj adjustment, int gid) {
+        out[gid] = ina[gid] + adjustment.val;
+    }
+
+    @Override
+    public void runTest() {
+        int[] inArray1 = new int[num];
+        int[] inArray2 = new int[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, inArray1, null);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    void setupArrays(int[] in1, int[] in2) {
+        for (int i = 0; i < num; i++) {
+            // Fill input arrays with a mix of positive and negative values.
+            in1[i] = i < num / 2 ? i + 1 : -(i + 1);
+            in2[i] = (i & 1) == 0 ? in1[i] + 10 : -(in1[i] + 10);
+            outArray[i] = -i;
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullParamCheckTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+
+/**
+ * Tests one of the kernel parameters being null.
+ */
+public class IntStreamNullParamCheckTest extends SingleExceptionTestBase {
+
+    static final int num = 20;
+    @Result protected int[] outArray = new int[num];
+
+    public static void run(int[] out, int[] ina, int[] inb, int gid) {
+        out[gid] = ina[gid] + inb[gid];
+    }
+
+    @Override
+    public void runTest() {
+        int[] inArray1 = new int[num];
+        int[] inArray2 = new int[num];
+        setupArrays(inArray1, inArray2);
+
+        try {
+            dispatchMethodKernel(num, outArray, null, inArray2);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    void setupArrays(int[] in1, int[] in2) {
+        for (int i = 0; i < num; i++) {
+            // Fill input arrays with a mix of positive and negative values.
+            in1[i] = i < num / 2 ? i + 1 : -(i + 1);
+            in2[i] = (i & 1) == 0 ? in1[i] + 10 : -(in1[i] + 10);
+            outArray[i] = -i;
+        }
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/SingleExceptionTestBase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+
+/**
+ * 
+ * @author ecaspole
+ */
+public abstract class SingleExceptionTestBase extends GraalKernelTester {
+
+    @Result Class<?> exceptionClass;
+    @Result String exceptionString;
+    @Result StackTraceElement firstStackTraceElement;
+
+    void recordException(Exception e) {
+        // for now we just test that the class the of the exception
+        // matches for the java and gpu side
+        exceptionClass = e.getClass();
+        // exception = e;
+        StackTraceElement[] elems = e.getStackTrace();
+        firstStackTraceElement = elems[0];
+        // for tests where the exception was in the method parameters
+        // ignore the firstStackTraceElement matching
+        if (firstStackTraceElement.getClassName().contains("KernelTester")) {
+            firstStackTraceElement = null;
+        }
+        for (StackTraceElement elem : elems) {
+            if (elem.toString().contains("KernelTester")) {
+                break;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMandelBoundsCheckTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.Test;
+import static org.junit.Assume.*;
+
+/**
+ * Unit test that simulates the Mandelbrot application. The run method here is a static method
+ * version of the original mandel kernel and the invoke parameters are for the starting point of the
+ * mandel demo. Note: this will likely not pass the junit test on real hardware, but should pass on
+ * the simulator.
+ */
+public class StaticMandelBoundsCheckTest extends SingleExceptionTestBase {
+
+    static final int initWidth = 768;
+    static final int initHeight = initWidth;
+    static final int maxIterations = 64;
+    static final int range = initWidth * initHeight;
+    private int[] rgb = new int[range];
+
+    public static void run(int[] rgb, int[] pallette, float xoffset, float yoffset, float scale, int gid) {
+        final int width = initWidth;
+        final int height = initHeight;
+        float lx = (((gid % width * scale) - ((scale / 2) * width)) / width) + xoffset;
+        float ly = (((gid / width * scale) - ((scale / 2) * height)) / height) + yoffset;
+        int count = 0;
+        float zx = lx;
+        float zy = ly;
+        float newzx = 0f;
+
+        // Iterate until the algorithm converges or until maxIterations are reached.
+        while (count < maxIterations && zx * zx + zy * zy < 8) {
+            newzx = zx * zx - zy * zy + lx;
+            zy = 2 * zx * zy + ly;
+            zx = newzx;
+            count++;
+        }
+        rgb[gid + 1] = pallette[count];   // will cause exception on last of range
+    }
+
+    void setupPalette(int[] in) {
+        for (int i = 0; i < in.length; i++) {
+            in[i] = i;
+        }
+    }
+
+    @Override
+    public void runTest() {
+        int[] palette = new int[256];
+        setupPalette(palette);
+        /**
+         * Call it for a range, specifying testmethod args (but not the fields it uses or the gid
+         * argument).
+         */
+        try {
+            dispatchMethodKernel(range, rgb, palette, -1f, 0f, 3f);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        assumeTrue(runningOnSimulator());
+        testGeneratedHsail();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamClassCastNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests an object array stream with one element being of the wrong class.
+ */
+public class Vec3ObjStreamClassCastNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int NUM = 20;
+
+    public Vec3[] inArray = new Vec3[NUM];
+
+    static class MyVec3 extends Vec3 {
+        public MyVec3(float x, float y, float z) {
+            super(x, y, z);
+        }
+    }
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new MyVec3(i, i + 1, -1);
+        }
+        // insert one wrong type
+        inArray[10] = new Vec3(10, 11, -1);
+    }
+
+    int dummyInt = 10;
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 vec3) {
+        int adjustment = 0;
+        int tmp = dummyInt;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        MyVec3 myvec3 = (MyVec3) vec3;
+        myvec3.z = myvec3.x + myvec3.y + adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(inArray);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamClassCastTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests an object array stream with one element being of the wrong class.
+ */
+public class Vec3ObjStreamClassCastTest extends SingleExceptionTestBase {
+
+    static final int NUM = 20;
+
+    public Vec3[] inArray = new Vec3[NUM];
+
+    static class MyVec3 extends Vec3 {
+        public MyVec3(float x, float y, float z) {
+            super(x, y, z);
+        }
+    }
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new MyVec3(i, i + 1, -1);
+        }
+        // insert one wrong type
+        inArray[10] = new Vec3(10, 11, -1);
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 vec3) {
+        MyVec3 myvec3 = (MyVec3) vec3;
+        myvec3.z = myvec3.x + myvec3.y;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(inArray);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullCheckNonZeroBciTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests an object array stream with one element being null.
+ */
+public class Vec3ObjStreamNullCheckNonZeroBciTest extends SingleExceptionTestBase {
+
+    static final int NUM = 20;
+
+    public Vec3[] inArray = new Vec3[NUM];
+
+    static class MyVec3 extends Vec3 {
+        public MyVec3(float x, float y, float z) {
+            super(x, y, z);
+        }
+    }
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new MyVec3(i, i + 1, -1);
+        }
+        // insert one null
+        inArray[10] = null;
+    }
+
+    int dummyInt = 10;
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 vec3) {
+        int adjustment = 0;
+        int tmp = dummyInt;
+        while (tmp-- >= 0) {
+            adjustment += tmp;
+        }
+        vec3.z = vec3.x + vec3.y + adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(inArray);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullCheckTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests an object array stream with one element being null.
+ */
+public class Vec3ObjStreamNullCheckTest extends SingleExceptionTestBase {
+
+    static final int NUM = 20;
+
+    public Vec3[] inArray = new Vec3[NUM];
+
+    static class MyVec3 extends Vec3 {
+        public MyVec3(float x, float y, float z) {
+            super(x, y, z);
+        }
+    }
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new MyVec3(i, i + 1, -1);
+        }
+        // insert one null
+        inArray[10] = null;
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 vec3) {
+        vec3.z = vec3.x + vec3.y;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(inArray);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullParamCheckTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests an object array stream with the object stream itself being null.
+ */
+public class Vec3ObjStreamNullParamCheckTest extends SingleExceptionTestBase {
+
+    static final int NUM = 20;
+
+    public Vec3[] inArray = new Vec3[NUM];
+
+    static class MyVec3 extends Vec3 {
+        public MyVec3(float x, float y, float z) {
+            super(x, y, z);
+        }
+    }
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new MyVec3(i, i + 1, -1);
+        }
+        // insert one null
+        inArray[10] = null;
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 vec3) {
+        MyVec3 myvec3 = (MyVec3) vec3;
+        myvec3.z = myvec3.x + myvec3.y;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        try {
+            dispatchMethodKernel(null);
+        } catch (Exception e) {
+            recordException(e);
+        }
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
@@ -54,7 +53,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -76,9 +74,9 @@
         }
     }
 
-    public HSAILLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
-        lir.setSpillMoveFactory(new HSAILSpillMoveFactory());
+    public HSAILLIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
+        lirGenRes.getLIR().setSpillMoveFactory(new HSAILSpillMoveFactory());
     }
 
     @Override
@@ -115,7 +113,11 @@
         }
     }
 
-    protected HSAILAddressValue asAddressValue(Value address) {
+    public void emitData(AllocatableValue dst, byte[] data) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public HSAILAddressValue asAddressValue(Value address) {
         if (address instanceof HSAILAddressValue) {
             return (HSAILAddressValue) address;
         } else {
@@ -173,7 +175,7 @@
         append(new JumpOp(label));
     }
 
-    protected static HSAILCompare mapKindToCompareOp(Kind kind) {
+    public static HSAILCompare mapKindToCompareOp(Kind kind) {
         switch (kind) {
             case Int:
                 return ICMP;
@@ -249,7 +251,7 @@
 
     /**
      * Generates the LIR instruction for a negation operation.
-     * 
+     *
      * @param input the value that is being negated
      * @return Variable that represents the result of the negation
      */
@@ -280,7 +282,7 @@
 
     /**
      * Generates the LIR instruction for a bitwise NOT operation.
-     * 
+     *
      * @param input the source operand
      * @return Variable that represents the result of the operation
      */
@@ -412,12 +414,6 @@
     }
 
     @Override
-    protected boolean peephole(ValueNode valueNode) {
-        // No peephole optimizations for now.
-        return false;
-    }
-
-    @Override
     public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
@@ -522,7 +518,7 @@
 
     /**
      * Generates the LIR instruction for a shift left operation.
-     * 
+     *
      * @param a The value that is being shifted
      * @param b The shift amount
      * @return Variable that represents the result of the operation
@@ -547,7 +543,7 @@
 
     /**
      * Generates the LIR instruction for a shift right operation.
-     * 
+     *
      * @param a The value that is being shifted
      * @param b The shift amount
      * @return Variable that represents the result of the operation
@@ -572,7 +568,7 @@
 
     /**
      * Generates the LIR instruction for an unsigned shift right operation.
-     * 
+     *
      * @param a The value that is being shifted
      * @param b The shift amount
      * @return Variable that represents the result of the operation
@@ -697,16 +693,6 @@
     }
 
     @Override
-    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    @Override
-    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    @Override
     public void emitBitCount(Variable result, Value value) {
         if (value.getKind().getStackKind() == Kind.Int) {
             append(new HSAILBitManipulationOp(IPOPCNT, result, value));
@@ -727,7 +713,7 @@
 
     /**
      * Emits the LIR code for the {@link HSAILArithmetic#ABS} operation.
-     * 
+     *
      * @param input the source operand
      * @return Value representing the result of the operation
      */
@@ -740,7 +726,7 @@
 
     /**
      * Emits the LIR code for the {@link HSAILArithmetic#CEIL} operation.
-     * 
+     *
      * @param input the source operand
      * @return Value representing the result of the operation
      */
@@ -752,7 +738,7 @@
 
     /**
      * Emits the LIR code for the {@link HSAILArithmetic#FLOOR} operation.
-     * 
+     *
      * @param input the source operand
      * @return Value representing the result of the operation
      */
@@ -764,7 +750,7 @@
 
     /**
      * Emits the LIR code for the {@link HSAILArithmetic#RINT} operation.
-     * 
+     *
      * @param input the source operand
      * @return Value representing the result of the operation
      */
@@ -776,7 +762,7 @@
 
     /**
      * Emits the LIR code for the {@link HSAILArithmetic#SQRT} operation.
-     * 
+     *
      * @param input the source operand
      * @return value representing the result of the operation
      */
@@ -819,21 +805,21 @@
     }
 
     @Override
-    protected void emitReturn(Value input) {
+    public void emitReturn(Value input) {
         append(new ReturnOp(input));
     }
 
     /**
      * This routine handles the LIR code generation for switch nodes by calling
      * emitSequentialSwitch.
-     * 
+     *
      * This routine overrides LIRGenerator.emitSwitch( ) which calls emitSequentialSwitch or
      * emitTableSwitch based on a heuristic.
-     * 
+     *
      * The recommended approach in HSAIL for generating performant code for switch statements is to
      * emit a series of cascading compare and branches. Thus this routines always calls
      * emitSequentialSwitch, which implements this approach.
-     * 
+     *
      * Note: Only IntegerSwitchNodes are currently supported. The IntegerSwitchNode is the node that
      * Graal generates for any switch construct appearing in Java bytecode.
      */
@@ -846,17 +832,17 @@
      * Generates the LIR instruction for a switch construct that is meant to be assembled into a
      * series of cascading compare and branch instructions. This is currently the recommended way of
      * generating performant HSAIL code for switch constructs.
-     * 
+     *
      * In Java bytecode the keys for switch statements are always ints.
-     * 
+     *
      * The x86 backend also adds support for handling keys of type long or Object but these two
      * special cases are for handling the TypeSwitchNode, which is a node that the JVM produces for
      * handling operations related to method dispatch. We haven't yet added support for the
      * TypeSwitchNode, so for the time being we have added a check to ensure that the keys are of
      * type int. This also allows us to flag any test cases/execution paths that may trigger the
      * creation of a TypeSwitchNode which we don't support yet.
-     * 
-     * 
+     *
+     *
      * @param strategy the strategy used for this switch.
      * @param keyTargets array of branch targets for each of the cases.
      * @param defaultTarget the branch target for the default case.
@@ -864,12 +850,12 @@
      */
     @Override
     protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
-        if (key.getKind() == Kind.Int) {
+        if ((key.getKind() == Kind.Int) || (key.getKind() == Kind.Long)) {
             // Append the LIR instruction for generating compare and branch instructions.
             append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key));
         } else {
             // Throw an exception if the keys aren't ints.
-            throw GraalInternalError.unimplemented("Switch statements are only supported for keys of type int");
+            throw GraalInternalError.unimplemented("Switch statements are only supported for keys of type int or long, not " + key.getKind());
         }
     }
 
@@ -879,30 +865,8 @@
     }
 
     @Override
-    public void visitBreakpointNode(BreakpointNode node) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    @Override
-    public void visitSafepointNode(SafepointNode i) {
-        Debug.log("visitSafePointNode unimplemented");
-    }
-
-    @Override
     public void emitUnwind(Value operand) {
         throw GraalInternalError.unimplemented();
     }
 
-    @Override
-    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
-        assert v.stamp() instanceof ObjectStamp;
-        Variable obj = newVariable(Kind.Object);
-        emitMove(obj, operand(v));
-        append(new HSAILMove.NullCheckOp(obj, state(deopting)));
-    }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        throw GraalInternalError.unimplemented();
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.hsail;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.hsail.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * This class implements the HSAIL specific portion of the LIR generator.
+ */
+public abstract class HSAILNodeLIRGenerator extends NodeLIRGenerator {
+
+    public HSAILNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        super(graph, lirGenRes, lirGen);
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        // No peephole optimizations for now.
+        return false;
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        Debug.log("visitSafePointNode unimplemented");
+    }
+
+    @Override
+    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
+        assert v.stamp() instanceof ObjectStamp;
+        Variable obj = newVariable(Kind.Object);
+        gen.emitMove(obj, operand(v));
+        append(new HSAILMove.NullCheckOp(obj, gen.state(deopting)));
+    }
+
+    @Override
+    public void visitInfopointNode(InfopointNode i) {
+        throw GraalInternalError.unimplemented();
+    }
+}
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -66,6 +66,7 @@
         return a.i + i;
     }
 
+    @Ignore("com.oracle.graal.graph.GraalInternalError: should not reach here: unhandled register type v3|z")
     @Test
     public void test2() {
         A a = new A();
@@ -79,6 +80,7 @@
         return a.z;
     }
 
+    @Ignore("[CUDA] Check for malformed PTX kernel or incorrect PTX compilation options")
     @Test
     public void test3() {
         for (byte b : new byte[]{Byte.MIN_VALUE, -10, 0, 1, 2, 10, Byte.MAX_VALUE}) {
@@ -92,6 +94,7 @@
         return a.b + b;
     }
 
+    @Ignore("com.oracle.graal.graph.GraalInternalError: should not reach here: unhandled register type v5|s")
     @Test
     public void test4() {
         for (short s : new short[]{Short.MIN_VALUE, -10, 0, 1, 2, 10, Short.MAX_VALUE}) {
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXMethodInvalidation1Test.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXMethodInvalidation1Test.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,8 +24,8 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.gpu.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.ptx.*;
 
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.gpu.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.ptx.*;
 import com.oracle.graal.nodes.*;
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,13 +29,10 @@
 import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.ptx.PTXCompare.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
@@ -64,7 +61,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.util.*;
 
@@ -89,11 +85,11 @@
         }
     }
 
-    public PTXLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
-        lir.setSpillMoveFactory(new PTXSpillMoveFactory());
+    public PTXLIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
+        lirGenRes.getLIR().setSpillMoveFactory(new PTXSpillMoveFactory());
         int callVariables = cc.getArgumentCount() + (cc.getReturn().equals(Value.ILLEGAL) ? 0 : 1);
-        lir.setFirstVariableNumber(callVariables);
+        lirGenRes.getLIR().setFirstVariableNumber(callVariables);
         nextPredRegNum = 0;
     }
 
@@ -134,43 +130,6 @@
         return value;
     }
 
-    @Override
-    public void emitPrologue(StructuredGraph graph) {
-        // Need to emit .param directives based on incoming arguments and return value
-        CallingConvention incomingArguments = cc;
-        Object returnObject = incomingArguments.getReturn();
-        AllocatableValue[] params = incomingArguments.getArguments();
-        int argCount = incomingArguments.getArgumentCount();
-
-        if (returnObject.equals(Value.ILLEGAL)) {
-            params = incomingArguments.getArguments();
-            append(new PTXParameterOp(params, false));
-        } else {
-            argCount = incomingArguments.getArgumentCount();
-            params = new Variable[argCount + 1];
-            for (int i = 0; i < argCount; i++) {
-                params[i] = incomingArguments.getArgument(i);
-            }
-            params[argCount] = (Variable) returnObject;
-            append(new PTXParameterOp(params, true));
-        }
-
-        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
-            int localIndex = param.index();
-            Value paramValue = params[param.index()];
-            int parameterIndex = localIndex;
-            if (!Modifier.isStatic(graph.method().getModifiers())) {
-                parameterIndex--;
-            }
-            Warp warpAnnotation = parameterIndex >= 0 ? MetaUtil.getParameterAnnotation(Warp.class, parameterIndex, graph.method()) : null;
-            if (warpAnnotation != null) {
-                setResult(param, emitWarpParam(paramValue.getKind().getStackKind(), warpAnnotation));
-            } else {
-                setResult(param, emitLoadParam(paramValue.getKind().getStackKind(), paramValue, null));
-            }
-        }
-    }
-
     public Variable emitWarpParam(Kind kind, Warp annotation) {
         Variable result = newVariable(kind);
         Variable tid = newVariable(Kind.Char);
@@ -208,6 +167,11 @@
     }
 
     @Override
+    public void emitData(AllocatableValue dst, byte[] data) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
     public PTXAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
@@ -533,12 +497,6 @@
     }
 
     @Override
-    protected boolean peephole(ValueNode valueNode) {
-        // No peephole optimizations for now
-        return false;
-    }
-
-    @Override
     public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
@@ -805,16 +763,6 @@
     }
 
     @Override
-    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitDirectCall()");
-    }
-
-    @Override
-    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitIndirectCall()");
-    }
-
-    @Override
     protected void emitForeignCall(ForeignCallLinkage callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitForeignCall()");
     }
@@ -880,11 +828,11 @@
     }
 
     @Override
-    protected void emitReturn(Value input) {
+    public void emitReturn(Value input) {
         append(new ReturnOp(input));
     }
 
-    private void emitReturnNoVal() {
+    void emitReturnNoVal() {
         append(new ReturnNoValOp());
     }
 
@@ -903,38 +851,10 @@
     }
 
     @Override
-    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
-        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitCompareAndSwap()");
-    }
-
-    @Override
-    public void visitBreakpointNode(BreakpointNode node) {
-        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitBreakpointNode()");
-    }
-
-    @Override
-    public void visitSafepointNode(SafepointNode i) {
-        // LIRFrameState info = state(i);
-        // append(new PTXSafepointOp(info, runtime().config, this));
-        Debug.log("visitSafePointNode unimplemented");
-    }
-
-    @Override
     public void emitUnwind(Value operand) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUnwind()");
     }
 
-    @Override
-    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
-        assert v.kind() == Kind.Object;
-        append(new PTXMove.NullCheckOp(load(operand(v)), state(deopting)));
-    }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitInfopointNode()");
-    }
-
     public Variable emitLoadParam(Kind kind, Value address, DeoptimizingNode deopting) {
 
         PTXAddressValue loadAddress = asAddress(address);
@@ -979,16 +899,4 @@
         return (new Variable(kind, 0));
     }
 
-    @Override
-    public void visitReturn(ReturnNode x) {
-        AllocatableValue operand = Value.ILLEGAL;
-        if (x.result() != null) {
-            operand = resultOperandFor(x.result().kind());
-            // Load the global memory address from return parameter
-            Variable loadVar = emitLoadReturnAddress(operand.getKind(), operand, null);
-            // Store result in global memory whose location is loadVar
-            emitStoreReturnValue(operand.getKind(), loadVar, operand(x.result()), null);
-        }
-        emitReturnNoVal();
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.ptx;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.ptx.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * This class implements the PTX specific portion of the LIR generator.
+ */
+public class PTXNodeLIRGenerator extends NodeLIRGenerator {
+
+    // Number of the predicate register that can be used when needed.
+    // This value will be recorded and incremented in the LIR instruction
+    // that sets a predicate register. (e.g., CompareOp)
+    private int nextPredRegNum;
+
+    public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class);
+    public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class);
+
+    public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory {
+
+        @Override
+        public LIRInstruction createMove(AllocatableValue result, Value input) {
+            throw GraalInternalError.unimplemented("PTXSpillMoveFactory.createMove()");
+        }
+    }
+
+    public PTXNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        super(graph, lirGenRes, lirGen);
+    }
+
+    public int getNextPredRegNumber() {
+        return nextPredRegNum;
+    }
+
+    @Override
+    public void emitPrologue(StructuredGraph graph) {
+        // Need to emit .param directives based on incoming arguments and return value
+        CallingConvention incomingArguments = gen.getCallingConvention();
+        Object returnObject = incomingArguments.getReturn();
+        AllocatableValue[] params = incomingArguments.getArguments();
+        int argCount = incomingArguments.getArgumentCount();
+
+        if (returnObject.equals(Value.ILLEGAL)) {
+            params = incomingArguments.getArguments();
+            append(new PTXParameterOp(params, false));
+        } else {
+            argCount = incomingArguments.getArgumentCount();
+            params = new Variable[argCount + 1];
+            for (int i = 0; i < argCount; i++) {
+                params[i] = incomingArguments.getArgument(i);
+            }
+            params[argCount] = (Variable) returnObject;
+            append(new PTXParameterOp(params, true));
+        }
+
+        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+            int localIndex = param.index();
+            Value paramValue = params[param.index()];
+            int parameterIndex = localIndex;
+            if (!Modifier.isStatic(graph.method().getModifiers())) {
+                parameterIndex--;
+            }
+            Warp warpAnnotation = parameterIndex >= 0 ? MetaUtil.getParameterAnnotation(Warp.class, parameterIndex, graph.method()) : null;
+            if (warpAnnotation != null) {
+                setResult(param, getGen().emitWarpParam(paramValue.getKind().getStackKind(), warpAnnotation));
+            } else {
+                setResult(param, getGen().emitLoadParam(paramValue.getKind().getStackKind(), paramValue, null));
+            }
+        }
+    }
+
+    private PTXLIRGenerator getGen() {
+        return (PTXLIRGenerator) gen;
+    }
+
+    @Override
+    protected <T extends AbstractBlock<T>> void emitPrologue(ResolvedJavaMethod method, BytecodeParser<T> parser) {
+        // Need to emit .param directives based on incoming arguments and return value
+        CallingConvention incomingArguments = gen.getCallingConvention();
+        Object returnObject = incomingArguments.getReturn();
+        AllocatableValue[] params = incomingArguments.getArguments();
+        int argCount = incomingArguments.getArgumentCount();
+
+        if (returnObject.equals(Value.ILLEGAL)) {
+            params = incomingArguments.getArguments();
+            append(new PTXParameterOp(params, false));
+        } else {
+            argCount = incomingArguments.getArgumentCount();
+            params = new Variable[argCount + 1];
+            for (int i = 0; i < argCount; i++) {
+                params[i] = incomingArguments.getArgument(i);
+            }
+            params[argCount] = (Variable) returnObject;
+            append(new PTXParameterOp(params, true));
+        }
+
+        Signature sig = method.getSignature();
+        boolean isStatic = Modifier.isStatic(method.getModifiers());
+
+        for (int i = 0; i < sig.getParameterCount(!isStatic); i++) {
+            Value paramValue = params[i];
+            int parameterIndex = i;
+            if (!isStatic) {
+                parameterIndex--;
+            }
+            Warp warpAnnotation = parameterIndex >= 0 ? MetaUtil.getParameterAnnotation(Warp.class, parameterIndex, method) : null;
+            if (warpAnnotation != null) {
+                // setResult(param, emitWarpParam(paramValue.getKind().getStackKind(),
+                // warpAnnotation));
+                parser.setParameter(i, getGen().emitWarpParam(paramValue.getKind().getStackKind(), warpAnnotation));
+            } else {
+                // setResult(param, emitLoadParam(paramValue.getKind().getStackKind(), paramValue,
+                // null));
+                parser.setParameter(i, getGen().emitLoadParam(paramValue.getKind().getStackKind(), paramValue, null));
+            }
+        }
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        // No peephole optimizations for now
+        return false;
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitDirectCall()");
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitIndirectCall()");
+    }
+
+    @Override
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitCompareAndSwap()");
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitBreakpointNode()");
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        // LIRFrameState info = state(i);
+        // append(new PTXSafepointOp(info, runtime().config, this));
+        Debug.log("visitSafePointNode unimplemented");
+    }
+
+    @Override
+    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
+        assert v.getKind() == Kind.Object;
+        append(new PTXMove.NullCheckOp(gen.load(operand(v)), gen.state(deopting)));
+    }
+
+    @Override
+    public void visitInfopointNode(InfopointNode i) {
+        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitInfopointNode()");
+    }
+
+    @Override
+    public void visitReturn(ReturnNode x) {
+        AllocatableValue operand = Value.ILLEGAL;
+        if (x.result() != null) {
+            operand = gen.resultOperandFor(x.result().getKind());
+            // Load the global memory address from return parameter
+            Variable loadVar = getGen().emitLoadReturnAddress(operand.getKind(), operand, null);
+            // Store result in global memory whose location is loadVar
+            getGen().emitStoreReturnValue(operand.getKind(), loadVar, operand(x.result()), null);
+        }
+        getGen().emitReturnNoVal();
+    }
+}
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -56,12 +56,10 @@
 import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.util.*;
 
@@ -78,9 +76,9 @@
         }
     }
 
-    public SPARCLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
-        lir.setSpillMoveFactory(new SPARCSpillMoveFactory());
+    public SPARCLIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
+        lirGenRes.getLIR().setSpillMoveFactory(new SPARCSpillMoveFactory());
     }
 
     @Override
@@ -132,6 +130,11 @@
     }
 
     @Override
+    public void emitData(AllocatableValue dst, byte[] data) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
     public SPARCAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
@@ -215,13 +218,7 @@
     }
 
     @Override
-    protected boolean peephole(ValueNode valueNode) {
-        // No peephole optimizations for now
-        return false;
-    }
-
-    @Override
-    protected void emitReturn(Value input) {
+    public void emitReturn(Value input) {
         append(new ReturnOp(input));
     }
 
@@ -918,35 +915,4 @@
         append(new ReturnOp(Value.ILLEGAL));
     }
 
-    @Override
-    public void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address) {
-        throw new InternalError("NYI");
-    }
-
-    @Override
-    public void visitBreakpointNode(BreakpointNode node) {
-        JavaType[] sig = new JavaType[node.arguments().size()];
-        for (int i = 0; i < sig.length; i++) {
-            sig[i] = node.arguments().get(i).stamp().javaType(getMetaAccess());
-        }
-
-        Value[] parameters = visitInvokeArguments(frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false), node.arguments());
-        append(new SPARCBreakpointOp(parameters));
-    }
-
-    @Override
-    public void emitUnwind(Value operand) {
-        throw new InternalError("NYI");
-    }
-
-    @Override
-    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
-        assert v.kind() == Kind.Object;
-        append(new NullCheckOp(load(operand(v)), state(deopting)));
-    }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        throw new InternalError("NYI");
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle 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.sparc;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public abstract class SPARCNodeLIRGenerator extends NodeLIRGenerator {
+
+    public SPARCNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        super(graph, lirGenRes, lirGen);
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        // No peephole optimizations for now
+        return false;
+    }
+
+    @Override
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address) {
+        throw new InternalError("NYI");
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        JavaType[] sig = new JavaType[node.arguments().size()];
+        for (int i = 0; i < sig.length; i++) {
+            sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
+        }
+
+        Value[] parameters = visitInvokeArguments(res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, gen.target(), false), node.arguments());
+        append(new SPARCBreakpointOp(parameters));
+    }
+
+    @Override
+    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
+        assert v.getKind() == Kind.Object;
+        append(new NullCheckOp(gen.load(operand(v)), gen.state(deopting)));
+    }
+
+    @Override
+    public void visitInfopointNode(InfopointNode i) {
+        throw new InternalError("NYI");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/AllocSpy.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,324 @@
+/*
+ * 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.compiler.test;
+
+import static java.lang.Boolean.*;
+import static java.lang.Integer.*;
+import static java.lang.System.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.google.monitoring.runtime.instrumentation.*;
+
+/**
+ * Tool for analyzing allocations within a scope using the <a
+ * href="https://code.google.com/p/java-allocation-instrumenter/">Java Allocation Instrumenter</a>.
+ * Allocation records are aggregated per stack trace at an allocation site. The size of the stack
+ * trace is governed by the value of the "AllocSpy.ContextSize" system property (default is 5).
+ * <p>
+ * Using this facility requires using -javaagent on the command line. For example:
+ * 
+ * <pre>
+ * mx --vm server unittest -javaagent:lib/java-allocation-instrumenter.jar -dsa -DAllocSpy.ContextSize=6 BC_iadd2
+ * </pre>
+ * 
+ * @see #SampleBytes
+ * @see #SampleInstances
+ * @see #HistogramLimit
+ * @see #NameSize
+ * @see #BarSize
+ * @see #NumberSize
+ */
+final class AllocSpy implements AutoCloseable {
+
+    static ThreadLocal<AllocSpy> current = new ThreadLocal<>();
+
+    private static final boolean ENABLED;
+    static {
+        boolean enabled = false;
+        try {
+            Field field = AllocationRecorder.class.getDeclaredField("instrumentation");
+            field.setAccessible(true);
+            enabled = field.get(null) != null;
+        } catch (Exception e) {
+        }
+        ENABLED = enabled;
+        if (ENABLED) {
+            AllocationRecorder.addSampler(new GraalContextSampler());
+        }
+    }
+
+    static String prop(String sfx) {
+        return AllocSpy.class.getSimpleName() + "." + sfx;
+    }
+
+    /**
+     * Determines if bytes per allocation site are recorded.
+     */
+    private static final boolean SampleBytes = parseBoolean(getProperty(prop("SampleBytes"), "true"));
+
+    /**
+     * Determines if allocations per allocation site are recorded.
+     */
+    private static final boolean SampleInstances = parseBoolean(getProperty(prop("SampleInstances"), "true"));
+
+    /**
+     * The size of context to record for each allocation site in terms of Graal frames.
+     */
+    private static final int ContextSize = getInteger(prop("ContextSize"), 5);
+
+    /**
+     * Only the {@code HistogramLimit} most frequent values are printed.
+     */
+    private static final int HistogramLimit = getInteger(prop("HistogramLimit"), 40);
+
+    /**
+     * The width of the allocation context column.
+     */
+    private static final int NameSize = getInteger(prop("NameSize"), 50);
+
+    /**
+     * The width of the histogram bar column.
+     */
+    private static final int BarSize = getInteger(prop("BarSize"), 100);
+
+    /**
+     * The width of the frequency column.
+     */
+    private static final int NumberSize = getInteger(prop("NumberSize"), 10);
+
+    final Object name;
+    final AllocSpy parent;
+    final Map<String, CountedValue> bytesPerGraalContext = new HashMap<>();
+    final Map<String, CountedValue> instancesPerGraalContext = new HashMap<>();
+
+    public static AllocSpy open(Object name) {
+        if (ENABLED) {
+            return new AllocSpy(name);
+        }
+        return null;
+    }
+
+    private AllocSpy(Object name) {
+        this.name = name;
+        parent = current.get();
+        current.set(this);
+    }
+
+    public void close() {
+        current.set(parent);
+        PrintStream ps = System.out;
+        ps.println("\n\nAllocation histograms for " + name);
+        if (SampleBytes) {
+            print(ps, bytesPerGraalContext, "BytesPerGraalContext", HistogramLimit, NameSize + 60, BarSize);
+        }
+        if (SampleInstances) {
+            print(ps, instancesPerGraalContext, "InstancesPerGraalContext", HistogramLimit, NameSize + 60, BarSize);
+        }
+    }
+
+    private static void printLine(PrintStream printStream, char c, int lineSize) {
+        char[] charArr = new char[lineSize];
+        Arrays.fill(charArr, c);
+        printStream.printf("%s%n", new String(charArr));
+    }
+
+    private static void print(PrintStream ps, Map<String, CountedValue> map, String name, int limit, int nameSize, int barSize) {
+        if (map.isEmpty()) {
+            return;
+        }
+
+        List<CountedValue> list = new ArrayList<>(map.values());
+        Collections.sort(list);
+
+        // Sum up the total number of elements.
+        int total = 0;
+        for (CountedValue cv : list) {
+            total += cv.getCount();
+        }
+
+        // Print header.
+        ps.printf("%s has %d unique elements and %d total elements:%n", name, list.size(), total);
+
+        int max = list.get(0).getCount();
+        final int lineSize = nameSize + NumberSize + barSize + 10;
+        printLine(ps, '-', lineSize);
+        String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n";
+        for (int i = 0; i < list.size() && i < limit; ++i) {
+            CountedValue cv = list.get(i);
+            int value = cv.getCount();
+            char[] bar = new char[(int) (((double) value / (double) max) * barSize)];
+            Arrays.fill(bar, '=');
+            String[] lines = String.valueOf(cv.getValue()).split("\\n");
+
+            String objectString = lines[0];
+            if (objectString.length() > nameSize) {
+                objectString = objectString.substring(0, nameSize - 3) + "...";
+            }
+            ps.printf(formatString, objectString, value, new String(bar));
+            for (int j = 1; j < lines.length; j++) {
+                String line = lines[j];
+                if (line.length() > nameSize) {
+                    line = line.substring(0, nameSize - 3) + "...";
+                }
+                ps.printf("|   %-" + (nameSize - 2) + "s | %-" + NumberSize + "s | %-" + barSize + "s |%n", line, " ", " ");
+
+            }
+        }
+        printLine(ps, '-', lineSize);
+    }
+
+    CountedValue bytesPerGraalContext(String context) {
+        return getCounter(context, bytesPerGraalContext);
+    }
+
+    CountedValue instancesPerGraalContext(String context) {
+        return getCounter(context, instancesPerGraalContext);
+    }
+
+    protected static CountedValue getCounter(String desc, Map<String, CountedValue> map) {
+        CountedValue count = map.get(desc);
+        if (count == null) {
+            count = new CountedValue(0, desc);
+            map.put(desc, count);
+        }
+        return count;
+    }
+
+    private static final String[] Excluded = {AllocSpy.class.getName(), AllocationRecorder.class.getName()};
+
+    private static boolean excludeFrame(String className) {
+        for (String e : Excluded) {
+            if (className.startsWith(e)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static class GraalContextSampler implements Sampler {
+
+        public void sampleAllocation(int count, String desc, Object newObj, long size) {
+            AllocSpy scope = current.get();
+            if (scope != null) {
+                StringBuilder sb = new StringBuilder(200);
+                Throwable t = new Throwable();
+                int remainingGraalFrames = ContextSize;
+                for (StackTraceElement e : t.getStackTrace()) {
+                    if (remainingGraalFrames < 0) {
+                        break;
+                    }
+                    String className = e.getClassName();
+                    boolean isGraalFrame = className.contains(".graal.");
+                    if (sb.length() != 0) {
+                        append(sb.append('\n'), e);
+                    } else {
+                        if (!excludeFrame(className)) {
+                            sb.append("type=").append(desc);
+                            if (count != 1) {
+                                sb.append("[]");
+                            }
+                            append(sb.append('\n'), e);
+                        }
+                    }
+                    if (isGraalFrame) {
+                        remainingGraalFrames--;
+                    }
+                }
+                String context = sb.toString();
+                if (SampleBytes) {
+                    scope.bytesPerGraalContext(context).add((int) size);
+                }
+                if (SampleInstances) {
+                    scope.instancesPerGraalContext(context).inc();
+                }
+            }
+        }
+
+        protected StringBuilder append(StringBuilder sb, StackTraceElement e) {
+            String className = e.getClassName();
+            int period = className.lastIndexOf('.');
+            if (period != -1) {
+                sb.append(className, period + 1, className.length());
+            } else {
+                sb.append(className);
+            }
+            sb.append('.').append(e.getMethodName());
+            if (e.isNativeMethod()) {
+                sb.append("(Native Method)");
+            } else if (e.getFileName() != null && e.getLineNumber() >= 0) {
+                sb.append('(').append(e.getFileName()).append(':').append(e.getLineNumber()).append(")");
+            } else {
+                sb.append("(Unknown Source)");
+            }
+            return sb;
+        }
+    }
+
+    /**
+     * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places
+     * values with higher frequencies first.
+     */
+    static class CountedValue implements Comparable<CountedValue> {
+
+        private int count;
+        private final Object value;
+
+        public CountedValue(int count, Object value) {
+            this.count = count;
+            this.value = value;
+        }
+
+        public int compareTo(CountedValue o) {
+            if (count < o.count) {
+                return 1;
+            } else if (count > o.count) {
+                return -1;
+            }
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return count + " -> " + value;
+        }
+
+        public void inc() {
+            count++;
+        }
+
+        public void add(int n) {
+            count += n;
+        }
+
+        public int getCount() {
+            return count;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -321,6 +321,7 @@
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        canonicalizer.apply(graph, context);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         if (loopPeeling) {
             new LoopTransformHighPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Sun Mar 30 16:08:33 2014 +0200
@@ -158,6 +158,7 @@
         new VerifyUsageWithEquals(JavaType.class).apply(graph, context);
         new VerifyUsageWithEquals(JavaMethod.class).apply(graph, context);
         new VerifyUsageWithEquals(JavaField.class).apply(graph, context);
+        new VerifyDebugUsage().apply(graph, context);
     }
 
     private static boolean matches(String[] filters, String s) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -130,7 +130,7 @@
     @Before
     public void beforeTest() {
         assert debugScope == null;
-        debugScope = Debug.scope(getClass().getSimpleName());
+        debugScope = Debug.scope(getClass());
     }
 
     @After
@@ -498,10 +498,9 @@
     }
 
     private CompilationResult compileBaseline(ResolvedJavaMethod javaMethod) {
-        try (Scope bds = Debug.scope("compileBaseline")) {
+        try (Scope bds = Debug.scope("CompileBaseline", javaMethod, providers.getCodeCache())) {
             BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess());
-            baselineCompiler.generate(javaMethod, -1);
-            return null;
+            return baselineCompiler.generate(javaMethod, -1, getBackend(), new CompilationResult(), javaMethod, CompilationResultBuilderFactory.Default);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -630,7 +629,7 @@
         final int id = compilationId.incrementAndGet();
 
         InstalledCode installedCode = null;
-        try (Scope ds = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
+        try (AllocSpy spy = AllocSpy.open(method); Scope ds = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
             final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
             if (printCompilation) {
                 TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s ...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature()));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfReorderTest.java	Sun Mar 30 16:08:33 2014 +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.compiler.test;
+
+import java.io.*;
+import java.util.*;
+
+import org.junit.*;
+
+public class IfReorderTest extends GraalCompilerTest {
+
+    private static Object fieldA = Integer.class;
+    private static Object fieldB = Double.class;
+
+    @Test
+    public void test1() {
+        test("test1Snippet", new ArrayList<>());
+    }
+
+    public static Object test1Snippet(Object o) {
+        /*
+         * Serializable and List are not mutually exclusive, so these two IFs should never be
+         * reordered.
+         */
+        if (branchProbability(0.1, o instanceof Serializable)) {
+            return fieldA;
+        }
+        if (branchProbability(0.9, o instanceof List)) {
+            return fieldB;
+        }
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class IntegerEqualsCanonicalizerTest extends GraalCompilerTest {
+
+    @Test
+    public void testShiftEquals() {
+        /*
+         * tests the canonicalization of (x >>> const) == 0 to x |test| (-1 << const)
+         */
+        test("testShiftEqualsSnippet", "testShiftEqualsReference");
+    }
+
+    @SuppressWarnings("unused") private static int field;
+
+    public static void testShiftEqualsSnippet(int x, int[] array, int y) {
+        // optimize
+        field = (x >>> 10) == 0 ? 1 : 0;
+        field = (array.length >> 10) == 0 ? 1 : 0;
+        field = (x << 10) == 0 ? 1 : 0;
+        // don't optimize
+        field = (x >> 10) == 0 ? 1 : 0;
+        field = (x >>> y) == 0 ? 1 : 0;
+        field = (x >> y) == 0 ? 1 : 0;
+        field = (x << y) == 0 ? 1 : 0;
+        field = (x >>> y) == 1 ? 1 : 0;
+        field = (x >> y) == 1 ? 1 : 0;
+        field = (x << y) == 1 ? 1 : 0;
+    }
+
+    public static void testShiftEqualsReference(int x, int[] array, int y) {
+        field = (x & 0xfffffc00) == 0 ? 1 : 0;
+        field = (array.length & 0xfffffc00) == 0 ? 1 : 0;
+        field = (x & 0x3fffff) == 0 ? 1 : 0;
+        // don't optimize signed right shifts
+        field = (x >> 10) == 0 ? 1 : 0;
+        // don't optimize no-constant shift amounts
+        field = (x >>> y) == 0 ? 1 : 0;
+        field = (x >> y) == 0 ? 1 : 0;
+        field = (x << y) == 0 ? 1 : 0;
+        // don't optimize non-zero comparisons
+        field = (x >>> y) == 1 ? 1 : 0;
+        field = (x >> y) == 1 ? 1 : 0;
+        field = (x << y) == 1 ? 1 : 0;
+    }
+
+    @Test
+    public void testCompare() {
+        test("testCompareSnippet", "testCompareReference");
+    }
+
+    public static void testCompareSnippet(int x, int y, int[] array1, int[] array2) {
+        int tempX = x;
+        int array1Length = array1.length;
+        int array2Length = array2.length;
+        // optimize
+        field = x == tempX ? 1 : 0;
+        field = x != tempX ? 1 : 0;
+        field = array1Length != (-1 - array2Length) ? 1 : 0;
+        field = array1Length == (-1 - array2Length) ? 1 : 0;
+        // don't optimize
+        field = x == y ? 1 : 0;
+        field = array1Length == array2Length ? 1 : 0;
+        field = array1Length == (-array2Length) ? 1 : 0;
+    }
+
+    public static void testCompareReference(int x, int y, int[] array1, int[] array2) {
+        int array1Length = array1.length;
+        int array2Length = array2.length;
+        // optimize
+        field = 1;
+        field = 0;
+        field = 1;
+        field = 0;
+        // don't optimize (overlapping value ranges)
+        field = x == y ? 1 : 0;
+        field = array1Length == array2Length ? 1 : 0;
+        field = array1Length == (-array2Length) ? 1 : 0;
+    }
+
+    private void test(String snippet, String referenceSnippet) {
+        StructuredGraph graph = getCanonicalizedGraph(snippet);
+        StructuredGraph referenceGraph = getCanonicalizedGraph(referenceSnippet);
+        assertEquals(referenceGraph, graph);
+    }
+
+    private StructuredGraph getCanonicalizedGraph(String snippet) {
+        StructuredGraph graph = parse(snippet);
+        new CanonicalizerPhase(false).apply(graph, new PhaseContext(getProviders(), null));
+        for (FrameState state : graph.getNodes(FrameState.class).snapshot()) {
+            state.replaceAtUsages(null);
+            state.safeDelete();
+        }
+        return graph;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryArithmeticTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,4333 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+public class MemoryArithmeticTest extends GraalCompilerTest {
+
+    @Override
+    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) {
+        return super.getCode(method, graph, true);
+    }
+
+    /**
+     * Called before a test is executed.
+     */
+    @Override
+    protected void before(Method method) {
+        // don't let any null exception tracking change the generated code.
+        getMetaAccess().lookupJavaMethod(method).reprofile();
+    }
+
+    /**
+     * A dummy field used by some tests to create side effects.
+     */
+    protected static int count;
+
+    static class FieldObject {
+        boolean booleanValue;
+        byte byteValue;
+        short shortValue;
+        char charValue;
+        int intValue;
+        float floatValue;
+        long longValue;
+        double doubleValue;
+        Object objectValue;
+    }
+
+    static FieldObject maxObject = new FieldObject();
+    static FieldObject minObject;
+
+    static final boolean booleanTestValue1 = false;
+    static final byte byteTestValue1 = 0;
+    static final short shortTestValue1 = 0;
+    static final char charTestValue1 = 0;
+    static final int intTestValue1 = 0;
+    static final float floatTestValue1 = 0;
+    static final long longTestValue1 = 0;
+    static final double doubleTestValue1 = 0;
+    static final Object objectTestValue1 = null;
+
+    static final boolean booleanTestValue2 = true;
+    static final byte byteTestValue2 = Byte.MAX_VALUE;
+    static final short shortTestValue2 = Short.MAX_VALUE;
+    static final char charTestValue2 = Character.MAX_VALUE;
+    static final int intTestValue2 = Integer.MAX_VALUE;
+    static final float floatTestValue2 = Float.MAX_VALUE;
+    static final long longTestValue2 = Long.MAX_VALUE;
+    static final double doubleTestValue2 = Double.MAX_VALUE;
+    static final Object objectTestValue2 = "String";
+
+    static {
+        maxObject.booleanValue = true;
+        maxObject.byteValue = Byte.MAX_VALUE;
+        maxObject.shortValue = Short.MAX_VALUE;
+        maxObject.charValue = Character.MAX_VALUE;
+        maxObject.intValue = Integer.MAX_VALUE;
+        maxObject.floatValue = Float.MAX_VALUE;
+        maxObject.longValue = Long.MAX_VALUE;
+        maxObject.doubleValue = Double.MAX_VALUE;
+        maxObject.objectValue = "String";
+    }
+
+    public static Object testBooleanCompare(FieldObject f, boolean booleanValue) {
+        if (f.booleanValue == booleanValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testBooleanCompareConstant1(FieldObject f) {
+        if (f.booleanValue == booleanTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testBooleanCompareConstant2(FieldObject f) {
+        if (f.booleanValue == booleanTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testBooleanCompares() {
+        FieldObject f = new FieldObject();
+        test("testBooleanCompare", f, booleanTestValue1);
+        test("testBooleanCompareConstant1", f);
+        test("testBooleanCompareConstant2", f);
+    }
+
+    @Test
+    public void testBooleanNullCompares() {
+        test("testBooleanCompare", null, booleanTestValue1);
+    }
+
+    @Test
+    public void testBooleanNullCompares1() {
+        test("testBooleanCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testBooleanNullCompares2() {
+        test("testBooleanCompareConstant2", (Object) null);
+    }
+
+    public static Object testByteCompare(FieldObject f, byte byteValue) {
+        if (f.byteValue == byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareConstant1(FieldObject f) {
+        if (f.byteValue == byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareConstant2(FieldObject f) {
+        if (f.byteValue == byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteCompares() {
+        FieldObject f = new FieldObject();
+        test("testByteCompare", f, byteTestValue1);
+        test("testByteCompareConstant1", f);
+        test("testByteCompareConstant2", f);
+    }
+
+    @Test
+    public void testByteNullCompares() {
+        test("testByteCompare", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullCompares1() {
+        test("testByteCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullCompares2() {
+        test("testByteCompareConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareLess(FieldObject f, byte byteValue) {
+        if (f.byteValue < byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessConstant1(FieldObject f) {
+        if (f.byteValue < byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessConstant2(FieldObject f) {
+        if (f.byteValue < byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareLess", f, byteTestValue1);
+        test("testByteCompareLessConstant1", f);
+        test("testByteCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesLess() {
+        test("testByteCompareLess", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesLess1() {
+        test("testByteCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesLess2() {
+        test("testByteCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareLess(FieldObject f, byte byteValue) {
+        if (byteValue < f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessConstant1(FieldObject f) {
+        if (byteTestValue1 < f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessConstant2(FieldObject f) {
+        if (byteTestValue2 < f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareLess", f, byteTestValue1);
+        test("testByteSwappedCompareLessConstant1", f);
+        test("testByteSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLess() {
+        test("testByteSwappedCompareLess", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLess1() {
+        test("testByteSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLess2() {
+        test("testByteSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareLessEqual(FieldObject f, byte byteValue) {
+        if (f.byteValue <= byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessEqualConstant1(FieldObject f) {
+        if (f.byteValue <= byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareLessEqualConstant2(FieldObject f) {
+        if (f.byteValue <= byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareLessEqual", f, byteTestValue1);
+        test("testByteCompareLessEqualConstant1", f);
+        test("testByteCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesLessEqual() {
+        test("testByteCompareLessEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesLessEqual1() {
+        test("testByteCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesLessEqual2() {
+        test("testByteCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareLessEqual(FieldObject f, byte byteValue) {
+        if (byteValue <= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (byteTestValue1 <= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (byteTestValue2 <= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareLessEqual", f, byteTestValue1);
+        test("testByteSwappedCompareLessEqualConstant1", f);
+        test("testByteSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLessEqual() {
+        test("testByteSwappedCompareLessEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLessEqual1() {
+        test("testByteSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesLessEqual2() {
+        test("testByteSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareGreater(FieldObject f, byte byteValue) {
+        if (f.byteValue > byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterConstant1(FieldObject f) {
+        if (f.byteValue > byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterConstant2(FieldObject f) {
+        if (f.byteValue > byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareGreater", f, byteTestValue1);
+        test("testByteCompareGreaterConstant1", f);
+        test("testByteCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesGreater() {
+        test("testByteCompareGreater", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesGreater1() {
+        test("testByteCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesGreater2() {
+        test("testByteCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareGreater(FieldObject f, byte byteValue) {
+        if (byteValue > f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterConstant1(FieldObject f) {
+        if (byteTestValue1 > f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterConstant2(FieldObject f) {
+        if (byteTestValue2 > f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareGreater", f, byteTestValue1);
+        test("testByteSwappedCompareGreaterConstant1", f);
+        test("testByteSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreater() {
+        test("testByteSwappedCompareGreater", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreater1() {
+        test("testByteSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreater2() {
+        test("testByteSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testByteCompareGreaterEqual(FieldObject f, byte byteValue) {
+        if (f.byteValue >= byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.byteValue >= byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.byteValue >= byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteCompareGreaterEqual", f, byteTestValue1);
+        test("testByteCompareGreaterEqualConstant1", f);
+        test("testByteCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullComparesGreaterEqual() {
+        test("testByteCompareGreaterEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullComparesGreaterEqual1() {
+        test("testByteCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullComparesGreaterEqual2() {
+        test("testByteCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testByteSwappedCompareGreaterEqual(FieldObject f, byte byteValue) {
+        if (byteValue >= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (byteTestValue1 >= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (byteTestValue2 >= f.byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testByteSwappedCompareGreaterEqual", f, byteTestValue1);
+        test("testByteSwappedCompareGreaterEqualConstant1", f);
+        test("testByteSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreaterEqual() {
+        test("testByteSwappedCompareGreaterEqual", null, byteTestValue1);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreaterEqual1() {
+        test("testByteSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testByteNullSwappedComparesGreaterEqual2() {
+        test("testByteSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortCompare(FieldObject f, short shortValue) {
+        if (f.shortValue == shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareConstant1(FieldObject f) {
+        if (f.shortValue == shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareConstant2(FieldObject f) {
+        if (f.shortValue == shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortCompares() {
+        FieldObject f = new FieldObject();
+        test("testShortCompare", f, shortTestValue1);
+        test("testShortCompareConstant1", f);
+        test("testShortCompareConstant2", f);
+    }
+
+    @Test
+    public void testShortNullCompares() {
+        test("testShortCompare", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullCompares1() {
+        test("testShortCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullCompares2() {
+        test("testShortCompareConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareLess(FieldObject f, short shortValue) {
+        if (f.shortValue < shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessConstant1(FieldObject f) {
+        if (f.shortValue < shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessConstant2(FieldObject f) {
+        if (f.shortValue < shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareLess", f, shortTestValue1);
+        test("testShortCompareLessConstant1", f);
+        test("testShortCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesLess() {
+        test("testShortCompareLess", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesLess1() {
+        test("testShortCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesLess2() {
+        test("testShortCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareLess(FieldObject f, short shortValue) {
+        if (shortValue < f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessConstant1(FieldObject f) {
+        if (shortTestValue1 < f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessConstant2(FieldObject f) {
+        if (shortTestValue2 < f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareLess", f, shortTestValue1);
+        test("testShortSwappedCompareLessConstant1", f);
+        test("testShortSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLess() {
+        test("testShortSwappedCompareLess", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLess1() {
+        test("testShortSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLess2() {
+        test("testShortSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareLessEqual(FieldObject f, short shortValue) {
+        if (f.shortValue <= shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessEqualConstant1(FieldObject f) {
+        if (f.shortValue <= shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareLessEqualConstant2(FieldObject f) {
+        if (f.shortValue <= shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareLessEqual", f, shortTestValue1);
+        test("testShortCompareLessEqualConstant1", f);
+        test("testShortCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesLessEqual() {
+        test("testShortCompareLessEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesLessEqual1() {
+        test("testShortCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesLessEqual2() {
+        test("testShortCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareLessEqual(FieldObject f, short shortValue) {
+        if (shortValue <= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (shortTestValue1 <= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (shortTestValue2 <= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareLessEqual", f, shortTestValue1);
+        test("testShortSwappedCompareLessEqualConstant1", f);
+        test("testShortSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLessEqual() {
+        test("testShortSwappedCompareLessEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLessEqual1() {
+        test("testShortSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesLessEqual2() {
+        test("testShortSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareGreater(FieldObject f, short shortValue) {
+        if (f.shortValue > shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterConstant1(FieldObject f) {
+        if (f.shortValue > shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterConstant2(FieldObject f) {
+        if (f.shortValue > shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareGreater", f, shortTestValue1);
+        test("testShortCompareGreaterConstant1", f);
+        test("testShortCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesGreater() {
+        test("testShortCompareGreater", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesGreater1() {
+        test("testShortCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesGreater2() {
+        test("testShortCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareGreater(FieldObject f, short shortValue) {
+        if (shortValue > f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterConstant1(FieldObject f) {
+        if (shortTestValue1 > f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterConstant2(FieldObject f) {
+        if (shortTestValue2 > f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareGreater", f, shortTestValue1);
+        test("testShortSwappedCompareGreaterConstant1", f);
+        test("testShortSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreater() {
+        test("testShortSwappedCompareGreater", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreater1() {
+        test("testShortSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreater2() {
+        test("testShortSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testShortCompareGreaterEqual(FieldObject f, short shortValue) {
+        if (f.shortValue >= shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.shortValue >= shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.shortValue >= shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortCompareGreaterEqual", f, shortTestValue1);
+        test("testShortCompareGreaterEqualConstant1", f);
+        test("testShortCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullComparesGreaterEqual() {
+        test("testShortCompareGreaterEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullComparesGreaterEqual1() {
+        test("testShortCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullComparesGreaterEqual2() {
+        test("testShortCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testShortSwappedCompareGreaterEqual(FieldObject f, short shortValue) {
+        if (shortValue >= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (shortTestValue1 >= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (shortTestValue2 >= f.shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testShortSwappedCompareGreaterEqual", f, shortTestValue1);
+        test("testShortSwappedCompareGreaterEqualConstant1", f);
+        test("testShortSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreaterEqual() {
+        test("testShortSwappedCompareGreaterEqual", null, shortTestValue1);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreaterEqual1() {
+        test("testShortSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testShortNullSwappedComparesGreaterEqual2() {
+        test("testShortSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharCompare(FieldObject f, char charValue) {
+        if (f.charValue == charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareConstant1(FieldObject f) {
+        if (f.charValue == charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareConstant2(FieldObject f) {
+        if (f.charValue == charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharCompares() {
+        FieldObject f = new FieldObject();
+        test("testCharCompare", f, charTestValue1);
+        test("testCharCompareConstant1", f);
+        test("testCharCompareConstant2", f);
+    }
+
+    @Test
+    public void testCharNullCompares() {
+        test("testCharCompare", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullCompares1() {
+        test("testCharCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullCompares2() {
+        test("testCharCompareConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareLess(FieldObject f, char charValue) {
+        if (f.charValue < charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessConstant1(FieldObject f) {
+        if (f.charValue < charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessConstant2(FieldObject f) {
+        if (f.charValue < charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareLess", f, charTestValue1);
+        test("testCharCompareLessConstant1", f);
+        test("testCharCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesLess() {
+        test("testCharCompareLess", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesLess1() {
+        test("testCharCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesLess2() {
+        test("testCharCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareLess(FieldObject f, char charValue) {
+        if (charValue < f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessConstant1(FieldObject f) {
+        if (charTestValue1 < f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessConstant2(FieldObject f) {
+        if (charTestValue2 < f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareLess", f, charTestValue1);
+        test("testCharSwappedCompareLessConstant1", f);
+        test("testCharSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLess() {
+        test("testCharSwappedCompareLess", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLess1() {
+        test("testCharSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLess2() {
+        test("testCharSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareLessEqual(FieldObject f, char charValue) {
+        if (f.charValue <= charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessEqualConstant1(FieldObject f) {
+        if (f.charValue <= charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareLessEqualConstant2(FieldObject f) {
+        if (f.charValue <= charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareLessEqual", f, charTestValue1);
+        test("testCharCompareLessEqualConstant1", f);
+        test("testCharCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesLessEqual() {
+        test("testCharCompareLessEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesLessEqual1() {
+        test("testCharCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesLessEqual2() {
+        test("testCharCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareLessEqual(FieldObject f, char charValue) {
+        if (charValue <= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (charTestValue1 <= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (charTestValue2 <= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareLessEqual", f, charTestValue1);
+        test("testCharSwappedCompareLessEqualConstant1", f);
+        test("testCharSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLessEqual() {
+        test("testCharSwappedCompareLessEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLessEqual1() {
+        test("testCharSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesLessEqual2() {
+        test("testCharSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareGreater(FieldObject f, char charValue) {
+        if (f.charValue > charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterConstant1(FieldObject f) {
+        if (f.charValue > charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterConstant2(FieldObject f) {
+        if (f.charValue > charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareGreater", f, charTestValue1);
+        test("testCharCompareGreaterConstant1", f);
+        test("testCharCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesGreater() {
+        test("testCharCompareGreater", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesGreater1() {
+        test("testCharCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesGreater2() {
+        test("testCharCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareGreater(FieldObject f, char charValue) {
+        if (charValue > f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterConstant1(FieldObject f) {
+        if (charTestValue1 > f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterConstant2(FieldObject f) {
+        if (charTestValue2 > f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareGreater", f, charTestValue1);
+        test("testCharSwappedCompareGreaterConstant1", f);
+        test("testCharSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreater() {
+        test("testCharSwappedCompareGreater", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreater1() {
+        test("testCharSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreater2() {
+        test("testCharSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testCharCompareGreaterEqual(FieldObject f, char charValue) {
+        if (f.charValue >= charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.charValue >= charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.charValue >= charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharCompareGreaterEqual", f, charTestValue1);
+        test("testCharCompareGreaterEqualConstant1", f);
+        test("testCharCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullComparesGreaterEqual() {
+        test("testCharCompareGreaterEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullComparesGreaterEqual1() {
+        test("testCharCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullComparesGreaterEqual2() {
+        test("testCharCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testCharSwappedCompareGreaterEqual(FieldObject f, char charValue) {
+        if (charValue >= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (charTestValue1 >= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (charTestValue2 >= f.charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testCharSwappedCompareGreaterEqual", f, charTestValue1);
+        test("testCharSwappedCompareGreaterEqualConstant1", f);
+        test("testCharSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreaterEqual() {
+        test("testCharSwappedCompareGreaterEqual", null, charTestValue1);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreaterEqual1() {
+        test("testCharSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testCharNullSwappedComparesGreaterEqual2() {
+        test("testCharSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntCompare(FieldObject f, int intValue) {
+        if (f.intValue == intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareConstant1(FieldObject f) {
+        if (f.intValue == intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareConstant2(FieldObject f) {
+        if (f.intValue == intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntCompares() {
+        FieldObject f = new FieldObject();
+        test("testIntCompare", f, intTestValue1);
+        test("testIntCompareConstant1", f);
+        test("testIntCompareConstant2", f);
+    }
+
+    @Test
+    public void testIntNullCompares() {
+        test("testIntCompare", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullCompares1() {
+        test("testIntCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullCompares2() {
+        test("testIntCompareConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareLess(FieldObject f, int intValue) {
+        if (f.intValue < intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessConstant1(FieldObject f) {
+        if (f.intValue < intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessConstant2(FieldObject f) {
+        if (f.intValue < intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareLess", f, intTestValue1);
+        test("testIntCompareLessConstant1", f);
+        test("testIntCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesLess() {
+        test("testIntCompareLess", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesLess1() {
+        test("testIntCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesLess2() {
+        test("testIntCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareLess(FieldObject f, int intValue) {
+        if (intValue < f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessConstant1(FieldObject f) {
+        if (intTestValue1 < f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessConstant2(FieldObject f) {
+        if (intTestValue2 < f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareLess", f, intTestValue1);
+        test("testIntSwappedCompareLessConstant1", f);
+        test("testIntSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLess() {
+        test("testIntSwappedCompareLess", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLess1() {
+        test("testIntSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLess2() {
+        test("testIntSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareLessEqual(FieldObject f, int intValue) {
+        if (f.intValue <= intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessEqualConstant1(FieldObject f) {
+        if (f.intValue <= intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareLessEqualConstant2(FieldObject f) {
+        if (f.intValue <= intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareLessEqual", f, intTestValue1);
+        test("testIntCompareLessEqualConstant1", f);
+        test("testIntCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesLessEqual() {
+        test("testIntCompareLessEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesLessEqual1() {
+        test("testIntCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesLessEqual2() {
+        test("testIntCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareLessEqual(FieldObject f, int intValue) {
+        if (intValue <= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (intTestValue1 <= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (intTestValue2 <= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareLessEqual", f, intTestValue1);
+        test("testIntSwappedCompareLessEqualConstant1", f);
+        test("testIntSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLessEqual() {
+        test("testIntSwappedCompareLessEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLessEqual1() {
+        test("testIntSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesLessEqual2() {
+        test("testIntSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareGreater(FieldObject f, int intValue) {
+        if (f.intValue > intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterConstant1(FieldObject f) {
+        if (f.intValue > intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterConstant2(FieldObject f) {
+        if (f.intValue > intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareGreater", f, intTestValue1);
+        test("testIntCompareGreaterConstant1", f);
+        test("testIntCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesGreater() {
+        test("testIntCompareGreater", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesGreater1() {
+        test("testIntCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesGreater2() {
+        test("testIntCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareGreater(FieldObject f, int intValue) {
+        if (intValue > f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterConstant1(FieldObject f) {
+        if (intTestValue1 > f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterConstant2(FieldObject f) {
+        if (intTestValue2 > f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareGreater", f, intTestValue1);
+        test("testIntSwappedCompareGreaterConstant1", f);
+        test("testIntSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreater() {
+        test("testIntSwappedCompareGreater", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreater1() {
+        test("testIntSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreater2() {
+        test("testIntSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testIntCompareGreaterEqual(FieldObject f, int intValue) {
+        if (f.intValue >= intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.intValue >= intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.intValue >= intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntCompareGreaterEqual", f, intTestValue1);
+        test("testIntCompareGreaterEqualConstant1", f);
+        test("testIntCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullComparesGreaterEqual() {
+        test("testIntCompareGreaterEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullComparesGreaterEqual1() {
+        test("testIntCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullComparesGreaterEqual2() {
+        test("testIntCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testIntSwappedCompareGreaterEqual(FieldObject f, int intValue) {
+        if (intValue >= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (intTestValue1 >= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (intTestValue2 >= f.intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testIntSwappedCompareGreaterEqual", f, intTestValue1);
+        test("testIntSwappedCompareGreaterEqualConstant1", f);
+        test("testIntSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreaterEqual() {
+        test("testIntSwappedCompareGreaterEqual", null, intTestValue1);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreaterEqual1() {
+        test("testIntSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testIntNullSwappedComparesGreaterEqual2() {
+        test("testIntSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompare(FieldObject f, float floatValue) {
+        if (f.floatValue == floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareConstant1(FieldObject f) {
+        if (f.floatValue == floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareConstant2(FieldObject f) {
+        if (f.floatValue == floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatCompares() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompare", f, floatTestValue1);
+        test("testFloatCompareConstant1", f);
+        test("testFloatCompareConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullCompares() {
+        test("testFloatCompare", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullCompares1() {
+        test("testFloatCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullCompares2() {
+        test("testFloatCompareConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareLess(FieldObject f, float floatValue) {
+        if (f.floatValue < floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessConstant1(FieldObject f) {
+        if (f.floatValue < floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessConstant2(FieldObject f) {
+        if (f.floatValue < floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareLess", f, floatTestValue1);
+        test("testFloatCompareLessConstant1", f);
+        test("testFloatCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesLess() {
+        test("testFloatCompareLess", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesLess1() {
+        test("testFloatCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesLess2() {
+        test("testFloatCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareLess(FieldObject f, float floatValue) {
+        if (floatValue < f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessConstant1(FieldObject f) {
+        if (floatTestValue1 < f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessConstant2(FieldObject f) {
+        if (floatTestValue2 < f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareLess", f, floatTestValue1);
+        test("testFloatSwappedCompareLessConstant1", f);
+        test("testFloatSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLess() {
+        test("testFloatSwappedCompareLess", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLess1() {
+        test("testFloatSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLess2() {
+        test("testFloatSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareLessEqual(FieldObject f, float floatValue) {
+        if (f.floatValue <= floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessEqualConstant1(FieldObject f) {
+        if (f.floatValue <= floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareLessEqualConstant2(FieldObject f) {
+        if (f.floatValue <= floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareLessEqual", f, floatTestValue1);
+        test("testFloatCompareLessEqualConstant1", f);
+        test("testFloatCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesLessEqual() {
+        test("testFloatCompareLessEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesLessEqual1() {
+        test("testFloatCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesLessEqual2() {
+        test("testFloatCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareLessEqual(FieldObject f, float floatValue) {
+        if (floatValue <= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (floatTestValue1 <= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (floatTestValue2 <= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareLessEqual", f, floatTestValue1);
+        test("testFloatSwappedCompareLessEqualConstant1", f);
+        test("testFloatSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLessEqual() {
+        test("testFloatSwappedCompareLessEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLessEqual1() {
+        test("testFloatSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesLessEqual2() {
+        test("testFloatSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareGreater(FieldObject f, float floatValue) {
+        if (f.floatValue > floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterConstant1(FieldObject f) {
+        if (f.floatValue > floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterConstant2(FieldObject f) {
+        if (f.floatValue > floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareGreater", f, floatTestValue1);
+        test("testFloatCompareGreaterConstant1", f);
+        test("testFloatCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesGreater() {
+        test("testFloatCompareGreater", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesGreater1() {
+        test("testFloatCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesGreater2() {
+        test("testFloatCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareGreater(FieldObject f, float floatValue) {
+        if (floatValue > f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterConstant1(FieldObject f) {
+        if (floatTestValue1 > f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterConstant2(FieldObject f) {
+        if (floatTestValue2 > f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareGreater", f, floatTestValue1);
+        test("testFloatSwappedCompareGreaterConstant1", f);
+        test("testFloatSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreater() {
+        test("testFloatSwappedCompareGreater", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreater1() {
+        test("testFloatSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreater2() {
+        test("testFloatSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testFloatCompareGreaterEqual(FieldObject f, float floatValue) {
+        if (f.floatValue >= floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.floatValue >= floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.floatValue >= floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompareGreaterEqual", f, floatTestValue1);
+        test("testFloatCompareGreaterEqualConstant1", f);
+        test("testFloatCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullComparesGreaterEqual() {
+        test("testFloatCompareGreaterEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullComparesGreaterEqual1() {
+        test("testFloatCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullComparesGreaterEqual2() {
+        test("testFloatCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testFloatSwappedCompareGreaterEqual(FieldObject f, float floatValue) {
+        if (floatValue >= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (floatTestValue1 >= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (floatTestValue2 >= f.floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testFloatSwappedCompareGreaterEqual", f, floatTestValue1);
+        test("testFloatSwappedCompareGreaterEqualConstant1", f);
+        test("testFloatSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreaterEqual() {
+        test("testFloatSwappedCompareGreaterEqual", null, floatTestValue1);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreaterEqual1() {
+        test("testFloatSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testFloatNullSwappedComparesGreaterEqual2() {
+        test("testFloatSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongCompare(FieldObject f, long longValue) {
+        if (f.longValue == longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareConstant1(FieldObject f) {
+        if (f.longValue == longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareConstant2(FieldObject f) {
+        if (f.longValue == longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongCompares() {
+        FieldObject f = new FieldObject();
+        test("testLongCompare", f, longTestValue1);
+        test("testLongCompareConstant1", f);
+        test("testLongCompareConstant2", f);
+    }
+
+    @Test
+    public void testLongNullCompares() {
+        test("testLongCompare", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullCompares1() {
+        test("testLongCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullCompares2() {
+        test("testLongCompareConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareLess(FieldObject f, long longValue) {
+        if (f.longValue < longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessConstant1(FieldObject f) {
+        if (f.longValue < longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessConstant2(FieldObject f) {
+        if (f.longValue < longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareLess", f, longTestValue1);
+        test("testLongCompareLessConstant1", f);
+        test("testLongCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesLess() {
+        test("testLongCompareLess", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesLess1() {
+        test("testLongCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesLess2() {
+        test("testLongCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareLess(FieldObject f, long longValue) {
+        if (longValue < f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessConstant1(FieldObject f) {
+        if (longTestValue1 < f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessConstant2(FieldObject f) {
+        if (longTestValue2 < f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareLess", f, longTestValue1);
+        test("testLongSwappedCompareLessConstant1", f);
+        test("testLongSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLess() {
+        test("testLongSwappedCompareLess", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLess1() {
+        test("testLongSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLess2() {
+        test("testLongSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareLessEqual(FieldObject f, long longValue) {
+        if (f.longValue <= longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessEqualConstant1(FieldObject f) {
+        if (f.longValue <= longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareLessEqualConstant2(FieldObject f) {
+        if (f.longValue <= longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareLessEqual", f, longTestValue1);
+        test("testLongCompareLessEqualConstant1", f);
+        test("testLongCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesLessEqual() {
+        test("testLongCompareLessEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesLessEqual1() {
+        test("testLongCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesLessEqual2() {
+        test("testLongCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareLessEqual(FieldObject f, long longValue) {
+        if (longValue <= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (longTestValue1 <= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (longTestValue2 <= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareLessEqual", f, longTestValue1);
+        test("testLongSwappedCompareLessEqualConstant1", f);
+        test("testLongSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLessEqual() {
+        test("testLongSwappedCompareLessEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLessEqual1() {
+        test("testLongSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesLessEqual2() {
+        test("testLongSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareGreater(FieldObject f, long longValue) {
+        if (f.longValue > longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterConstant1(FieldObject f) {
+        if (f.longValue > longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterConstant2(FieldObject f) {
+        if (f.longValue > longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareGreater", f, longTestValue1);
+        test("testLongCompareGreaterConstant1", f);
+        test("testLongCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesGreater() {
+        test("testLongCompareGreater", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesGreater1() {
+        test("testLongCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesGreater2() {
+        test("testLongCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareGreater(FieldObject f, long longValue) {
+        if (longValue > f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterConstant1(FieldObject f) {
+        if (longTestValue1 > f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterConstant2(FieldObject f) {
+        if (longTestValue2 > f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareGreater", f, longTestValue1);
+        test("testLongSwappedCompareGreaterConstant1", f);
+        test("testLongSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreater() {
+        test("testLongSwappedCompareGreater", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreater1() {
+        test("testLongSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreater2() {
+        test("testLongSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testLongCompareGreaterEqual(FieldObject f, long longValue) {
+        if (f.longValue >= longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.longValue >= longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.longValue >= longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongCompareGreaterEqual", f, longTestValue1);
+        test("testLongCompareGreaterEqualConstant1", f);
+        test("testLongCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullComparesGreaterEqual() {
+        test("testLongCompareGreaterEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullComparesGreaterEqual1() {
+        test("testLongCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullComparesGreaterEqual2() {
+        test("testLongCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testLongSwappedCompareGreaterEqual(FieldObject f, long longValue) {
+        if (longValue >= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (longTestValue1 >= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (longTestValue2 >= f.longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testLongSwappedCompareGreaterEqual", f, longTestValue1);
+        test("testLongSwappedCompareGreaterEqualConstant1", f);
+        test("testLongSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreaterEqual() {
+        test("testLongSwappedCompareGreaterEqual", null, longTestValue1);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreaterEqual1() {
+        test("testLongSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testLongNullSwappedComparesGreaterEqual2() {
+        test("testLongSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompare(FieldObject f, double doubleValue) {
+        if (f.doubleValue == doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareConstant1(FieldObject f) {
+        if (f.doubleValue == doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareConstant2(FieldObject f) {
+        if (f.doubleValue == doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleCompares() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompare", f, doubleTestValue1);
+        test("testDoubleCompareConstant1", f);
+        test("testDoubleCompareConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullCompares() {
+        test("testDoubleCompare", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullCompares1() {
+        test("testDoubleCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullCompares2() {
+        test("testDoubleCompareConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareLess(FieldObject f, double doubleValue) {
+        if (f.doubleValue < doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessConstant1(FieldObject f) {
+        if (f.doubleValue < doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessConstant2(FieldObject f) {
+        if (f.doubleValue < doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareLess", f, doubleTestValue1);
+        test("testDoubleCompareLessConstant1", f);
+        test("testDoubleCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesLess() {
+        test("testDoubleCompareLess", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesLess1() {
+        test("testDoubleCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesLess2() {
+        test("testDoubleCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareLess(FieldObject f, double doubleValue) {
+        if (doubleValue < f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessConstant1(FieldObject f) {
+        if (doubleTestValue1 < f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessConstant2(FieldObject f) {
+        if (doubleTestValue2 < f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesLess() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareLess", f, doubleTestValue1);
+        test("testDoubleSwappedCompareLessConstant1", f);
+        test("testDoubleSwappedCompareLessConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLess() {
+        test("testDoubleSwappedCompareLess", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLess1() {
+        test("testDoubleSwappedCompareLessConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLess2() {
+        test("testDoubleSwappedCompareLessConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareLessEqual(FieldObject f, double doubleValue) {
+        if (f.doubleValue <= doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessEqualConstant1(FieldObject f) {
+        if (f.doubleValue <= doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareLessEqualConstant2(FieldObject f) {
+        if (f.doubleValue <= doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareLessEqual", f, doubleTestValue1);
+        test("testDoubleCompareLessEqualConstant1", f);
+        test("testDoubleCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesLessEqual() {
+        test("testDoubleCompareLessEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesLessEqual1() {
+        test("testDoubleCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesLessEqual2() {
+        test("testDoubleCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareLessEqual(FieldObject f, double doubleValue) {
+        if (doubleValue <= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessEqualConstant1(FieldObject f) {
+        if (doubleTestValue1 <= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareLessEqualConstant2(FieldObject f) {
+        if (doubleTestValue2 <= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesLessEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareLessEqual", f, doubleTestValue1);
+        test("testDoubleSwappedCompareLessEqualConstant1", f);
+        test("testDoubleSwappedCompareLessEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLessEqual() {
+        test("testDoubleSwappedCompareLessEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLessEqual1() {
+        test("testDoubleSwappedCompareLessEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesLessEqual2() {
+        test("testDoubleSwappedCompareLessEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareGreater(FieldObject f, double doubleValue) {
+        if (f.doubleValue > doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterConstant1(FieldObject f) {
+        if (f.doubleValue > doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterConstant2(FieldObject f) {
+        if (f.doubleValue > doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareGreater", f, doubleTestValue1);
+        test("testDoubleCompareGreaterConstant1", f);
+        test("testDoubleCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreater() {
+        test("testDoubleCompareGreater", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreater1() {
+        test("testDoubleCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreater2() {
+        test("testDoubleCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareGreater(FieldObject f, double doubleValue) {
+        if (doubleValue > f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterConstant1(FieldObject f) {
+        if (doubleTestValue1 > f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterConstant2(FieldObject f) {
+        if (doubleTestValue2 > f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesGreater() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareGreater", f, doubleTestValue1);
+        test("testDoubleSwappedCompareGreaterConstant1", f);
+        test("testDoubleSwappedCompareGreaterConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreater() {
+        test("testDoubleSwappedCompareGreater", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreater1() {
+        test("testDoubleSwappedCompareGreaterConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreater2() {
+        test("testDoubleSwappedCompareGreaterConstant2", (Object) null);
+    }
+
+    public static Object testDoubleCompareGreaterEqual(FieldObject f, double doubleValue) {
+        if (f.doubleValue >= doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterEqualConstant1(FieldObject f) {
+        if (f.doubleValue >= doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareGreaterEqualConstant2(FieldObject f) {
+        if (f.doubleValue >= doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompareGreaterEqual", f, doubleTestValue1);
+        test("testDoubleCompareGreaterEqualConstant1", f);
+        test("testDoubleCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreaterEqual() {
+        test("testDoubleCompareGreaterEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreaterEqual1() {
+        test("testDoubleCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullComparesGreaterEqual2() {
+        test("testDoubleCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testDoubleSwappedCompareGreaterEqual(FieldObject f, double doubleValue) {
+        if (doubleValue >= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterEqualConstant1(FieldObject f) {
+        if (doubleTestValue1 >= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleSwappedCompareGreaterEqualConstant2(FieldObject f) {
+        if (doubleTestValue2 >= f.doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleSwappedComparesGreaterEqual() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSwappedCompareGreaterEqual", f, doubleTestValue1);
+        test("testDoubleSwappedCompareGreaterEqualConstant1", f);
+        test("testDoubleSwappedCompareGreaterEqualConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreaterEqual() {
+        test("testDoubleSwappedCompareGreaterEqual", null, doubleTestValue1);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreaterEqual1() {
+        test("testDoubleSwappedCompareGreaterEqualConstant1", (Object) null);
+    }
+
+    @Test
+    public void testDoubleNullSwappedComparesGreaterEqual2() {
+        test("testDoubleSwappedCompareGreaterEqualConstant2", (Object) null);
+    }
+
+    public static Object testObjectCompare(FieldObject f, Object objectValue) {
+        if (f.objectValue == objectValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testObjectCompareConstant1(FieldObject f) {
+        if (f.objectValue == objectTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testObjectCompareConstant2(FieldObject f) {
+        if (f.objectValue == objectTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testObjectCompares() {
+        FieldObject f = new FieldObject();
+        test("testObjectCompare", f, objectTestValue1);
+        test("testObjectCompareConstant1", f);
+        test("testObjectCompareConstant2", f);
+    }
+
+    @Test
+    public void testObjectNullCompares() {
+        test("testObjectCompare", null, objectTestValue1);
+    }
+
+    @Test
+    public void testObjectNullCompares1() {
+        test("testObjectCompareConstant1", (Object) null);
+    }
+
+    @Test
+    public void testObjectNullCompares2() {
+        test("testObjectCompareConstant2", (Object) null);
+    }
+
+    public static int testByteAdd(FieldObject f, byte byteValue) {
+        return f.byteValue + byteValue;
+    }
+
+    public static int testByteAddConstant1(FieldObject f) {
+        return f.byteValue + byteTestValue1;
+    }
+
+    public static int testByteAddConstant2(FieldObject f) {
+        return f.byteValue + byteTestValue2;
+    }
+
+    @Test
+    public void testByteAdds() {
+        FieldObject f = new FieldObject();
+        test("testByteAdd", f, byteTestValue1);
+        test("testByteAddConstant1", f);
+        test("testByteAddConstant2", f);
+    }
+
+    @Test
+    public void testByteNullAdd() {
+        test("testByteAdd", null, byteTestValue1);
+    }
+
+    public static int testShortAdd(FieldObject f, short shortValue) {
+        return f.shortValue + shortValue;
+    }
+
+    public static int testShortAddConstant1(FieldObject f) {
+        return f.shortValue + shortTestValue1;
+    }
+
+    public static int testShortAddConstant2(FieldObject f) {
+        return f.shortValue + shortTestValue2;
+    }
+
+    @Test
+    public void testShortAdds() {
+        FieldObject f = new FieldObject();
+        test("testShortAdd", f, shortTestValue1);
+        test("testShortAddConstant1", f);
+        test("testShortAddConstant2", f);
+    }
+
+    @Test
+    public void testShortNullAdd() {
+        test("testShortAdd", null, shortTestValue1);
+    }
+
+    public static int testCharAdd(FieldObject f, char charValue) {
+        return f.charValue + charValue;
+    }
+
+    public static int testCharAddConstant1(FieldObject f) {
+        return f.charValue + charTestValue1;
+    }
+
+    public static int testCharAddConstant2(FieldObject f) {
+        return f.charValue + charTestValue2;
+    }
+
+    @Test
+    public void testCharAdds() {
+        FieldObject f = new FieldObject();
+        test("testCharAdd", f, charTestValue1);
+        test("testCharAddConstant1", f);
+        test("testCharAddConstant2", f);
+    }
+
+    @Test
+    public void testCharNullAdd() {
+        test("testCharAdd", null, charTestValue1);
+    }
+
+    public static int testIntAdd(FieldObject f, int intValue) {
+        return f.intValue + intValue;
+    }
+
+    public static int testIntAddConstant1(FieldObject f) {
+        return f.intValue + intTestValue1;
+    }
+
+    public static int testIntAddConstant2(FieldObject f) {
+        return f.intValue + intTestValue2;
+    }
+
+    @Test
+    public void testIntAdds() {
+        FieldObject f = new FieldObject();
+        test("testIntAdd", f, intTestValue1);
+        test("testIntAddConstant1", f);
+        test("testIntAddConstant2", f);
+    }
+
+    @Test
+    public void testIntNullAdd() {
+        test("testIntAdd", null, intTestValue1);
+    }
+
+    public static long testLongAdd(FieldObject f, long longValue) {
+        return f.longValue + longValue;
+    }
+
+    public static long testLongAddConstant1(FieldObject f) {
+        return f.longValue + longTestValue1;
+    }
+
+    public static long testLongAddConstant2(FieldObject f) {
+        return f.longValue + longTestValue2;
+    }
+
+    @Test
+    public void testLongAdds() {
+        FieldObject f = new FieldObject();
+        test("testLongAdd", f, longTestValue1);
+        test("testLongAddConstant1", f);
+        test("testLongAddConstant2", f);
+    }
+
+    @Test
+    public void testLongNullAdd() {
+        test("testLongAdd", null, longTestValue1);
+    }
+
+    public static float testFloatAdd(FieldObject f, float floatValue) {
+        return f.floatValue + floatValue;
+    }
+
+    public static float testFloatAddConstant1(FieldObject f) {
+        return f.floatValue + floatTestValue1;
+    }
+
+    public static float testFloatAddConstant2(FieldObject f) {
+        return f.floatValue + floatTestValue2;
+    }
+
+    @Test
+    public void testFloatAdds() {
+        FieldObject f = new FieldObject();
+        test("testFloatAdd", f, floatTestValue1);
+        test("testFloatAddConstant1", f);
+        test("testFloatAddConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullAdd() {
+        test("testFloatAdd", null, floatTestValue1);
+    }
+
+    public static double testDoubleAdd(FieldObject f, double doubleValue) {
+        return f.doubleValue + doubleValue;
+    }
+
+    public static double testDoubleAddConstant1(FieldObject f) {
+        return f.doubleValue + doubleTestValue1;
+    }
+
+    public static double testDoubleAddConstant2(FieldObject f) {
+        return f.doubleValue + doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleAdds() {
+        FieldObject f = new FieldObject();
+        test("testDoubleAdd", f, doubleTestValue1);
+        test("testDoubleAddConstant1", f);
+        test("testDoubleAddConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullAdd() {
+        test("testDoubleAdd", null, doubleTestValue1);
+    }
+
+    public static int testByteSub(FieldObject f, byte byteValue) {
+        return f.byteValue - byteValue;
+    }
+
+    public static int testByteSubConstant1(FieldObject f) {
+        return f.byteValue - byteTestValue1;
+    }
+
+    public static int testByteSubConstant2(FieldObject f) {
+        return f.byteValue - byteTestValue2;
+    }
+
+    @Test
+    public void testByteSubs() {
+        FieldObject f = new FieldObject();
+        test("testByteSub", f, byteTestValue1);
+        test("testByteSubConstant1", f);
+        test("testByteSubConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSub() {
+        test("testByteSub", null, byteTestValue1);
+    }
+
+    public static int testShortSub(FieldObject f, short shortValue) {
+        return f.shortValue - shortValue;
+    }
+
+    public static int testShortSubConstant1(FieldObject f) {
+        return f.shortValue - shortTestValue1;
+    }
+
+    public static int testShortSubConstant2(FieldObject f) {
+        return f.shortValue - shortTestValue2;
+    }
+
+    @Test
+    public void testShortSubs() {
+        FieldObject f = new FieldObject();
+        test("testShortSub", f, shortTestValue1);
+        test("testShortSubConstant1", f);
+        test("testShortSubConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSub() {
+        test("testShortSub", null, shortTestValue1);
+    }
+
+    public static int testCharSub(FieldObject f, char charValue) {
+        return f.charValue - charValue;
+    }
+
+    public static int testCharSubConstant1(FieldObject f) {
+        return f.charValue - charTestValue1;
+    }
+
+    public static int testCharSubConstant2(FieldObject f) {
+        return f.charValue - charTestValue2;
+    }
+
+    @Test
+    public void testCharSubs() {
+        FieldObject f = new FieldObject();
+        test("testCharSub", f, charTestValue1);
+        test("testCharSubConstant1", f);
+        test("testCharSubConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSub() {
+        test("testCharSub", null, charTestValue1);
+    }
+
+    public static int testIntSub(FieldObject f, int intValue) {
+        return f.intValue - intValue;
+    }
+
+    public static int testIntSubConstant1(FieldObject f) {
+        return f.intValue - intTestValue1;
+    }
+
+    public static int testIntSubConstant2(FieldObject f) {
+        return f.intValue - intTestValue2;
+    }
+
+    @Test
+    public void testIntSubs() {
+        FieldObject f = new FieldObject();
+        test("testIntSub", f, intTestValue1);
+        test("testIntSubConstant1", f);
+        test("testIntSubConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSub() {
+        test("testIntSub", null, intTestValue1);
+    }
+
+    public static long testLongSub(FieldObject f, long longValue) {
+        return f.longValue - longValue;
+    }
+
+    public static long testLongSubConstant1(FieldObject f) {
+        return f.longValue - longTestValue1;
+    }
+
+    public static long testLongSubConstant2(FieldObject f) {
+        return f.longValue - longTestValue2;
+    }
+
+    @Test
+    public void testLongSubs() {
+        FieldObject f = new FieldObject();
+        test("testLongSub", f, longTestValue1);
+        test("testLongSubConstant1", f);
+        test("testLongSubConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSub() {
+        test("testLongSub", null, longTestValue1);
+    }
+
+    public static float testFloatSub(FieldObject f, float floatValue) {
+        return f.floatValue - floatValue;
+    }
+
+    public static float testFloatSubConstant1(FieldObject f) {
+        return f.floatValue - floatTestValue1;
+    }
+
+    public static float testFloatSubConstant2(FieldObject f) {
+        return f.floatValue - floatTestValue2;
+    }
+
+    @Test
+    public void testFloatSubs() {
+        FieldObject f = new FieldObject();
+        test("testFloatSub", f, floatTestValue1);
+        test("testFloatSubConstant1", f);
+        test("testFloatSubConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSub() {
+        test("testFloatSub", null, floatTestValue1);
+    }
+
+    public static double testDoubleSub(FieldObject f, double doubleValue) {
+        return f.doubleValue - doubleValue;
+    }
+
+    public static double testDoubleSubConstant1(FieldObject f) {
+        return f.doubleValue - doubleTestValue1;
+    }
+
+    public static double testDoubleSubConstant2(FieldObject f) {
+        return f.doubleValue - doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleSubs() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSub", f, doubleTestValue1);
+        test("testDoubleSubConstant1", f);
+        test("testDoubleSubConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSub() {
+        test("testDoubleSub", null, doubleTestValue1);
+    }
+
+    public static int testByteMul(FieldObject f, byte byteValue) {
+        return f.byteValue * byteValue;
+    }
+
+    public static int testByteMulConstant1(FieldObject f) {
+        return f.byteValue * byteTestValue1;
+    }
+
+    public static int testByteMulConstant2(FieldObject f) {
+        return f.byteValue * byteTestValue2;
+    }
+
+    @Test
+    public void testByteMuls() {
+        FieldObject f = new FieldObject();
+        test("testByteMul", f, byteTestValue1);
+        test("testByteMulConstant1", f);
+        test("testByteMulConstant2", f);
+    }
+
+    @Test
+    public void testByteNullMul() {
+        test("testByteMul", null, byteTestValue1);
+    }
+
+    public static int testShortMul(FieldObject f, short shortValue) {
+        return f.shortValue * shortValue;
+    }
+
+    public static int testShortMulConstant1(FieldObject f) {
+        return f.shortValue * shortTestValue1;
+    }
+
+    public static int testShortMulConstant2(FieldObject f) {
+        return f.shortValue * shortTestValue2;
+    }
+
+    @Test
+    public void testShortMuls() {
+        FieldObject f = new FieldObject();
+        test("testShortMul", f, shortTestValue1);
+        test("testShortMulConstant1", f);
+        test("testShortMulConstant2", f);
+    }
+
+    @Test
+    public void testShortNullMul() {
+        test("testShortMul", null, shortTestValue1);
+    }
+
+    public static int testCharMul(FieldObject f, char charValue) {
+        return f.charValue * charValue;
+    }
+
+    public static int testCharMulConstant1(FieldObject f) {
+        return f.charValue * charTestValue1;
+    }
+
+    public static int testCharMulConstant2(FieldObject f) {
+        return f.charValue * charTestValue2;
+    }
+
+    @Test
+    public void testCharMuls() {
+        FieldObject f = new FieldObject();
+        test("testCharMul", f, charTestValue1);
+        test("testCharMulConstant1", f);
+        test("testCharMulConstant2", f);
+    }
+
+    @Test
+    public void testCharNullMul() {
+        test("testCharMul", null, charTestValue1);
+    }
+
+    public static int testIntMul(FieldObject f, int intValue) {
+        return f.intValue * intValue;
+    }
+
+    public static int testIntMulConstant1(FieldObject f) {
+        return f.intValue * intTestValue1;
+    }
+
+    public static int testIntMulConstant2(FieldObject f) {
+        return f.intValue * intTestValue2;
+    }
+
+    @Test
+    public void testIntMuls() {
+        FieldObject f = new FieldObject();
+        test("testIntMul", f, intTestValue1);
+        test("testIntMulConstant1", f);
+        test("testIntMulConstant2", f);
+    }
+
+    @Test
+    public void testIntNullMul() {
+        test("testIntMul", null, intTestValue1);
+    }
+
+    public static long testLongMul(FieldObject f, long longValue) {
+        return f.longValue * longValue;
+    }
+
+    public static long testLongMulConstant1(FieldObject f) {
+        return f.longValue * longTestValue1;
+    }
+
+    public static long testLongMulConstant2(FieldObject f) {
+        return f.longValue * longTestValue2;
+    }
+
+    @Test
+    public void testLongMuls() {
+        FieldObject f = new FieldObject();
+        test("testLongMul", f, longTestValue1);
+        test("testLongMulConstant1", f);
+        test("testLongMulConstant2", f);
+    }
+
+    @Test
+    public void testLongNullMul() {
+        test("testLongMul", null, longTestValue1);
+    }
+
+    public static float testFloatMul(FieldObject f, float floatValue) {
+        return f.floatValue * floatValue;
+    }
+
+    public static float testFloatMulConstant1(FieldObject f) {
+        return f.floatValue * floatTestValue1;
+    }
+
+    public static float testFloatMulConstant2(FieldObject f) {
+        return f.floatValue * floatTestValue2;
+    }
+
+    @Test
+    public void testFloatMuls() {
+        FieldObject f = new FieldObject();
+        test("testFloatMul", f, floatTestValue1);
+        test("testFloatMulConstant1", f);
+        test("testFloatMulConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullMul() {
+        test("testFloatMul", null, floatTestValue1);
+    }
+
+    public static double testDoubleMul(FieldObject f, double doubleValue) {
+        return f.doubleValue * doubleValue;
+    }
+
+    public static double testDoubleMulConstant1(FieldObject f) {
+        return f.doubleValue * doubleTestValue1;
+    }
+
+    public static double testDoubleMulConstant2(FieldObject f) {
+        return f.doubleValue * doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleMuls() {
+        FieldObject f = new FieldObject();
+        test("testDoubleMul", f, doubleTestValue1);
+        test("testDoubleMulConstant1", f);
+        test("testDoubleMulConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullMul() {
+        test("testDoubleMul", null, doubleTestValue1);
+    }
+
+    public static int testByteDiv(FieldObject f, byte byteValue) {
+        return f.byteValue / byteValue;
+    }
+
+    public static int testByteDivConstant1(FieldObject f) {
+        return f.byteValue / byteTestValue1;
+    }
+
+    public static int testByteDivConstant2(FieldObject f) {
+        return f.byteValue / byteTestValue2;
+    }
+
+    @Test
+    public void testByteDivs() {
+        FieldObject f = new FieldObject();
+        test("testByteDiv", f, byteTestValue1);
+        test("testByteDivConstant1", f);
+        test("testByteDivConstant2", f);
+    }
+
+    @Test
+    public void testByteNullDiv() {
+        test("testByteDiv", null, byteTestValue1);
+    }
+
+    public static int testShortDiv(FieldObject f, short shortValue) {
+        return f.shortValue / shortValue;
+    }
+
+    public static int testShortDivConstant1(FieldObject f) {
+        return f.shortValue / shortTestValue1;
+    }
+
+    public static int testShortDivConstant2(FieldObject f) {
+        return f.shortValue / shortTestValue2;
+    }
+
+    @Test
+    public void testShortDivs() {
+        FieldObject f = new FieldObject();
+        test("testShortDiv", f, shortTestValue1);
+        test("testShortDivConstant1", f);
+        test("testShortDivConstant2", f);
+    }
+
+    @Test
+    public void testShortNullDiv() {
+        test("testShortDiv", null, shortTestValue1);
+    }
+
+    public static int testCharDiv(FieldObject f, char charValue) {
+        return f.charValue / charValue;
+    }
+
+    public static int testCharDivConstant1(FieldObject f) {
+        return f.charValue / charTestValue1;
+    }
+
+    public static int testCharDivConstant2(FieldObject f) {
+        return f.charValue / charTestValue2;
+    }
+
+    @Test
+    public void testCharDivs() {
+        FieldObject f = new FieldObject();
+        test("testCharDiv", f, charTestValue1);
+        test("testCharDivConstant1", f);
+        test("testCharDivConstant2", f);
+    }
+
+    @Test
+    public void testCharNullDiv() {
+        test("testCharDiv", null, charTestValue1);
+    }
+
+    public static int testIntDiv(FieldObject f, int intValue) {
+        return f.intValue / intValue;
+    }
+
+    public static int testIntDivConstant1(FieldObject f) {
+        return f.intValue / intTestValue1;
+    }
+
+    public static int testIntDivConstant2(FieldObject f) {
+        return f.intValue / intTestValue2;
+    }
+
+    @Test
+    public void testIntDivs() {
+        FieldObject f = new FieldObject();
+        test("testIntDiv", f, intTestValue1);
+        test("testIntDivConstant1", f);
+        test("testIntDivConstant2", f);
+    }
+
+    @Test
+    public void testIntNullDiv() {
+        test("testIntDiv", null, intTestValue1);
+    }
+
+    public static long testLongDiv(FieldObject f, long longValue) {
+        return f.longValue / longValue;
+    }
+
+    public static long testLongDivConstant1(FieldObject f) {
+        return f.longValue / longTestValue1;
+    }
+
+    public static long testLongDivConstant2(FieldObject f) {
+        return f.longValue / longTestValue2;
+    }
+
+    @Test
+    public void testLongDivs() {
+        FieldObject f = new FieldObject();
+        test("testLongDiv", f, longTestValue1);
+        test("testLongDivConstant1", f);
+        test("testLongDivConstant2", f);
+    }
+
+    @Test
+    public void testLongNullDiv() {
+        test("testLongDiv", null, longTestValue1);
+    }
+
+    public static float testFloatDiv(FieldObject f, float floatValue) {
+        return f.floatValue / floatValue;
+    }
+
+    public static float testFloatDivConstant1(FieldObject f) {
+        return f.floatValue / floatTestValue1;
+    }
+
+    public static float testFloatDivConstant2(FieldObject f) {
+        return f.floatValue / floatTestValue2;
+    }
+
+    @Test
+    public void testFloatDivs() {
+        FieldObject f = new FieldObject();
+        test("testFloatDiv", f, floatTestValue1);
+        test("testFloatDivConstant1", f);
+        test("testFloatDivConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullDiv() {
+        test("testFloatDiv", null, floatTestValue1);
+    }
+
+    public static double testDoubleDiv(FieldObject f, double doubleValue) {
+        return f.doubleValue / doubleValue;
+    }
+
+    public static double testDoubleDivConstant1(FieldObject f) {
+        return f.doubleValue / doubleTestValue1;
+    }
+
+    public static double testDoubleDivConstant2(FieldObject f) {
+        return f.doubleValue / doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleDivs() {
+        FieldObject f = new FieldObject();
+        test("testDoubleDiv", f, doubleTestValue1);
+        test("testDoubleDivConstant1", f);
+        test("testDoubleDivConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullDiv() {
+        test("testDoubleDiv", null, doubleTestValue1);
+    }
+
+    public static int testByteOr(FieldObject f, byte byteValue) {
+        return f.byteValue | byteValue;
+    }
+
+    public static int testByteOrConstant1(FieldObject f) {
+        return f.byteValue | byteTestValue1;
+    }
+
+    public static int testByteOrConstant2(FieldObject f) {
+        return f.byteValue | byteTestValue2;
+    }
+
+    @Test
+    public void testByteOrs() {
+        FieldObject f = new FieldObject();
+        test("testByteOr", f, byteTestValue1);
+        test("testByteOrConstant1", f);
+        test("testByteOrConstant2", f);
+    }
+
+    @Test
+    public void testByteNullOr() {
+        test("testByteOr", null, byteTestValue1);
+    }
+
+    public static int testShortOr(FieldObject f, short shortValue) {
+        return f.shortValue | shortValue;
+    }
+
+    public static int testShortOrConstant1(FieldObject f) {
+        return f.shortValue | shortTestValue1;
+    }
+
+    public static int testShortOrConstant2(FieldObject f) {
+        return f.shortValue | shortTestValue2;
+    }
+
+    @Test
+    public void testShortOrs() {
+        FieldObject f = new FieldObject();
+        test("testShortOr", f, shortTestValue1);
+        test("testShortOrConstant1", f);
+        test("testShortOrConstant2", f);
+    }
+
+    @Test
+    public void testShortNullOr() {
+        test("testShortOr", null, shortTestValue1);
+    }
+
+    public static int testCharOr(FieldObject f, char charValue) {
+        return f.charValue | charValue;
+    }
+
+    public static int testCharOrConstant1(FieldObject f) {
+        return f.charValue | charTestValue1;
+    }
+
+    public static int testCharOrConstant2(FieldObject f) {
+        return f.charValue | charTestValue2;
+    }
+
+    @Test
+    public void testCharOrs() {
+        FieldObject f = new FieldObject();
+        test("testCharOr", f, charTestValue1);
+        test("testCharOrConstant1", f);
+        test("testCharOrConstant2", f);
+    }
+
+    @Test
+    public void testCharNullOr() {
+        test("testCharOr", null, charTestValue1);
+    }
+
+    public static int testIntOr(FieldObject f, int intValue) {
+        return f.intValue | intValue;
+    }
+
+    public static int testIntOrConstant1(FieldObject f) {
+        return f.intValue | intTestValue1;
+    }
+
+    public static int testIntOrConstant2(FieldObject f) {
+        return f.intValue | intTestValue2;
+    }
+
+    @Test
+    public void testIntOrs() {
+        FieldObject f = new FieldObject();
+        test("testIntOr", f, intTestValue1);
+        test("testIntOrConstant1", f);
+        test("testIntOrConstant2", f);
+    }
+
+    @Test
+    public void testIntNullOr() {
+        test("testIntOr", null, intTestValue1);
+    }
+
+    public static long testLongOr(FieldObject f, long longValue) {
+        return f.longValue | longValue;
+    }
+
+    public static long testLongOrConstant1(FieldObject f) {
+        return f.longValue | longTestValue1;
+    }
+
+    public static long testLongOrConstant2(FieldObject f) {
+        return f.longValue | longTestValue2;
+    }
+
+    @Test
+    public void testLongOrs() {
+        FieldObject f = new FieldObject();
+        test("testLongOr", f, longTestValue1);
+        test("testLongOrConstant1", f);
+        test("testLongOrConstant2", f);
+    }
+
+    @Test
+    public void testLongNullOr() {
+        test("testLongOr", null, longTestValue1);
+    }
+
+    public static int testByteXor(FieldObject f, byte byteValue) {
+        return f.byteValue ^ byteValue;
+    }
+
+    public static int testByteXorConstant1(FieldObject f) {
+        return f.byteValue ^ byteTestValue1;
+    }
+
+    public static int testByteXorConstant2(FieldObject f) {
+        return f.byteValue ^ byteTestValue2;
+    }
+
+    @Test
+    public void testByteXors() {
+        FieldObject f = new FieldObject();
+        test("testByteXor", f, byteTestValue1);
+        test("testByteXorConstant1", f);
+        test("testByteXorConstant2", f);
+    }
+
+    @Test
+    public void testByteNullXor() {
+        test("testByteXor", null, byteTestValue1);
+    }
+
+    public static int testShortXor(FieldObject f, short shortValue) {
+        return f.shortValue ^ shortValue;
+    }
+
+    public static int testShortXorConstant1(FieldObject f) {
+        return f.shortValue ^ shortTestValue1;
+    }
+
+    public static int testShortXorConstant2(FieldObject f) {
+        return f.shortValue ^ shortTestValue2;
+    }
+
+    @Test
+    public void testShortXors() {
+        FieldObject f = new FieldObject();
+        test("testShortXor", f, shortTestValue1);
+        test("testShortXorConstant1", f);
+        test("testShortXorConstant2", f);
+    }
+
+    @Test
+    public void testShortNullXor() {
+        test("testShortXor", null, shortTestValue1);
+    }
+
+    public static int testCharXor(FieldObject f, char charValue) {
+        return f.charValue ^ charValue;
+    }
+
+    public static int testCharXorConstant1(FieldObject f) {
+        return f.charValue ^ charTestValue1;
+    }
+
+    public static int testCharXorConstant2(FieldObject f) {
+        return f.charValue ^ charTestValue2;
+    }
+
+    @Test
+    public void testCharXors() {
+        FieldObject f = new FieldObject();
+        test("testCharXor", f, charTestValue1);
+        test("testCharXorConstant1", f);
+        test("testCharXorConstant2", f);
+    }
+
+    @Test
+    public void testCharNullXor() {
+        test("testCharXor", null, charTestValue1);
+    }
+
+    public static int testIntXor(FieldObject f, int intValue) {
+        return f.intValue ^ intValue;
+    }
+
+    public static int testIntXorConstant1(FieldObject f) {
+        return f.intValue ^ intTestValue1;
+    }
+
+    public static int testIntXorConstant2(FieldObject f) {
+        return f.intValue ^ intTestValue2;
+    }
+
+    @Test
+    public void testIntXors() {
+        FieldObject f = new FieldObject();
+        test("testIntXor", f, intTestValue1);
+        test("testIntXorConstant1", f);
+        test("testIntXorConstant2", f);
+    }
+
+    @Test
+    public void testIntNullXor() {
+        test("testIntXor", null, intTestValue1);
+    }
+
+    public static long testLongXor(FieldObject f, long longValue) {
+        return f.longValue ^ longValue;
+    }
+
+    public static long testLongXorConstant1(FieldObject f) {
+        return f.longValue ^ longTestValue1;
+    }
+
+    public static long testLongXorConstant2(FieldObject f) {
+        return f.longValue ^ longTestValue2;
+    }
+
+    @Test
+    public void testLongXors() {
+        FieldObject f = new FieldObject();
+        test("testLongXor", f, longTestValue1);
+        test("testLongXorConstant1", f);
+        test("testLongXorConstant2", f);
+    }
+
+    @Test
+    public void testLongNullXor() {
+        test("testLongXor", null, longTestValue1);
+    }
+
+    public static int testByteAnd(FieldObject f, byte byteValue) {
+        return f.byteValue & byteValue;
+    }
+
+    public static int testByteAndConstant1(FieldObject f) {
+        return f.byteValue & byteTestValue1;
+    }
+
+    public static int testByteAndConstant2(FieldObject f) {
+        return f.byteValue & byteTestValue2;
+    }
+
+    @Test
+    public void testByteAnds() {
+        FieldObject f = new FieldObject();
+        test("testByteAnd", f, byteTestValue1);
+        test("testByteAndConstant1", f);
+        test("testByteAndConstant2", f);
+    }
+
+    @Test
+    public void testByteNullAnd() {
+        test("testByteAnd", null, byteTestValue1);
+    }
+
+    public static int testShortAnd(FieldObject f, short shortValue) {
+        return f.shortValue & shortValue;
+    }
+
+    public static int testShortAndConstant1(FieldObject f) {
+        return f.shortValue & shortTestValue1;
+    }
+
+    public static int testShortAndConstant2(FieldObject f) {
+        return f.shortValue & shortTestValue2;
+    }
+
+    @Test
+    public void testShortAnds() {
+        FieldObject f = new FieldObject();
+        test("testShortAnd", f, shortTestValue1);
+        test("testShortAndConstant1", f);
+        test("testShortAndConstant2", f);
+    }
+
+    @Test
+    public void testShortNullAnd() {
+        test("testShortAnd", null, shortTestValue1);
+    }
+
+    public static int testCharAnd(FieldObject f, char charValue) {
+        return f.charValue & charValue;
+    }
+
+    public static int testCharAndConstant1(FieldObject f) {
+        return f.charValue & charTestValue1;
+    }
+
+    public static int testCharAndConstant2(FieldObject f) {
+        return f.charValue & charTestValue2;
+    }
+
+    @Test
+    public void testCharAnds() {
+        FieldObject f = new FieldObject();
+        test("testCharAnd", f, charTestValue1);
+        test("testCharAndConstant1", f);
+        test("testCharAndConstant2", f);
+    }
+
+    @Test
+    public void testCharNullAnd() {
+        test("testCharAnd", null, charTestValue1);
+    }
+
+    public static int testIntAnd(FieldObject f, int intValue) {
+        return f.intValue & intValue;
+    }
+
+    public static int testIntAndConstant1(FieldObject f) {
+        return f.intValue & intTestValue1;
+    }
+
+    public static int testIntAndConstant2(FieldObject f) {
+        return f.intValue & intTestValue2;
+    }
+
+    @Test
+    public void testIntAnds() {
+        FieldObject f = new FieldObject();
+        test("testIntAnd", f, intTestValue1);
+        test("testIntAndConstant1", f);
+        test("testIntAndConstant2", f);
+    }
+
+    @Test
+    public void testIntNullAnd() {
+        test("testIntAnd", null, intTestValue1);
+    }
+
+    public static long testLongAnd(FieldObject f, long longValue) {
+        return f.longValue & longValue;
+    }
+
+    public static long testLongAndConstant1(FieldObject f) {
+        return f.longValue & longTestValue1;
+    }
+
+    public static long testLongAndConstant2(FieldObject f) {
+        return f.longValue & longTestValue2;
+    }
+
+    @Test
+    public void testLongAnds() {
+        FieldObject f = new FieldObject();
+        test("testLongAnd", f, longTestValue1);
+        test("testLongAndConstant1", f);
+        test("testLongAndConstant2", f);
+    }
+
+    @Test
+    public void testLongNullAnd() {
+        test("testLongAnd", null, longTestValue1);
+    }
+
+    public static boolean testIntMask(FieldObject f, int intValue) {
+        if ((f.intValue & intValue) != 0) {
+            count++;
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean testIntMaskConstant1(FieldObject f) {
+        return (f.intValue & intTestValue1) != 0;
+    }
+
+    public static boolean testIntMaskConstant2(FieldObject f) {
+        return (f.intValue & intTestValue2) != 0;
+    }
+
+    @Test
+    public void testIntMasks() {
+        FieldObject f = new FieldObject();
+        test("testIntMask", f, intTestValue1);
+        test("testIntMaskConstant1", f);
+        test("testIntMaskConstant2", f);
+    }
+
+    @Test
+    public void testIntNullMask() {
+        test("testIntMask", null, intTestValue1);
+    }
+
+    public static boolean testLongMask(FieldObject f, long longValue) {
+        if ((f.longValue & longValue) != 0) {
+            count++;
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean testLongMaskConstant1(FieldObject f) {
+        return (f.longValue & longTestValue1) != 0;
+    }
+
+    public static boolean testLongMaskConstant2(FieldObject f) {
+        return (f.longValue & longTestValue2) != 0;
+    }
+
+    @Test
+    public void testLongMasks() {
+        FieldObject f = new FieldObject();
+        test("testLongMask", f, longTestValue1);
+        test("testLongMaskConstant1", f);
+        test("testLongMaskConstant2", f);
+    }
+
+    @Test
+    public void testLongNullMask() {
+        test("testLongMask", null, longTestValue1);
+    }
+
+    public static int doConvertByteInt(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteInt() {
+        test("doConvertByteInt", maxObject);
+        test("doConvertByteInt", (FieldObject) null);
+    }
+
+    public static int doConvertShortInt(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortInt() {
+        test("doConvertShortInt", maxObject);
+        test("doConvertShortInt", (FieldObject) null);
+    }
+
+    public static int doConvertCharInt(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharInt() {
+        test("doConvertCharInt", maxObject);
+        test("doConvertCharInt", (FieldObject) null);
+    }
+
+    public static int doConvertLongInt(FieldObject f) {
+        return (int) f.longValue;
+    }
+
+    @Test
+    public void testConvertLongInt() {
+        test("doConvertLongInt", maxObject);
+        test("doConvertLongInt", (FieldObject) null);
+    }
+
+    public static int doConvertFloatInt(FieldObject f) {
+        return (int) f.floatValue;
+    }
+
+    @Test
+    public void testConvertFloatInt() {
+        test("doConvertFloatInt", maxObject);
+        test("doConvertFloatInt", (FieldObject) null);
+    }
+
+    public static int doConvertDoubleInt(FieldObject f) {
+        return (int) f.doubleValue;
+    }
+
+    @Test
+    public void testConvertDoubleInt() {
+        test("doConvertDoubleInt", maxObject);
+        test("doConvertDoubleInt", (FieldObject) null);
+    }
+
+    public static long doConvertByteLong(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteLong() {
+        test("doConvertByteLong", maxObject);
+        test("doConvertByteLong", (FieldObject) null);
+    }
+
+    public static long doConvertShortLong(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortLong() {
+        test("doConvertShortLong", maxObject);
+        test("doConvertShortLong", (FieldObject) null);
+    }
+
+    public static long doConvertCharLong(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharLong() {
+        test("doConvertCharLong", maxObject);
+        test("doConvertCharLong", (FieldObject) null);
+    }
+
+    public static long doConvertIntLong(FieldObject f) {
+        return f.intValue;
+    }
+
+    @Test
+    public void testConvertIntLong() {
+        test("doConvertIntLong", maxObject);
+        test("doConvertIntLong", (FieldObject) null);
+    }
+
+    public static long doConvertFloatLong(FieldObject f) {
+        return (long) f.floatValue;
+    }
+
+    @Test
+    public void testConvertFloatLong() {
+        test("doConvertFloatLong", maxObject);
+        test("doConvertFloatLong", (FieldObject) null);
+    }
+
+    public static long doConvertDoubleLong(FieldObject f) {
+        return (long) f.doubleValue;
+    }
+
+    @Test
+    public void testConvertDoubleLong() {
+        test("doConvertDoubleLong", maxObject);
+        test("doConvertDoubleLong", (FieldObject) null);
+    }
+
+    public static float doConvertByteFloat(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteFloat() {
+        test("doConvertByteFloat", maxObject);
+        test("doConvertByteFloat", (FieldObject) null);
+    }
+
+    public static float doConvertShortFloat(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortFloat() {
+        test("doConvertShortFloat", maxObject);
+        test("doConvertShortFloat", (FieldObject) null);
+    }
+
+    public static float doConvertCharFloat(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharFloat() {
+        test("doConvertCharFloat", maxObject);
+        test("doConvertCharFloat", (FieldObject) null);
+    }
+
+    public static float doConvertIntFloat(FieldObject f) {
+        return f.intValue;
+    }
+
+    @Test
+    public void testConvertIntFloat() {
+        test("doConvertIntFloat", maxObject);
+        test("doConvertIntFloat", (FieldObject) null);
+    }
+
+    public static float doConvertLongFloat(FieldObject f) {
+        return f.longValue;
+    }
+
+    @Test
+    public void testConvertLongFloat() {
+        test("doConvertLongFloat", maxObject);
+        test("doConvertLongFloat", (FieldObject) null);
+    }
+
+    public static float doConvertDoubleFloat(FieldObject f) {
+        return (float) f.doubleValue;
+    }
+
+    @Test
+    public void testConvertDoubleFloat() {
+        test("doConvertDoubleFloat", maxObject);
+        test("doConvertDoubleFloat", (FieldObject) null);
+    }
+
+    public static double doConvertByteDouble(FieldObject f) {
+        return f.byteValue;
+    }
+
+    @Test
+    public void testConvertByteDouble() {
+        test("doConvertByteDouble", maxObject);
+        test("doConvertByteDouble", (FieldObject) null);
+    }
+
+    public static double doConvertShortDouble(FieldObject f) {
+        return f.shortValue;
+    }
+
+    @Test
+    public void testConvertShortDouble() {
+        test("doConvertShortDouble", maxObject);
+        test("doConvertShortDouble", (FieldObject) null);
+    }
+
+    public static double doConvertCharDouble(FieldObject f) {
+        return f.charValue;
+    }
+
+    @Test
+    public void testConvertCharDouble() {
+        test("doConvertCharDouble", maxObject);
+        test("doConvertCharDouble", (FieldObject) null);
+    }
+
+    public static double doConvertIntDouble(FieldObject f) {
+        return f.intValue;
+    }
+
+    @Test
+    public void testConvertIntDouble() {
+        test("doConvertIntDouble", maxObject);
+        test("doConvertIntDouble", (FieldObject) null);
+    }
+
+    public static double doConvertLongDouble(FieldObject f) {
+        return f.longValue;
+    }
+
+    @Test
+    public void testConvertLongDouble() {
+        test("doConvertLongDouble", maxObject);
+        test("doConvertLongDouble", (FieldObject) null);
+    }
+
+    public static double doConvertFloatDouble(FieldObject f) {
+        return f.floatValue;
+    }
+
+    @Test
+    public void testConvertFloatDouble() {
+        test("doConvertFloatDouble", maxObject);
+        test("doConvertFloatDouble", (FieldObject) null);
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -73,8 +73,8 @@
         public RegisterStats(LIR lir) {
             this.lir = lir;
 
-            for (Block block : lir.codeEmittingOrder()) {
-                for (LIRInstruction instr : lir.lir(block)) {
+            for (AbstractBlock<?> block : lir.codeEmittingOrder()) {
+                for (LIRInstruction instr : lir.getLIRforBlock(block)) {
                     collectStats(instr);
                 }
             }
@@ -120,7 +120,7 @@
         }
 
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        LIRGenerator lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc);
-        return new RegisterStats(lirGen.lir);
+        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc);
+        return new RegisterStats(lirGen.getLIR());
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -59,7 +59,7 @@
         new DeadCodeEliminationPhase().apply(graph);
 
         for (ConstantNode node : ConstantNode.getConstantNodes(graph)) {
-            if (node.kind() == Kind.Object && " ".equals(node.getValue().asObject())) {
+            if (node.getKind() == Kind.Object && " ".equals(node.getValue().asObject())) {
                 node.replace(graph, ConstantNode.forObject("-", getMetaAccess(), graph));
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package com.oracle.graal.compiler.test.deopt;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+
+public final class MonitorDeoptTest extends GraalCompilerTest {
+
+    private enum State {
+        INITIAL, RUNNING_GRAAL, INVALIDATED, RUNNING_INTERPRETER, TERMINATED
+    }
+
+    private static class Monitor {
+        private volatile State state = State.INITIAL;
+
+        public synchronized void setState(State newState) {
+            state = newState;
+            notifyAll();
+        }
+
+        public synchronized boolean tryUpdateState(State oldState, State newState) {
+            if (state == oldState) {
+                state = newState;
+                notifyAll();
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        public synchronized void waitState(State targetState) throws InterruptedException {
+            while (state != targetState) {
+                wait();
+            }
+        }
+
+        public synchronized State getState() {
+            return state;
+        }
+
+        public synchronized void invalidate(InstalledCode code) {
+            state = State.INVALIDATED;
+            code.invalidate();
+        }
+    }
+
+    public static boolean test(Monitor monitor) {
+        // initially, we're running as Graal compiled code
+        monitor.setState(State.RUNNING_GRAAL);
+
+        for (;;) {
+            // wait for the compiled code to be invalidated
+            if (monitor.tryUpdateState(State.INVALIDATED, State.RUNNING_INTERPRETER)) {
+                break;
+            }
+        }
+
+        for (int i = 0; i < 500; i++) {
+            // wait for the control thread to send the TERMINATED signal
+            if (monitor.getState() == State.TERMINATED) {
+                return true;
+            }
+
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException e) {
+            }
+        }
+
+        // we're running for more than 5 s in the interpreter
+        // probably the control thread is deadlocked
+        return false;
+    }
+
+    private static LoopBeginNode findFirstLoop(StructuredGraph graph) {
+        FixedNode node = graph.start();
+        for (;;) {
+            if (node instanceof LoopBeginNode) {
+                return (LoopBeginNode) node;
+            } else if (node instanceof FixedWithNextNode) {
+                node = ((FixedWithNextNode) node).next();
+            } else if (node instanceof AbstractEndNode) {
+                node = ((AbstractEndNode) node).merge();
+            } else {
+                Assert.fail(String.format("unexpected node %s in graph of test method", node));
+            }
+        }
+    }
+
+    /**
+     * Remove the safepoint from the first loop in the test method, so only the safepoints on
+     * MonitorEnter and MonitorExit remain in the loop. That way, we can make sure it deopts inside
+     * the MonitorEnter by invalidating the code while holding the lock.
+     */
+    private static void removeLoopSafepoint(StructuredGraph graph) {
+        LoopBeginNode loopBegin = findFirstLoop(graph);
+        for (LoopEndNode end : loopBegin.loopEnds()) {
+            end.disableSafepoint();
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        Method method = getMethod("test");
+
+        StructuredGraph graph = parse(method);
+        removeLoopSafepoint(graph);
+
+        ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method);
+        CompilationResult compilationResult = compile(javaMethod, graph);
+        final InstalledCode installedCode = getProviders().getCodeCache().setDefaultMethod(javaMethod, compilationResult);
+
+        final Monitor monitor = new Monitor();
+
+        Thread controlThread = new Thread(new Runnable() {
+
+            public void run() {
+                try {
+                    // wait for the main thread to start
+                    monitor.waitState(State.RUNNING_GRAAL);
+
+                    // invalidate the compiled code while holding the lock
+                    // at this point, the compiled method hangs in a MonitorEnter
+                    monitor.invalidate(installedCode);
+
+                    // wait for the main thread to continue running in the interpreter
+                    monitor.waitState(State.RUNNING_INTERPRETER);
+
+                    // terminate the main thread
+                    monitor.setState(State.TERMINATED);
+                } catch (InterruptedException e) {
+                }
+            }
+        });
+
+        controlThread.start();
+
+        boolean result = test(monitor);
+        Assert.assertTrue(result);
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -149,7 +149,7 @@
     protected void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) {
         ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet));
         graph = new StructuredGraph(method);
-        try (Scope s = Debug.scope(getClass().getSimpleName(), graph, method, getCodeCache())) {
+        try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
             new GraphBuilderPhase.Instance(getMetaAccess(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
             Assumptions assumptions = new Assumptions(false);
             context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test.ea;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+/**
+ * Tests {@link AbstractNewObjectNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)}.
+ * 
+ */
+public class PoorMansEATest extends GraalCompilerTest {
+    public static class A {
+        public A obj;
+    }
+
+    public static A test1Snippet() {
+        A a = new A();
+        a.obj = a;
+        return null;
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet");
+    }
+
+    private void test(final String snippet) {
+        try (Scope s = Debug.scope("PoorMansEATest", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = parse(snippet);
+            Assumptions assumptions = new Assumptions(false);
+            HighTierContext highTierContext = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+            new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
+            PhaseContext context = new PhaseContext(getProviders(), assumptions);
+            new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+
+            // remove framestates in order to trigger the simplification.
+            cleanup: for (FrameState fs : graph.getNodes(FrameState.class).snapshot()) {
+                for (Node input : fs.inputs()) {
+                    if (input instanceof NewInstanceNode) {
+                        fs.replaceAtUsages(null);
+                        fs.safeDelete();
+                        continue cleanup;
+                    }
+                }
+            }
+            new CanonicalizerPhase(true).apply(graph, context);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThread.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle 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;
+
+import com.oracle.graal.compiler.CompilerThreadFactory.*;
+import com.oracle.graal.debug.*;
+
+/**
+ * A compiler thread is a daemon thread that runs at {@link Thread#MAX_PRIORITY} and executes in the
+ * context of a thread-local {@linkplain GraalDebugConfig debug configuration}.
+ */
+public class CompilerThread extends Thread {
+
+    private final DebugConfigAccess debugConfigAccess;
+
+    public CompilerThread(Runnable r, String namePrefix, DebugConfigAccess debugConfigAccess) {
+        super(r);
+        this.setName(namePrefix + "-" + this.getId());
+        this.setPriority(Thread.MAX_PRIORITY);
+        this.setDaemon(true);
+        this.debugConfigAccess = debugConfigAccess;
+    }
+
+    @Override
+    public void run() {
+        GraalDebugConfig debugConfig = debugConfigAccess.getDebugConfig();
+        try {
+            super.run();
+        } finally {
+            if (debugConfig != null) {
+                for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) {
+                    try {
+                        dumpHandler.close();
+                    } catch (Throwable t) {
+                    }
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThreadFactory.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThreadFactory.java	Sun Mar 30 16:08:33 2014 +0200
@@ -53,38 +53,4 @@
     public Thread newThread(Runnable r) {
         return new CompilerThread(r, threadNamePrefix, debugConfigAccess);
     }
-
-    /**
-     * A compiler thread is a daemon thread that runs at {@link Thread#MAX_PRIORITY} and executes in
-     * the context of a thread-local {@linkplain GraalDebugConfig debug configuration}.
-     */
-    public static class CompilerThread extends Thread {
-
-        private final DebugConfigAccess debugConfigAccess;
-
-        public CompilerThread(Runnable r, String namePrefix, DebugConfigAccess debugConfigAccess) {
-            super(r);
-            this.setName(namePrefix + "-" + this.getId());
-            this.setPriority(Thread.MAX_PRIORITY);
-            this.setDaemon(true);
-            this.debugConfigAccess = debugConfigAccess;
-        }
-
-        @Override
-        public void run() {
-            GraalDebugConfig debugConfig = debugConfigAccess.getDebugConfig();
-            try {
-                super.run();
-            } finally {
-                if (debugConfig != null) {
-                    for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) {
-                        try {
-                            dumpHandler.close();
-                        } catch (Throwable t) {
-                        }
-                    }
-                }
-            }
-        }
-    }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -145,10 +145,10 @@
                 throw Debug.handle(e);
             }
             try (TimerCloseable a = BackEnd.start()) {
-                LIRGenerator lirGen = null;
-                lirGen = emitLIR(backend, target, schedule, graph, stub, cc);
-                try (Scope s = Debug.scope("CodeGen", lirGen)) {
-                    emitCode(backend, assumptions, lirGen, compilationResult, installedCodeOwner, factory);
+                LIRGenerationResult lirGenRes = null;
+                lirGenRes = emitLIR(backend, target, schedule, graph, stub, cc);
+                try (Scope s = Debug.scope("CodeGen", lirGenRes)) {
+                    emitCode(backend, assumptions, lirGenRes, compilationResult, installedCodeOwner, factory);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
@@ -205,30 +205,32 @@
 
     }
 
-    private static void emitBlock(LIRGenerator lirGen, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
-        if (lirGen.lir.lir(b) == null) {
+    private static void emitBlock(NodeLIRGenerator nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
+        if (lirGenRes.getLIR().getLIRforBlock(b) == null) {
             for (Block pred : b.getPredecessors()) {
                 if (!b.isLoopHeader() || !pred.isLoopEnd()) {
-                    emitBlock(lirGen, pred, graph, blockMap);
+                    emitBlock(nodeLirGen, lirGenRes, pred, graph, blockMap);
                 }
             }
-            lirGen.doBlock(b, graph, blockMap);
+            nodeLirGen.doBlock(b, graph, blockMap);
         }
     }
 
-    public static LIRGenerator emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc) {
+    public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc) {
         Block[] blocks = schedule.getCFG().getBlocks();
         Block startBlock = schedule.getCFG().getStartBlock();
         assert startBlock != null;
         assert startBlock.getPredecessorCount() == 0;
 
         LIR lir = null;
+        List<Block> codeEmittingOrder = null;
+        List<Block> linearScanOrder = null;
         try (Scope ds = Debug.scope("MidEnd")) {
             try (Scope s = Debug.scope("ComputeLinearScanOrder")) {
                 NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
-                System.out.printf("%d, %d\n", nodeProbabilities.getCount(), graph.getNodeCount());
-                List<Block> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, nodeProbabilities);
-                List<Block> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, nodeProbabilities);
+                BlocksToDoubles blockProbabilities = BlocksToDoubles.createFromNodeProbability(nodeProbabilities, schedule.getCFG());
+                codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, blockProbabilities);
+                linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, blockProbabilities);
 
                 lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder);
                 Debug.dump(lir, "After linear scan order");
@@ -240,11 +242,13 @@
         }
         try (Scope ds = Debug.scope("BackEnd", lir)) {
             FrameMap frameMap = backend.newFrameMap();
-            LIRGenerator lirGen = backend.newLIRGenerator(graph, stub, frameMap, cc, lir);
+            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMap, stub);
+            LIRGenerator lirGen = backend.newLIRGenerator(cc, lirGenRes);
+            NodeLIRGenerator nodeLirGen = backend.newNodeLIRGenerator(graph, lirGenRes, lirGen);
 
             try (Scope s = Debug.scope("LIRGen", lirGen)) {
-                for (Block b : lir.linearScanOrder()) {
-                    emitBlock(lirGen, b, graph, schedule.getBlockToNodesMap());
+                for (Block b : linearScanOrder) {
+                    emitBlock(nodeLirGen, lirGenRes, b, graph, schedule.getBlockToNodesMap());
                 }
                 lirGen.beforeRegisterAllocation();
 
@@ -253,7 +257,7 @@
                 throw Debug.handle(e);
             }
 
-            try (Scope s = Debug.scope("Allocator", lirGen)) {
+            try (Scope s = Debug.scope("Allocator", nodeLirGen)) {
                 if (backend.shouldAllocateRegisters()) {
                     new LinearScan(target, lir, frameMap).allocate();
                 }
@@ -263,7 +267,7 @@
 
             try (Scope s = Debug.scope("ControlFlowOptimizations")) {
                 EdgeMoveOptimizer.optimize(lir);
-                ControlFlowOptimizer.optimize(lir);
+                ControlFlowOptimizer.optimize(lir, codeEmittingOrder);
                 if (lirGen.canEliminateRedundantMoves()) {
                     RedundantMoveElimination.optimize(lir, frameMap);
                 }
@@ -273,16 +277,16 @@
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
-            return lirGen;
+            return lirGenRes;
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
     }
 
-    public static void emitCode(Backend backend, Assumptions assumptions, LIRGenerator lirGen, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
+    public static void emitCode(Backend backend, Assumptions assumptions, LIRGenerationResult lirGenRes, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
                     CompilationResultBuilderFactory factory) {
-        CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGen, compilationResult, factory);
-        backend.emitCode(crb, lirGen.lir, installedCodeOwner);
+        CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, compilationResult, factory);
+        backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner);
         crb.finish();
         if (!assumptions.isEmpty()) {
             compilationResult.setAssumptions(assumptions);
@@ -290,9 +294,10 @@
 
         if (Debug.isMeterEnabled()) {
             List<DataPatch> ldp = compilationResult.getDataReferences();
-            DebugMetric[] dms = new DebugMetric[Kind.values().length];
+            Kind[] kindValues = Kind.values();
+            DebugMetric[] dms = new DebugMetric[kindValues.length];
             for (int i = 0; i < dms.length; i++) {
-                dms[i] = Debug.metric("DataPatches-" + Kind.values()[i].toString());
+                dms[i] = Debug.metric("DataPatches-%s", kindValues[i]);
             }
 
             for (DataPatch dp : ldp) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Sun Mar 30 16:08:33 2014 +0200
@@ -1179,7 +1179,9 @@
         String to = "?";
         if (first != null && first != Range.EndMarker) {
             from = String.valueOf(from());
-            to = String.valueOf(to());
+            // to() may cache a computed value, modifying the current object, which is a bad idea
+            // for a printing function. Compute it directly instead.
+            to = String.valueOf(calcTo());
         }
         String locationString = this.location == null ? "" : "@" + this.location;
         return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Sun Mar 30 16:08:33 2014 +0200
@@ -135,9 +135,9 @@
     LIRInstruction[] opIdToInstructionMap;
 
     /**
-     * Map from an instruction {@linkplain LIRInstruction#id id} to the {@linkplain Block block}
-     * containing the instruction. Entries should be retrieved with {@link #blockForId(int)} as the
-     * id is not simply an index into this array.
+     * Map from an instruction {@linkplain LIRInstruction#id id} to the {@linkplain AbstractBlock
+     * block} containing the instruction. Entries should be retrieved with {@link #blockForId(int)}
+     * as the id is not simply an index into this array.
      */
     AbstractBlock<?>[] opIdToBlockMap;
 
@@ -172,13 +172,13 @@
     }
 
     public int getFirstLirInstructionId(AbstractBlock<?> block) {
-        int result = ir.lir(block).get(0).id();
+        int result = ir.getLIRforBlock(block).get(0).id();
         assert result >= 0;
         return result;
     }
 
     public int getLastLirInstructionId(AbstractBlock<?> block) {
-        List<LIRInstruction> instructions = ir.lir(block);
+        List<LIRInstruction> instructions = ir.getLIRforBlock(block);
         int result = instructions.get(instructions.size() - 1).id();
         assert result >= 0;
         return result;
@@ -279,7 +279,7 @@
 
     /**
      * Creates a new interval.
-     * 
+     *
      * @param operand the operand for the interval
      * @return the created interval
      */
@@ -295,7 +295,7 @@
 
     /**
      * Creates an interval as a result of splitting or spilling another interval.
-     * 
+     *
      * @param source an interval being split of spilled
      * @return a new interval derived from {@code source}
      */
@@ -376,7 +376,7 @@
 
     /**
      * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}.
-     * 
+     *
      * @param opId an instruction {@linkplain LIRInstruction#id id}
      * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id}
      */
@@ -389,7 +389,7 @@
 
     /**
      * Gets the block containing a given instruction.
-     * 
+     *
      * @param opId an instruction {@linkplain LIRInstruction#id id}
      * @return the block containing the instruction denoted by {@code opId}
      */
@@ -408,7 +408,7 @@
 
     /**
      * Determines if an {@link LIRInstruction} destroys all caller saved registers.
-     * 
+     *
      * @param opId an instruction {@linkplain LIRInstruction#id id}
      * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved
      *         registers.
@@ -505,79 +505,82 @@
 
     // called once before assignment of register numbers
     void eliminateSpillMoves() {
-        Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves");
+        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 (AbstractBlock<?> block : sortedBlocks) {
+                List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+                int numInst = instructions.size();
 
-        // 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);
-        }
+                // iterate all instructions of the block. skip the first
+                // because it is always a label
+                for (int j = 1; j < numInst; j++) {
+                    LIRInstruction op = instructions.get(j);
+                    int opId = op.id();
 
-        LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
-        for (AbstractBlock<?> block : sortedBlocks) {
-            List<LIRInstruction> instructions = ir.lir(block);
-            int numInst = instructions.size();
+                    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.
+                        assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables";
+
+                        Interval curInterval = intervalFor(move.getResult());
 
-            // iterate all instructions of the block. skip the first because it is always a label
-            for (int j = 1; j < numInst; j++) {
-                LIRInstruction op = instructions.get(j);
-                int opId = op.id();
+                        if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) {
+                            // move target is a stack slot that is always correct, so eliminate
+                            // instruction
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult()));
+                            }
+                            // 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";
 
-                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.
-                    assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables";
+                        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);
+                                }
 
-                    Interval curInterval = intervalFor(move.getResult());
+                                AllocatableValue fromLocation = interval.location();
+                                AllocatableValue toLocation = canonicalSpillOpr(interval);
+
+                                assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState();
+                                assert isStackSlot(toLocation) : "to operand must be a stack slot";
 
-                    if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) {
-                        // move target is a stack slot that is always correct, so eliminate
-                        // instruction
-                        if (Debug.isLogEnabled()) {
-                            Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult()));
+                                insertionBuffer.append(j + 1, ir.getSpillMoveFactory().createMove(toLocation, fromLocation));
+
+                                Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
+                            }
+                            interval = interval.next;
                         }
-                        instructions.set(j, null); // null-instructions are deleted by assignRegNum
                     }
-
-                } 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 of the
-                                // block are processed)
-                                insertionBuffer.init(instructions);
-                            }
-
-                            AllocatableValue fromLocation = interval.location();
-                            AllocatableValue toLocation = canonicalSpillOpr(interval);
+                } // end of instruction iteration
 
-                            assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState();
-                            assert isStackSlot(toLocation) : "to operand must be a stack slot";
-
-                            insertionBuffer.append(j + 1, ir.getSpillMoveFactory().createMove(toLocation, fromLocation));
-
-                            Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
-                        }
-                        interval = interval.next;
-                    }
+                if (insertionBuffer.initialized()) {
+                    insertionBuffer.finish();
                 }
-            } // end of instruction iteration
+            } // end of block iteration
 
-            if (insertionBuffer.initialized()) {
-                insertionBuffer.finish();
-            }
-        } // end of block iteration
-
-        assert interval == Interval.EndMarker : "missed an interval";
-        indent.outdent();
+            assert interval == Interval.EndMarker : "missed an interval";
+        }
     }
 
     private static void checkIntervals(Interval interval) {
@@ -624,19 +627,19 @@
         // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
         int numInstructions = 0;
         for (AbstractBlock<?> block : sortedBlocks) {
-            numInstructions += ir.lir(block).size();
+            numInstructions += ir.getLIRforBlock(block).size();
         }
 
         // initialize with correct length
         opIdToInstructionMap = new LIRInstruction[numInstructions];
-        opIdToBlockMap = new Block[numInstructions];
+        opIdToBlockMap = new AbstractBlock<?>[numInstructions];
 
         int opId = 0;
         int index = 0;
         for (AbstractBlock<?> block : sortedBlocks) {
             blockData.put(block, new BlockData());
 
-            List<LIRInstruction> instructions = ir.lir(block);
+            List<LIRInstruction> instructions = ir.getLIRforBlock(block);
 
             int numInst = instructions.size();
             for (int j = 0; j < numInst; j++) {
@@ -676,95 +679,95 @@
 
         // iterate all blocks
         for (final AbstractBlock<?> block : sortedBlocks) {
-            Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId());
+            try (Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId())) {
+
+                final BitSet liveGen = new BitSet(liveSize);
+                final BitSet liveKill = new BitSet(liveSize);
 
-            final BitSet liveGen = new BitSet(liveSize);
-            final BitSet liveKill = new BitSet(liveSize);
+                List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+                int numInst = instructions.size();
 
-            List<LIRInstruction> instructions = ir.lir(block);
-            int numInst = instructions.size();
+                // iterate all instructions of the block
+                for (int j = 0; j < numInst; j++) {
+                    final LIRInstruction op = instructions.get(j);
+
+                    ValueProcedure useProc = new ValueProcedure() {
 
-            // iterate all instructions of the block
-            for (int j = 0; j < numInst; j++) {
-                final LIRInstruction op = instructions.get(j);
+                        @Override
+                        protected Value doValue(Value operand) {
+                            if (isVariable(operand)) {
+                                int operandNum = operandNumber(operand);
+                                if (!liveKill.get(operandNum)) {
+                                    liveGen.set(operandNum);
+                                    Debug.log("liveGen for operand %d", operandNum);
+                                }
+                                if (block.getLoop() != null) {
+                                    intervalInLoop.setBit(operandNum, block.getLoop().index);
+                                }
+                            }
 
-                ValueProcedure useProc = new ValueProcedure() {
+                            if (DetailedAsserts.getValue()) {
+                                verifyInput(block, liveKill, operand);
+                            }
+                            return operand;
+                        }
+                    };
+                    ValueProcedure stateProc = new ValueProcedure() {
 
-                    @Override
-                    protected Value doValue(Value operand) {
-                        if (isVariable(operand)) {
+                        @Override
+                        public Value doValue(Value operand) {
                             int operandNum = operandNumber(operand);
                             if (!liveKill.get(operandNum)) {
                                 liveGen.set(operandNum);
-                                Debug.log("liveGen for operand %d", operandNum);
-                            }
-                            if (block.getLoop() != null) {
-                                intervalInLoop.setBit(operandNum, block.getLoop().index);
+                                Debug.log("liveGen in state for operand %d", operandNum);
                             }
-                        }
-
-                        if (DetailedAsserts.getValue()) {
-                            verifyInput(block, liveKill, operand);
+                            return operand;
                         }
-                        return operand;
-                    }
-                };
-                ValueProcedure stateProc = new ValueProcedure() {
+                    };
+                    ValueProcedure defProc = new ValueProcedure() {
 
-                    @Override
-                    public Value doValue(Value operand) {
-                        int operandNum = operandNumber(operand);
-                        if (!liveKill.get(operandNum)) {
-                            liveGen.set(operandNum);
-                            Debug.log("liveGen in state for operand %d", operandNum);
-                        }
-                        return operand;
-                    }
-                };
-                ValueProcedure defProc = new ValueProcedure() {
+                        @Override
+                        public Value doValue(Value operand) {
+                            if (isVariable(operand)) {
+                                int varNum = operandNumber(operand);
+                                liveKill.set(varNum);
+                                Debug.log("liveKill for operand %d", varNum);
+                                if (block.getLoop() != null) {
+                                    intervalInLoop.setBit(varNum, block.getLoop().index);
+                                }
+                            }
 
-                    @Override
-                    public Value doValue(Value operand) {
-                        if (isVariable(operand)) {
-                            int varNum = operandNumber(operand);
-                            liveKill.set(varNum);
-                            Debug.log("liveKill for operand %d", varNum);
-                            if (block.getLoop() != null) {
-                                intervalInLoop.setBit(varNum, block.getLoop().index);
+                            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);
                             }
+                            return operand;
                         }
-
-                        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);
-                        }
-                        return operand;
-                    }
-                };
+                    };
 
-                try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) {
-                    op.forEachInput(useProc);
-                    op.forEachAlive(useProc);
-                    // Add uses of live locals from interpreter's point of view for proper debug
-                    // information generation
-                    op.forEachState(stateProc);
-                    op.forEachTemp(defProc);
-                    op.forEachOutput(defProc);
-                }
-            } // end of instruction iteration
+                    try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) {
+                        op.forEachInput(useProc);
+                        op.forEachAlive(useProc);
+                        // Add uses of live locals from interpreter's point of view for proper debug
+                        // information generation
+                        op.forEachState(stateProc);
+                        op.forEachTemp(defProc);
+                        op.forEachOutput(defProc);
+                    }
+                } // 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);
+                BlockData blockSets = blockData.get(block);
+                blockSets.liveGen = liveGen;
+                blockSets.liveKill = liveKill;
+                blockSets.liveIn = new BitSet(liveSize);
+                blockSets.liveOut = new BitSet(liveSize);
 
-            Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
-            Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
+                Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
+                Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
 
-            indent.outdent();
+            }
         } // end of block iteration
     }
 
@@ -797,92 +800,93 @@
      * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
      */
     void computeGlobalLiveSets() {
-        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
+        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;
+            // 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;
 
-            Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount);
+                try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) {
 
-            // iterate all blocks in reverse order
-            for (int i = numBlocks - 1; i >= 0; i--) {
-                AbstractBlock<?> block = blockAt(i);
-                BlockData blockSets = blockData.get(block);
+                    // iterate all blocks in reverse order
+                    for (int i = numBlocks - 1; i >= 0; i--) {
+                        AbstractBlock<?> block = blockAt(i);
+                        BlockData blockSets = blockData.get(block);
 
-                changeOccurredInBlock = false;
+                        changeOccurredInBlock = false;
 
-                // liveOut(block) is the union of liveIn(sux), for successors sux of block
-                int n = block.getSuccessorCount();
-                if (n > 0) {
-                    // block has successors
-                    if (n > 0) {
-                        liveOut.clear();
-                        for (AbstractBlock<?> successor : block.getSuccessors()) {
-                            liveOut.or(blockData.get(successor).liveIn);
+                        // liveOut(block) is the union of liveIn(sux), for successors sux of block
+                        int n = block.getSuccessorCount();
+                        if (n > 0) {
+                            // block has successors
+                            if (n > 0) {
+                                liveOut.clear();
+                                for (AbstractBlock<?> successor : block.getSuccessors()) {
+                                    liveOut.or(blockData.get(successor).liveIn);
+                                }
+                            } else {
+                                liveOut.clear();
+                            }
+
+                            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;
+                            }
                         }
-                    } else {
-                        liveOut.clear();
-                    }
 
-                    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;
+                        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);
 
-                        changeOccurred = true;
-                        changeOccurredInBlock = true;
+                            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 (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);
-
-                    Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
-                }
+            if (DetailedAsserts.getValue()) {
+                verifyLiveness();
             }
-            iterationCount++;
 
-            if (changeOccurred && iterationCount > 50) {
-                throw new BailoutException("too many iterations in computeGlobalLiveSets");
+            // check that the liveIn set of the first block is empty
+            AbstractBlock<?> 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);
             }
-            indent2.outdent();
-        } while (changeOccurred);
-
-        if (DetailedAsserts.getValue()) {
-            verifyLiveness();
         }
-
-        // check that the liveIn set of the first block is empty
-        Block 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);
-        }
-        indent.outdent();
     }
 
-    private static LIRGenerator getLIRGeneratorFromDebugContext() {
+    private static NodeLIRGenerator getNodeLIRGeneratorFromDebugContext() {
         if (Debug.isEnabled()) {
-            LIRGenerator lirGen = Debug.contextLookup(LIRGenerator.class);
+            NodeLIRGenerator lirGen = Debug.contextLookup(NodeLIRGenerator.class);
             assert lirGen != null;
             return lirGen;
         }
@@ -890,7 +894,7 @@
     }
 
     private static ValueNode getValueForOperandFromDebugContext(Value value) {
-        LIRGenerator gen = getLIRGeneratorFromDebugContext();
+        NodeLIRGenerator gen = getNodeLIRGeneratorFromDebugContext();
         if (gen != null) {
             return gen.valueForOperand(value);
         }
@@ -899,76 +903,76 @@
 
     private void reportFailure(int numBlocks) {
         try (Scope s = Debug.forceLog()) {
-            Indent indent = Debug.logAndIndent("report failure");
+            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):")) {
+                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)) {
+                        Value operand = operandFor(operandNum);
+                        Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand));
+                    }
+                }
+
+                // print some additional information to simplify debugging
                 for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
                     Value operand = operandFor(operandNum);
-                    Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand));
-                }
-            }
+                    try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand))) {
 
-            // print some additional information to simplify debugging
-            for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
-                Value operand = operandFor(operandNum);
-                final Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand));
+                        Deque<AbstractBlock<?>> definedIn = new ArrayDeque<>();
+                        HashSet<AbstractBlock<?>> usedIn = new HashSet<>();
+                        for (AbstractBlock<?> 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(new ValueProcedure() {
 
-                Deque<AbstractBlock<?>> definedIn = new ArrayDeque<>();
-                HashSet<AbstractBlock<?>> usedIn = new HashSet<>();
-                for (AbstractBlock<?> 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.lir(block)) {
-                                try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) {
-                                    ins.forEachState(new ValueProcedure() {
-
-                                        @Override
-                                        public Value doValue(Value liveStateOperand) {
-                                            Debug.log("operand=%s", liveStateOperand);
-                                            return liveStateOperand;
+                                                @Override
+                                                public Value doValue(Value liveStateOperand) {
+                                                    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);
+                                    }
                                 }
                             }
                         }
-                    }
-                    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.lir(block)) {
-                                Debug.log("%d: %s", ins.id(), ins);
+
+                        int[] hitCount = new int[numBlocks];
+
+                        while (!definedIn.isEmpty()) {
+                            AbstractBlock<?> block = definedIn.removeFirst();
+                            usedIn.remove(block);
+                            for (AbstractBlock<?> 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 (AbstractBlock<?> block : usedIn) {
+                                Debug.log("B%d", block.getId());
                             }
                         }
                     }
                 }
-
-                int[] hitCount = new int[numBlocks];
-
-                while (!definedIn.isEmpty()) {
-                    AbstractBlock<?> block = definedIn.removeFirst();
-                    usedIn.remove(block);
-                    for (AbstractBlock<?> 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 (AbstractBlock<?> block : usedIn) {
-                        Debug.log("B%d", block.getId());
-                    }
-                }
-                indent2.outdent();
             }
-            indent.outdent();
         }
     }
 
@@ -1147,140 +1151,142 @@
 
     void buildIntervals() {
 
-        Indent indent = Debug.logAndIndent("build intervals");
+        try (Indent indent = Debug.logAndIndent("build intervals")) {
 
-        intervalsSize = operandSize();
-        intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY];
+            intervalsSize = operandSize();
+            intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY];
 
-        // create a list with all caller-save registers (cpu, fpu, xmm)
-        Register[] callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters();
+            // create a list with all caller-save registers (cpu, fpu, xmm)
+            Register[] callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters();
 
-        // iterate all blocks in reverse order
-        for (int i = blockCount() - 1; i >= 0; i--) {
-
-            AbstractBlock<?> block = blockAt(i);
-            Indent indent2 = Debug.logAndIndent("handle block %d", block.getId());
+            // iterate all blocks in reverse order
+            for (int i = blockCount() - 1; i >= 0; i--) {
 
-            List<LIRInstruction> instructions = ir.lir(block);
-            final int blockFrom = getFirstLirInstructionId(block);
-            int blockTo = getLastLirInstructionId(block);
+                AbstractBlock<?> block = blockAt(i);
+                try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
 
-            assert blockFrom == instructions.get(0).id();
-            assert blockTo == instructions.get(instructions.size() - 1).id();
+                    List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+                    final int blockFrom = getFirstLirInstructionId(block);
+                    int blockTo = getLastLirInstructionId(block);
 
-            // 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 = operandFor(operandNum);
-                Debug.log("live in %d: %s", operandNum, operand);
-
-                addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal);
+                    assert blockFrom == instructions.get(0).id();
+                    assert blockTo == instructions.get(instructions.size() - 1).id();
 
-                // 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().index)) {
-                    intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
-                }
-            }
+                    // 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 = operandFor(operandNum);
+                        Debug.log("live in %d: %s", operandNum, operand);
 
-            // 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();
+                        addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal);
 
-                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, Kind.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().index)) {
+                            intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
                         }
                     }
-                    Debug.log("operation destroys all caller-save registers");
-                }
 
-                op.forEachOutput(new ValueProcedure() {
+                    // 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)) {
 
-                    @Override
-                    public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                        if (isVariableOrRegister(operand)) {
-                            addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind());
-                            addRegisterHint(op, operand, mode, flags, true);
-                        }
-                        return operand;
-                    }
-                });
-                op.forEachTemp(new ValueProcedure() {
+                            // 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, Kind.Illegal);
+                                    }
+                                }
+                                Debug.log("operation destroys all caller-save registers");
+                            }
+
+                            op.forEachOutput(new ValueProcedure() {
 
-                    @Override
-                    public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                        if (isVariableOrRegister(operand)) {
-                            addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind());
-                            addRegisterHint(op, operand, mode, flags, false);
-                        }
-                        return operand;
-                    }
-                });
-                op.forEachAlive(new ValueProcedure() {
+                                @Override
+                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                                    if (isVariableOrRegister(operand)) {
+                                        addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind());
+                                        addRegisterHint(op, operand, mode, flags, true);
+                                    }
+                                    return operand;
+                                }
+                            });
+                            op.forEachTemp(new ValueProcedure() {
 
-                    @Override
-                    public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                        if (isVariableOrRegister(operand)) {
-                            RegisterPriority p = registerPriorityOfInputOperand(flags);
-                            addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind());
-                            addRegisterHint(op, operand, mode, flags, false);
-                        }
-                        return operand;
-                    }
-                });
-                op.forEachInput(new ValueProcedure() {
+                                @Override
+                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                                    if (isVariableOrRegister(operand)) {
+                                        addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind());
+                                        addRegisterHint(op, operand, mode, flags, false);
+                                    }
+                                    return operand;
+                                }
+                            });
+                            op.forEachAlive(new ValueProcedure() {
 
-                    @Override
-                    public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                        if (isVariableOrRegister(operand)) {
-                            RegisterPriority p = registerPriorityOfInputOperand(flags);
-                            addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind());
-                            addRegisterHint(op, operand, mode, flags, false);
-                        }
-                        return operand;
-                    }
-                });
+                                @Override
+                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                                    if (isVariableOrRegister(operand)) {
+                                        RegisterPriority p = registerPriorityOfInputOperand(flags);
+                                        addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind());
+                                        addRegisterHint(op, operand, mode, flags, false);
+                                    }
+                                    return operand;
+                                }
+                            });
+                            op.forEachInput(new ValueProcedure() {
 
-                // Add uses of live locals from interpreter's point of view for proper
-                // debug information generation
-                // Treat these operands as temp values (if the live range is extended
-                // to a call site, the value would be in a register at the call otherwise)
-                op.forEachState(new ValueProcedure() {
+                                @Override
+                                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                                    if (isVariableOrRegister(operand)) {
+                                        RegisterPriority p = registerPriorityOfInputOperand(flags);
+                                        addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind());
+                                        addRegisterHint(op, operand, mode, flags, false);
+                                    }
+                                    return operand;
+                                }
+                            });
 
-                    @Override
-                    public Value doValue(Value operand) {
-                        addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind());
-                        return operand;
-                    }
-                });
+                            // Add uses of live locals from interpreter's point of view for proper
+                            // debug information generation
+                            // Treat these operands as temp values (if the live range is extended
+                            // to a call site, the value would be in a register at
+                            // the call otherwise)
+                            op.forEachState(new ValueProcedure() {
 
-                // special steps for some instructions (especially moves)
-                handleMethodArguments(op);
+                                @Override
+                                public Value doValue(Value operand) {
+                                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind());
+                                    return operand;
+                                }
+                            });
 
-                indent3.outdent();
+                            // special steps for some instructions (especially moves)
+                            handleMethodArguments(op);
 
-            } // end of instruction iteration
-            indent2.outdent();
-        } // 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);
+                    } // 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);
+                }
             }
         }
-        indent.outdent();
     }
 
     // * Phase 5: actual register allocation
@@ -1432,19 +1438,19 @@
     };
 
     public void allocateRegisters() {
-        Indent indent = Debug.logAndIndent("allocate registers");
-        Interval precoloredIntervals;
-        Interval notPrecoloredIntervals;
+        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;
+            Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL);
+            precoloredIntervals = result.first;
+            notPrecoloredIntervals = result.second;
 
-        // allocate cpu registers
-        LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
-        lsw.walk();
-        lsw.finishAllocation();
-        indent.outdent();
+            // allocate cpu registers
+            LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
+            lsw.walk();
+            lsw.finishAllocation();
+        }
     }
 
     // * Phase 6: resolve data flow
@@ -1510,7 +1516,7 @@
         if (fromBlock.getSuccessorCount() <= 1) {
             Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
 
-            List<LIRInstruction> instructions = ir.lir(fromBlock);
+            List<LIRInstruction> instructions = ir.getLIRforBlock(fromBlock);
             LIRInstruction instr = instructions.get(instructions.size() - 1);
             if (instr instanceof StandardOp.JumpOp) {
                 // insert moves before branch
@@ -1523,7 +1529,7 @@
             Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
 
             if (DetailedAsserts.getValue()) {
-                assert ir.lir(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
+                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
@@ -1534,7 +1540,7 @@
                 }
             }
 
-            moveResolver.setInsertPosition(ir.lir(toBlock), 1);
+            moveResolver.setInsertPosition(ir.getLIRforBlock(toBlock), 1);
         }
     }
 
@@ -1543,69 +1549,71 @@
      * have been split.
      */
     void resolveDataFlow() {
-        Indent indent = Debug.logAndIndent("resolve data flow");
+        try (Indent indent = Debug.logAndIndent("resolve data flow")) {
 
-        int numBlocks = blockCount();
-        MoveResolver moveResolver = new MoveResolver(this);
-        BitSet blockCompleted = new BitSet(numBlocks);
-        BitSet alreadyResolved = new BitSet(numBlocks);
+            int numBlocks = blockCount();
+            MoveResolver moveResolver = new MoveResolver(this);
+            BitSet blockCompleted = new BitSet(numBlocks);
+            BitSet alreadyResolved = new BitSet(numBlocks);
+
+            for (AbstractBlock<?> block : sortedBlocks) {
 
-        for (AbstractBlock<?> 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 has only one predecessor and only one successor
-            if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) {
-                List<LIRInstruction> instructions = ir.lir(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) {
+                        AbstractBlock<?> pred = block.getPredecessors().iterator().next();
+                        AbstractBlock<?> sux = block.getSuccessors().iterator().next();
+
+                        // prevent optimization of two consecutive blocks
+                        if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) {
+                            Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId());
+
+                            blockCompleted.set(block.getLinearScanNumber());
 
-                // check if block is empty (only label and branch)
-                if (instructions.size() == 2) {
-                    AbstractBlock<?> pred = block.getPredecessors().iterator().next();
-                    AbstractBlock<?> sux = block.getSuccessors().iterator().next();
-
-                    // prevent optimization of two consecutive blocks
-                    if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) {
-                        Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId());
+                            // directly resolve between pred and sux (without looking
+                            // at the empty block
+                            // between)
+                            resolveCollectMappings(pred, sux, moveResolver);
+                            if (moveResolver.hasMappings()) {
+                                moveResolver.setInsertPosition(instructions, 1);
+                                moveResolver.resolveAndAppendMoves();
+                            }
+                        }
+                    }
+                }
+            }
 
-                        blockCompleted.set(block.getLinearScanNumber());
+            for (AbstractBlock<?> fromBlock : sortedBlocks) {
+                if (!blockCompleted.get(fromBlock.getLinearScanNumber())) {
+                    alreadyResolved.clear();
+                    alreadyResolved.or(blockCompleted);
+
+                    for (AbstractBlock<?> toBlock : fromBlock.getSuccessors()) {
 
-                        // directly resolve between pred and sux (without looking at the empty block
-                        // between)
-                        resolveCollectMappings(pred, sux, moveResolver);
-                        if (moveResolver.hasMappings()) {
-                            moveResolver.setInsertPosition(instructions, 1);
-                            moveResolver.resolveAndAppendMoves();
+                        // check for duplicate edges between the same blocks (can happen with switch
+                        // blocks)
+                        if (!alreadyResolved.get(toBlock.getLinearScanNumber())) {
+                            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, moveResolver);
+                            if (moveResolver.hasMappings()) {
+                                resolveFindInsertPos(fromBlock, toBlock, moveResolver);
+                                moveResolver.resolveAndAppendMoves();
+                            }
                         }
                     }
                 }
             }
         }
-
-        for (AbstractBlock<?> fromBlock : sortedBlocks) {
-            if (!blockCompleted.get(fromBlock.getLinearScanNumber())) {
-                alreadyResolved.clear();
-                alreadyResolved.or(blockCompleted);
-
-                for (AbstractBlock<?> toBlock : fromBlock.getSuccessors()) {
-
-                    // check for duplicate edges between the same blocks (can happen with switch
-                    // blocks)
-                    if (!alreadyResolved.get(toBlock.getLinearScanNumber())) {
-                        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, moveResolver);
-                        if (moveResolver.hasMappings()) {
-                            resolveFindInsertPos(fromBlock, toBlock, moveResolver);
-                            moveResolver.resolveAndAppendMoves();
-                        }
-                    }
-                }
-            }
-        }
-        indent.outdent();
     }
 
     // * Phase 7: assign register numbers back to LIR
@@ -1618,7 +1626,7 @@
 
     /**
      * 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
@@ -1636,7 +1644,7 @@
                     // before the branch instruction. So the split child information for this branch
                     // would
                     // be incorrect.
-                    LIRInstruction instr = ir.lir(block).get(ir.lir(block).size() - 1);
+                    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 : "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)";
@@ -1752,7 +1760,7 @@
                     // are not
                     // considered in the live ranges of intervals)
                     // Solution: use the first opId of the branch target block instead.
-                    final LIRInstruction instr = ir.lir(block).get(ir.lir(block).size() - 1);
+                    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());
@@ -1846,7 +1854,7 @@
         try (Indent indent = Debug.logAndIndent("assign locations")) {
             for (AbstractBlock<?> block : sortedBlocks) {
                 try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
-                    assignLocations(ir.lir(block), iw);
+                    assignLocations(ir.getLIRforBlock(block), iw);
                 }
             }
         }
@@ -1857,57 +1865,57 @@
         /*
          * This is the point to enable debug logging for the whole register allocation.
          */
-        Indent indent = Debug.logAndIndent("LinearScan allocate");
-
-        try (Scope s = Debug.scope("LifetimeAnalysis")) {
-            numberInstructions();
-            printLir("Before register allocation", true);
-            computeLocalLiveSets();
-            computeGlobalLiveSets();
-            buildIntervals();
-            sortIntervalsBeforeAllocation();
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
+        try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
 
-        try (Scope s = Debug.scope("RegisterAllocation")) {
-            printIntervals("Before register allocation");
-            allocateRegisters();
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
+            try (Scope s = Debug.scope("LifetimeAnalysis")) {
+                numberInstructions();
+                printLir("Before register allocation", true);
+                computeLocalLiveSets();
+                computeGlobalLiveSets();
+                buildIntervals();
+                sortIntervalsBeforeAllocation();
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
 
-        try (Scope s = Debug.scope("ResolveDataFlow")) {
-            resolveDataFlow();
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
+            try (Scope s = Debug.scope("RegisterAllocation")) {
+                printIntervals("Before register allocation");
+                allocateRegisters();
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
 
-        try (Scope s = Debug.scope("DebugInfo")) {
-            frameMap.finish();
-
-            printIntervals("After register allocation");
-            printLir("After register allocation", true);
-
-            sortIntervalsAfterAllocation();
-
-            if (DetailedAsserts.getValue()) {
-                verify();
+            try (Scope s = Debug.scope("ResolveDataFlow")) {
+                resolveDataFlow();
+            } catch (Throwable e) {
+                throw Debug.handle(e);
             }
 
-            eliminateSpillMoves();
-            assignLocations();
+            try (Scope s = Debug.scope("DebugInfo")) {
+                frameMap.finish();
+
+                printIntervals("After register allocation");
+                printLir("After register allocation", true);
+
+                sortIntervalsAfterAllocation();
 
-            if (DetailedAsserts.getValue()) {
-                verifyIntervals();
+                if (DetailedAsserts.getValue()) {
+                    verify();
+                }
+
+                eliminateSpillMoves();
+                assignLocations();
+
+                if (DetailedAsserts.getValue()) {
+                    verifyIntervals();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
             }
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
 
-        printLir("After register number assignment", true);
+            printLir("After register number assignment", true);
 
-        indent.outdent();
+        }
     }
 
     void printIntervals(String label) {
@@ -2060,7 +2068,7 @@
             IntervalWalker iw = new IntervalWalker(this, fixedIntervals, otherIntervals);
 
             for (AbstractBlock<?> block : sortedBlocks) {
-                List<LIRInstruction> instructions = ir.lir(block);
+                List<LIRInstruction> instructions = ir.getLIRforBlock(block);
 
                 for (int j = 0; j < instructions.size(); j++) {
                     LIRInstruction op = instructions.get(j);
@@ -2114,7 +2122,7 @@
 
     /**
      * 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.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Sun Mar 30 16:08:33 2014 +0200
@@ -53,6 +53,14 @@
 
     private MoveResolver moveResolver; // for ordering spill moves
 
+    /**
+     * 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
+     * bootstrap run of Graal). Therefore, we initialize {@link #spillIntervals} with this marker
+     * value, and allocate a "real" list only on demand in {@link #setUsePos}.
+     */
+    private static final List<Interval> EMPTY_LIST = new ArrayList<>(0);
+
     // accessors mapped to same functions in class LinearScan
     int blockCount() {
         return allocator.blockCount();
@@ -70,16 +78,13 @@
         super(allocator, unhandledFixedFirst, unhandledAnyFirst);
 
         // 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.
-        HashSet<Register> registers = new HashSet<>(Arrays.asList(allocator.frameMap.registerConfig.getAllocatableRegisters()));
-        registers.removeAll(Arrays.asList(allocator.frameMap.registerConfig.getCallerSaveRegisters()));
-        allocator.callKillsRegisters = registers.size() == 0;
+        // site. The register allocator can save time not trying to find a register at a call site.
+        allocator.callKillsRegisters = allocator.frameMap.registerConfig.areAllAllocatableRegistersCallerSaved();
 
         moveResolver = new MoveResolver(allocator);
         spillIntervals = Util.uncheckedCast(new List[allocator.registers.length]);
         for (int i = 0; i < allocator.registers.length; i++) {
-            spillIntervals[i] = new ArrayList<>(2);
+            spillIntervals[i] = EMPTY_LIST;
         }
         usePos = new int[allocator.registers.length];
         blockPos = new int[allocator.registers.length];
@@ -114,7 +119,12 @@
                     this.usePos[i] = usePos;
                 }
                 if (!onlyProcessUsePos) {
-                    spillIntervals[i].add(interval);
+                    List<Interval> list = spillIntervals[i];
+                    if (list == EMPTY_LIST) {
+                        list = new ArrayList<>(2);
+                        spillIntervals[i] = list;
+                    }
+                    list.add(interval);
                 }
             }
         }
@@ -244,7 +254,7 @@
         // numbering of instructions is known.
         // When the block already contains spill moves, the index must be increased until the
         // correct index is reached.
-        List<LIRInstruction> instructions = allocator.ir.lir(opBlock);
+        List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(opBlock);
         int index = (opId - instructions.get(0).id()) >> 1;
         assert instructions.get(index).id() <= opId : "error in calculation";
 
@@ -440,82 +450,82 @@
         int maxSplitPos = currentPosition;
         int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos) + 1, interval.from());
 
-        Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos);
+        try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
 
-        assert interval.state == State.Active : "why spill interval that is not active?";
-        assert interval.from() <= minSplitPos : "cannot split before start of interval";
-        assert minSplitPos <= maxSplitPos : "invalid order";
-        assert maxSplitPos < interval.to() : "cannot split at end end of interval";
-        assert currentPosition < interval.to() : "interval must not end before current position";
+            assert interval.state == State.Active : "why spill interval that is not active?";
+            assert interval.from() <= minSplitPos : "cannot split before start of interval";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos < interval.to() : "cannot split at end end of interval";
+            assert currentPosition < interval.to() : "interval must not end before current position";
+
+            if (minSplitPos == interval.from()) {
+                // the whole interval is never used, so spill it entirely to memory
 
-        if (minSplitPos == interval.from()) {
-            // the whole interval is never used, so spill it entirely to memory
+                try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
 
-            try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
+                    assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition";
+
+                    allocator.assignSpillSlot(interval);
+                    allocator.changeSpillState(interval, minSplitPos);
 
-                assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition";
-
-                allocator.assignSpillSlot(interval);
-                allocator.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
+                    // memory . avoid useless moves from memory to register and back
+                    Interval parent = interval;
+                    while (parent != null && parent.isSplitChild()) {
+                        parent = parent.getSplitChildBeforeOpId(parent.from());
 
-                // 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
-                // memory . avoid useless moves from memory to register and back
-                Interval parent = interval;
-                while (parent != null && parent.isSplitChild()) {
-                    parent = parent.getSplitChildBeforeOpId(parent.from());
+                        if (isRegister(parent.location())) {
+                            if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
+                                // parent is never used, so kick it out of its assigned register
+                                Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                                allocator.assignSpillSlot(parent);
+                            } else {
+                                // do not go further back because the register is actually used by
+                                // the interval
+                                parent = null;
+                            }
+                        }
+                    }
+                }
+
+            } else {
+                // search optimal split pos, split interval and spill only the right hand part
+                int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false);
+
+                assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
+                assert optimalSplitPos < interval.to() : "cannot split at end of interval";
+                assert optimalSplitPos >= interval.from() : "cannot split before start of interval";
 
-                    if (isRegister(parent.location())) {
-                        if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
-                            // parent is never used, so kick it out of its assigned register
-                            Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
-                            allocator.assignSpillSlot(parent);
-                        } else {
-                            // do not go further back because the register is actually used by
-                            // the interval
-                            parent = null;
-                        }
+                if (!allocator.isBlockBegin(optimalSplitPos)) {
+                    // move position before actual instruction (odd opId)
+                    optimalSplitPos = (optimalSplitPos - 1) | 1;
+                }
+
+                try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
+                    assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
+                    assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
+
+                    Interval spilledPart = interval.split(optimalSplitPos, allocator);
+                    allocator.assignSpillSlot(spilledPart);
+                    allocator.changeSpillState(spilledPart, optimalSplitPos);
+
+                    if (!allocator.isBlockBegin(optimalSplitPos)) {
+                        Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
+                        insertMove(optimalSplitPos, interval, spilledPart);
+                    }
+
+                    // the currentSplitChild is needed later when moves are inserted for reloading
+                    assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
+                    spilledPart.makeCurrentSplitChild();
+
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("left interval: %s", interval.logString(allocator));
+                        Debug.log("spilled interval   : %s", spilledPart.logString(allocator));
                     }
                 }
             }
-
-        } else {
-            // search optimal split pos, split interval and spill only the right hand part
-            int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false);
-
-            assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
-            assert optimalSplitPos < interval.to() : "cannot split at end of interval";
-            assert optimalSplitPos >= interval.from() : "cannot split before start of interval";
-
-            if (!allocator.isBlockBegin(optimalSplitPos)) {
-                // move position before actual instruction (odd opId)
-                optimalSplitPos = (optimalSplitPos - 1) | 1;
-            }
-
-            try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
-                assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
-                assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
-
-                Interval spilledPart = interval.split(optimalSplitPos, allocator);
-                allocator.assignSpillSlot(spilledPart);
-                allocator.changeSpillState(spilledPart, optimalSplitPos);
-
-                if (!allocator.isBlockBegin(optimalSplitPos)) {
-                    Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
-                    insertMove(optimalSplitPos, interval, spilledPart);
-                }
-
-                // the currentSplitChild is needed later when moves are inserted for reloading
-                assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
-                spilledPart.makeCurrentSplitChild();
-
-                if (Debug.isLogEnabled()) {
-                    Debug.log("left interval: %s", interval.logString(allocator));
-                    Debug.log("spilled interval   : %s", spilledPart.logString(allocator));
-                }
-            }
         }
-        indent.outdent();
     }
 
     void splitStackInterval(Interval interval) {
@@ -830,52 +840,52 @@
         Interval interval = currentInterval;
         boolean result = true;
 
-        Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber);
+        try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
 
-        final Value operand = interval.operand;
-        if (interval.location() != null && isStackSlot(interval.location())) {
-            // activating an interval that has a stack slot assigned . split it at first use
-            // position
-            // used for method parameters
-            Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
-            splitStackInterval(interval);
-            result = false;
+            final Value operand = interval.operand;
+            if (interval.location() != null && isStackSlot(interval.location())) {
+                // activating an interval that has a stack slot assigned . split it at first use
+                // position
+                // used for method parameters
+                Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
+                splitStackInterval(interval);
+                result = false;
 
-        } else {
-            if (interval.location() == null) {
-                // interval has not assigned register . normal allocation
-                // (this is the normal case for most intervals)
-                Debug.log("normal allocation of register");
+            } else {
+                if (interval.location() == null) {
+                    // interval has not assigned register . normal allocation
+                    // (this is the normal case for most intervals)
+                    Debug.log("normal allocation of register");
 
-                // assign same spill slot to non-intersecting intervals
-                combineSpilledIntervals(interval);
+                    // assign same spill slot to non-intersecting intervals
+                    combineSpilledIntervals(interval);
 
-                initVarsForAlloc(interval);
-                if (noAllocationPossible(interval) || !allocFreeRegister(interval)) {
-                    // no empty register available.
-                    // split and spill another interval so that this interval gets a register
-                    allocLockedRegister(interval);
-                }
+                    initVarsForAlloc(interval);
+                    if (noAllocationPossible(interval) || !allocFreeRegister(interval)) {
+                        // no empty register available.
+                        // split and spill another interval so that this interval gets a register
+                        allocLockedRegister(interval);
+                    }
 
-                // spilled intervals need not be move to active-list
-                if (!isRegister(interval.location())) {
-                    result = false;
+                    // spilled intervals need not be move to active-list
+                    if (!isRegister(interval.location())) {
+                        result = false;
+                    }
                 }
             }
-        }
 
-        // load spilled values that become active from stack slot to register
-        if (interval.insertMoveWhenActivated()) {
-            assert interval.isSplitChild();
-            assert interval.currentSplitChild() != null;
-            assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
-            Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
+            // load spilled values that become active from stack slot to register
+            if (interval.insertMoveWhenActivated()) {
+                assert interval.isSplitChild();
+                assert interval.currentSplitChild() != null;
+                assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
+                Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
 
-            insertMove(interval.from(), interval.currentSplitChild(), interval);
+                insertMove(interval.from(), interval.currentSplitChild(), interval);
+            }
+            interval.makeCurrentSplitChild();
+
         }
-        interval.makeCurrentSplitChild();
-
-        indent.outdent();
 
         return result; // true = interval is moved to active list
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Sun Mar 30 16:08:33 2014 +0200
@@ -106,7 +106,7 @@
             }
 
             // process all operations of the block
-            processOperations(allocator.ir.lir(block), inputState);
+            processOperations(allocator.ir.getLIRforBlock(block), inputState);
 
             // iterate all successors
             for (AbstractBlock<?> succ : block.getSuccessors()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeParser.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.gen;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.cfg.*;
+
+public interface BytecodeParser<T extends AbstractBlock<T>> {
+    void processBlock(T block);
+
+    void setParameter(int i, Variable emitMove);
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -89,7 +89,7 @@
                                 if (!currentField.fieldValues().get(i).isConstant() || currentField.fieldValues().get(i).asConstant().getKind() != Kind.Illegal) {
                                     values[pos++] = toValue(currentField.fieldValues().get(i));
                                 } else {
-                                    assert currentField.fieldValues().get(i - 1).kind() == Kind.Double || currentField.fieldValues().get(i - 1).kind() == Kind.Long : vobj + " " + i + " " +
+                                    assert currentField.fieldValues().get(i - 1).getKind() == Kind.Double || currentField.fieldValues().get(i - 1).getKind() == Kind.Long : vobj + " " + i + " " +
                                                     currentField.fieldValues().get(i - 1);
                                 }
                             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResult.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.gen;
+
+import com.oracle.graal.lir.*;
+
+public interface LIRGenerationResult {
+    FrameMap getFrameMap();
+
+    LIR getLIR();
+
+    boolean hasForeignCall();
+
+    void setForeignCall(boolean b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResultBase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.gen;
+
+import com.oracle.graal.lir.*;
+
+public class LIRGenerationResultBase implements LIRGenerationResult {
+    private final LIR lir;
+    private final FrameMap frameMap;
+    /**
+     * Records whether the code being generated makes at least one foreign call.
+     */
+    private boolean hasForeignCall;
+
+    public LIRGenerationResultBase(LIR lir, FrameMap frameMap) {
+        this.lir = lir;
+        this.frameMap = frameMap;
+    }
+
+    public LIR getLIR() {
+        return lir;
+    }
+
+    /**
+     * Determines whether the code being generated makes at least one foreign call.
+     */
+    public boolean hasForeignCall() {
+        return hasForeignCall;
+    }
+
+    public final void setForeignCall(boolean hasForeignCall) {
+        this.hasForeignCall = hasForeignCall;
+    }
+
+    public final FrameMap getFrameMap() {
+        return frameMap;
+    }
+
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,38 +26,31 @@
 import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
-import static com.oracle.graal.nodes.ConstantNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
-import java.util.Map.Entry;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.util.*;
 
 /**
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
-public abstract class LIRGenerator implements LIRGeneratorTool, LIRTypeTool {
+public abstract class LIRGenerator implements ArithmeticLIRGenerator, LIRGeneratorTool, LIRTypeTool {
 
     public static class Options {
         // @formatter:off
@@ -68,16 +61,12 @@
         // @formatter:on
     }
 
-    public final FrameMap frameMap;
-    public final NodeMap<Value> nodeOperands;
-    public final LIR lir;
+    private final Providers providers;
+    private final CallingConvention cc;
 
-    private final Providers providers;
-    protected final CallingConvention cc;
+    private DebugInfoBuilder debugInfoBuilder;
 
-    protected final DebugInfoBuilder debugInfoBuilder;
-
-    protected Block currentBlock;
+    protected AbstractBlock<?> currentBlock;
     private final int traceLevel;
     private final boolean printIRWithLIR;
 
@@ -103,12 +92,12 @@
          * The block that does or will contain {@link #op}. This is initially the block where the
          * first usage of the constant is seen during LIR generation.
          */
-        private Block block;
+        Block block;
 
         /**
          * The variable into which the constant is loaded.
          */
-        private final Variable variable;
+        final Variable variable;
 
         public LoadConstant(Variable variable, Block block, int index, LIRInstruction op) {
             this.variable = variable;
@@ -143,40 +132,40 @@
             if (index >= 0) {
                 // Replace the move with a filler op so that the operation
                 // list does not need to be adjusted.
-                List<LIRInstruction> instructions = lir.lir(block);
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
                 instructions.set(index, new NoOp(null, -1));
                 index = -1;
             }
         }
     }
 
-    private Map<Constant, LoadConstant> constantLoads;
+    Map<Constant, LoadConstant> constantLoads;
 
-    private ValueNode currentInstruction;
-    private ValueNode lastInstructionPrinted; // Debugging only
+    protected LIRGenerationResult res;
 
     /**
-     * Records whether the code being generated makes at least one foreign call.
+     * Set this before using the LIRGenerator.
+     *
+     * TODO this should be removed
      */
-    private boolean hasForeignCall;
+    void setDebugInfoBuilder(DebugInfoBuilder builder) {
+        debugInfoBuilder = builder;
+    }
 
     /**
      * Checks whether the supplied constant can be used without loading it into a register for store
      * operations, i.e., on the right hand side of a memory access.
-     * 
+     *
      * @param c The constant to check.
      * @return True if the constant can be used directly, false if the constant needs to be in a
      *         register.
      */
     public abstract boolean canStoreConstant(Constant c, boolean isCompressed);
 
-    public LIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) {
+    public LIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult res) {
+        this.res = res;
         this.providers = providers;
-        this.frameMap = frameMap;
         this.cc = cc;
-        this.nodeOperands = graph.createNodeMap();
-        this.lir = lir;
-        this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
         this.traceLevel = Options.TraceLIRGeneratorLevel.getValue();
         this.printIRWithLIR = Options.PrintIRWithLIR.getValue();
     }
@@ -189,17 +178,12 @@
         return true;
     }
 
-    @SuppressWarnings("hiding")
-    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
-        return new DebugInfoBuilder(nodeOperands);
-    }
-
     @Override
     public TargetDescription target() {
         return getCodeCache().getTarget();
     }
 
-    protected Providers getProviders() {
+    public Providers getProviders() {
         return providers;
     }
 
@@ -219,100 +203,19 @@
     }
 
     /**
-     * Determines whether the code being generated makes at least one foreign call.
-     */
-    public boolean hasForeignCall() {
-        return hasForeignCall;
-    }
-
-    /**
-     * Returns the operand that has been previously initialized by
-     * {@link #setResult(ValueNode, Value)} with the result of an instruction.
-     * 
-     * @param node A node that produces a result value.
-     */
-    @Override
-    public Value operand(ValueNode node) {
-        if (nodeOperands == null) {
-            return null;
-        }
-        Value operand = nodeOperands.get(node);
-        if (operand == null) {
-            return getConstantOperand(node);
-        }
-        return operand;
-    }
-
-    private Value getConstantOperand(ValueNode node) {
-        if (!ConstantNodeRecordsUsages) {
-            Constant value = node.asConstant();
-            if (value != null) {
-                if (canInlineConstant(value)) {
-                    return setResult(node, value);
-                } else {
-                    Variable loadedValue;
-                    if (constantLoads == null) {
-                        constantLoads = new HashMap<>();
-                    }
-                    LoadConstant load = constantLoads.get(value);
-                    if (load == null) {
-                        int index = lir.lir(currentBlock).size();
-                        loadedValue = emitMove(value);
-                        LIRInstruction op = lir.lir(currentBlock).get(index);
-                        constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op));
-                    } else {
-                        Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock);
-                        loadedValue = load.variable;
-                        if (dominator != load.block) {
-                            load.unpin(lir);
-                        } else {
-                            assert load.block != currentBlock || load.index < lir.lir(currentBlock).size();
-                        }
-                        load.block = dominator;
-                    }
-                    return loadedValue;
-                }
-            }
-        } else {
-            // Constant is loaded by ConstantNode.generate()
-        }
-        return null;
-    }
-
-    public ValueNode valueForOperand(Value value) {
-        for (Entry<Node, Value> entry : nodeOperands.entries()) {
-            if (entry.getValue().equals(value)) {
-                return (ValueNode) entry.getKey();
-            }
-        }
-        return null;
-    }
-
-    /**
      * Creates a new {@linkplain Variable variable}.
-     * 
+     *
      * @param platformKind The kind of the new variable.
      * @return a new variable
      */
     @Override
     public Variable newVariable(PlatformKind platformKind) {
-        return new Variable(platformKind, lir.nextVariable());
+        return new Variable(platformKind, res.getLIR().nextVariable());
     }
 
     @Override
     public RegisterAttributes attributes(Register register) {
-        return frameMap.registerConfig.getAttributesMap()[register.number];
-    }
-
-    @Override
-    public Value setResult(ValueNode x, Value operand) {
-        assert (!isRegister(operand) || !attributes(asRegister(operand)).isAllocatable());
-        assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice";
-        assert operand != null && isLegal(operand) : "operand must be legal";
-        assert operand.getKind().getStackKind() == x.kind() || x.kind() == Kind.Illegal : operand.getKind().getStackKind() + " must match " + x.kind();
-        assert !(x instanceof VirtualObjectNode);
-        nodeOperands.set(x, operand);
-        return operand;
+        return res.getFrameMap().registerConfig.getAttributesMap()[register.number];
     }
 
     @Override
@@ -341,11 +244,13 @@
     }
 
     public LabelRef getLIRBlock(FixedNode b) {
-        Block result = lir.getControlFlowGraph().blockFor(b);
+        assert res.getLIR().getControlFlowGraph() instanceof ControlFlowGraph;
+        Block result = ((ControlFlowGraph) res.getLIR().getControlFlowGraph()).blockFor(b);
         int suxIndex = currentBlock.getSuccessors().indexOf(result);
         assert suxIndex != -1 : "Block not in successor list of current block";
 
-        return LabelRef.forSuccessor(lir, currentBlock, suxIndex);
+        assert currentBlock instanceof Block;
+        return LabelRef.forSuccessor(res.getLIR(), (Block) currentBlock, suxIndex);
     }
 
     /**
@@ -355,18 +260,31 @@
         return false;
     }
 
+    private static FrameState getFrameState(DeoptimizingNode deopt) {
+        if (deopt instanceof DeoptimizingNode.DeoptBefore) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore();
+        } else if (deopt instanceof DeoptimizingNode.DeoptDuring) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring();
+        } else {
+            assert deopt instanceof DeoptimizingNode.DeoptAfter;
+            return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter();
+        }
+    }
+
     public LIRFrameState state(DeoptimizingNode deopt) {
         if (!deopt.canDeoptimize()) {
             return null;
         }
-        return stateFor(deopt.getDeoptimizationState());
+        return stateFor(getFrameState(deopt));
     }
 
     public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
         if (!deopt.canDeoptimize()) {
             return null;
         }
-        return stateForWithExceptionEdge(deopt.getDeoptimizationState(), exceptionEdge);
+        return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge);
     }
 
     public LIRFrameState stateFor(FrameState state) {
@@ -378,12 +296,12 @@
             return new LIRFrameState(null, null, null);
         }
         assert state != null;
-        return debugInfoBuilder.build(state, exceptionEdge);
+        return getDebugInfoBuilder().build(state, exceptionEdge);
     }
 
     /**
      * Gets the ABI specific operand used to return a value of a given kind from a method.
-     * 
+     *
      * @param kind the kind of value being returned
      * @return the operand representing the ABI defined location used return a value of kind
      *         {@code kind}
@@ -392,24 +310,24 @@
         if (kind == Kind.Void) {
             return ILLEGAL;
         }
-        return frameMap.registerConfig.getReturnRegister(kind).asValue(kind);
+        return res.getFrameMap().registerConfig.getReturnRegister(kind).asValue(kind);
     }
 
     public void append(LIRInstruction op) {
         if (printIRWithLIR && !TTY.isSuppressed()) {
-            if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
-                lastInstructionPrinted = currentInstruction;
-                InstructionPrinter ip = new InstructionPrinter(TTY.out());
-                ip.printInstructionListing(currentInstruction);
-            }
+            // if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
+            // lastInstructionPrinted = currentInstruction;
+            // InstructionPrinter ip = new InstructionPrinter(TTY.out());
+            // ip.printInstructionListing(currentInstruction);
+            // }
             TTY.println(op.toStringWithIdPrefix());
             TTY.println();
         }
         assert LIRVerifier.verify(op);
-        lir.lir(currentBlock).add(op);
+        res.getLIR().getLIRforBlock(currentBlock).add(op);
     }
 
-    public void doBlock(Block block, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
+    public final void doBlockStart(AbstractBlock<?> block) {
         if (printIRWithLIR) {
             TTY.print(block.toString());
         }
@@ -417,63 +335,17 @@
         currentBlock = block;
 
         // set up the list of LIR instructions
-        assert lir.lir(block) == null : "LIR list already computed for this block";
-        lir.setLir(block, new ArrayList<LIRInstruction>());
+        assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block";
+        res.getLIR().setLIRforBlock(block, new ArrayList<LIRInstruction>());
 
         append(new LabelOp(new Label(block.getId()), block.isAligned()));
 
         if (traceLevel >= 1) {
             TTY.println("BEGIN Generating LIR for block B" + block.getId());
         }
-
-        if (block == lir.getControlFlowGraph().getStartBlock()) {
-            assert block.getPredecessorCount() == 0;
-            emitPrologue(graph);
-        } else {
-            assert block.getPredecessorCount() > 0;
-        }
+    }
 
-        List<ScheduledNode> nodes = blockMap.get(block);
-        for (int i = 0; i < nodes.size(); i++) {
-            Node instr = nodes.get(i);
-            if (traceLevel >= 3) {
-                TTY.println("LIRGen for " + instr);
-            }
-            if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
-                // Loading of constants is done lazily by operand()
-            } else if (instr instanceof ValueNode) {
-                ValueNode valueNode = (ValueNode) instr;
-                if (operand(valueNode) == null) {
-                    if (!peephole(valueNode)) {
-                        try {
-                            doRoot((ValueNode) instr);
-                        } catch (GraalInternalError e) {
-                            throw e.addContext(instr);
-                        } catch (Throwable e) {
-                            throw new GraalInternalError(e).addContext(instr);
-                        }
-                    }
-                } else {
-                    // There can be cases in which the result of an instruction is already set
-                    // before by other instructions.
-                }
-            }
-        }
-
-        if (!hasBlockEnd(block)) {
-            NodeClassIterable successors = block.getEndNode().successors();
-            assert successors.count() == block.getSuccessorCount();
-            if (block.getSuccessorCount() != 1) {
-                /*
-                 * If we have more than one successor, we cannot just use the first one. Since
-                 * successors are unordered, this would be a random choice.
-                 */
-                throw new GraalInternalError("Block without BlockEndOp: " + block.getEndNode());
-            }
-            emitJump(getLIRBlock((FixedNode) successors.first()));
-        }
-
-        assert verifyBlock(lir, block);
+    public final void doBlockEnd(AbstractBlock<?> block) {
 
         if (traceLevel >= 1) {
             TTY.println("END Generating LIR for block B" + block.getId());
@@ -486,188 +358,12 @@
         }
     }
 
-    protected abstract boolean peephole(ValueNode valueNode);
-
-    private boolean hasBlockEnd(Block block) {
-        List<LIRInstruction> ops = lir.lir(block);
-        if (ops.size() == 0) {
-            return false;
-        }
-        return ops.get(ops.size() - 1) instanceof BlockEndOp;
-    }
-
-    private void doRoot(ValueNode instr) {
-        if (traceLevel >= 2) {
-            TTY.println("Emitting LIR for instruction " + instr);
-        }
-        currentInstruction = instr;
-
-        Debug.log("Visiting %s", instr);
-        emitNode(instr);
-        Debug.log("Operand for %s = %s", instr, operand(instr));
-    }
-
-    protected void emitNode(ValueNode node) {
-        if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) {
-            Debug.log("This node has invalid type, we are emitting dead code(?): %s", node);
-        }
-        if (node instanceof LIRGenLowerable) {
-            ((LIRGenLowerable) node).generate(this);
-        } else if (node instanceof LIRLowerable) {
-            ((LIRLowerable) node).generate(this);
-        } else if (node instanceof ArithmeticLIRLowerable) {
-            ((ArithmeticLIRLowerable) node).generate(this);
-        } else {
-            throw GraalInternalError.shouldNotReachHere("node is not LIRLowerable: " + node);
-        }
-    }
-
-    protected void emitPrologue(StructuredGraph graph) {
-        CallingConvention incomingArguments = cc;
-
-        Value[] params = new Value[incomingArguments.getArgumentCount()];
-        for (int i = 0; i < params.length; i++) {
-            params[i] = toStackKind(incomingArguments.getArgument(i));
-            if (ValueUtil.isStackSlot(params[i])) {
-                StackSlot slot = ValueUtil.asStackSlot(params[i]);
-                if (slot.isInCallerFrame() && !lir.hasArgInCallerFrame()) {
-                    lir.setHasArgInCallerFrame();
-                }
-            }
-        }
-
-        emitIncomingValues(params);
-
-        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
-            Value paramValue = params[param.index()];
-            assert paramValue.getKind() == param.kind().getStackKind();
-            setResult(param, emitMove(paramValue));
-        }
-    }
-
     public void emitIncomingValues(Value[] params) {
-        ((LabelOp) lir.lir(currentBlock).get(0)).setIncomingValues(params);
-    }
-
-    @Override
-    public void visitReturn(ReturnNode x) {
-        AllocatableValue operand = ILLEGAL;
-        if (x.result() != null) {
-            operand = resultOperandFor(x.result().kind());
-            emitMove(operand, operand(x.result()));
-        }
-        emitReturn(operand);
-    }
-
-    protected abstract void emitReturn(Value input);
-
-    @Override
-    public void visitMerge(MergeNode x) {
-    }
-
-    @Override
-    public void visitEndNode(AbstractEndNode end) {
-        moveToPhi(end.merge(), end);
-    }
-
-    /**
-     * Runtime specific classes can override this to insert a safepoint at the end of a loop.
-     */
-    @Override
-    public void visitLoopEnd(LoopEndNode x) {
-    }
-
-    private void moveToPhi(MergeNode merge, AbstractEndNode pred) {
-        if (traceLevel >= 1) {
-            TTY.println("MOVE TO PHI from " + pred + " to " + merge);
-        }
-        PhiResolver resolver = new PhiResolver(this);
-        for (PhiNode phi : merge.phis()) {
-            if (phi.type() == PhiType.Value) {
-                ValueNode curVal = phi.valueAt(pred);
-                resolver.move(operandForPhi(phi), operand(curVal));
-            }
-        }
-        resolver.dispose();
-
-        append(new JumpOp(getLIRBlock(merge)));
+        ((LabelOp) res.getLIR().getLIRforBlock(currentBlock).get(0)).setIncomingValues(params);
     }
 
     protected PlatformKind getPhiKind(PhiNode phi) {
-        return phi.kind();
-    }
-
-    private Value operandForPhi(PhiNode phi) {
-        assert phi.type() == PhiType.Value : "wrong phi type: " + phi;
-        Value result = operand(phi);
-        if (result == null) {
-            // allocate a variable for this phi
-            Variable newOperand = newVariable(getPhiKind(phi));
-            setResult(phi, newOperand);
-            return newOperand;
-        } else {
-            return result;
-        }
-    }
-
-    @Override
-    public void emitIf(IfNode x) {
-        emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
-    }
-
-    public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        if (node instanceof IsNullNode) {
-            emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else if (node instanceof CompareNode) {
-            emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else if (node instanceof LogicConstantNode) {
-            emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor);
-        } else if (node instanceof IntegerTestNode) {
-            emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else {
-            throw GraalInternalError.unimplemented(node.toString());
-        }
-    }
-
-    private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        emitIntegerTestBranch(operand(test.x()), operand(test.y()), trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) {
-        LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock;
-        emitJump(block);
-    }
-
-    @Override
-    public void emitConditional(ConditionalNode conditional) {
-        Value tVal = operand(conditional.trueValue());
-        Value fVal = operand(conditional.falseValue());
-        setResult(conditional, emitConditional(conditional.condition(), tVal, fVal));
-    }
-
-    public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) {
-        if (node instanceof IsNullNode) {
-            IsNullNode isNullNode = (IsNullNode) node;
-            return emitConditionalMove(operand(isNullNode.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueValue, falseValue);
-        } else if (node instanceof CompareNode) {
-            CompareNode compare = (CompareNode) node;
-            return emitConditionalMove(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue);
-        } else if (node instanceof LogicConstantNode) {
-            return emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue);
-        } else if (node instanceof IntegerTestNode) {
-            IntegerTestNode test = (IntegerTestNode) node;
-            return emitIntegerTestMove(operand(test.x()), operand(test.y()), trueValue, falseValue);
-        } else {
-            throw GraalInternalError.unimplemented(node.toString());
-        }
+        return phi.getKind();
     }
 
     public abstract void emitJump(LabelRef label);
@@ -682,42 +378,6 @@
 
     public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
 
-    @Override
-    public void emitInvoke(Invoke x) {
-        LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget();
-        CallingConvention invokeCc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(getMetaAccess()), callTarget.signature(), target(), false);
-        frameMap.callsMethod(invokeCc);
-
-        Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments());
-
-        LabelRef exceptionEdge = null;
-        if (x instanceof InvokeWithExceptionNode) {
-            exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge());
-        }
-        LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge);
-
-        Value result = invokeCc.getReturn();
-        if (callTarget instanceof DirectCallTargetNode) {
-            emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
-        } else if (callTarget instanceof IndirectCallTargetNode) {
-            emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        if (isLegal(result)) {
-            setResult(x.asNode(), emitMove(result));
-        }
-
-        if (x instanceof InvokeWithExceptionNode) {
-            emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next()));
-        }
-    }
-
-    protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
-
-    protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
-
     protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
 
     protected static AllocatableValue toStackKind(AllocatableValue value) {
@@ -735,29 +395,12 @@
         return value;
     }
 
-    public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection<ValueNode> arguments) {
-        // for each argument, load it into the correct location
-        Value[] result = new Value[arguments.size()];
-        int j = 0;
-        for (ValueNode arg : arguments) {
-            if (arg != null) {
-                AllocatableValue operand = toStackKind(invokeCc.getArgument(j));
-                emitMove(operand, operand(arg));
-                result[j] = operand;
-                j++;
-            } else {
-                throw GraalInternalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types...");
-            }
-        }
-        return result;
-    }
-
     @Override
     public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
         LIRFrameState state = null;
         if (linkage.canDeoptimize()) {
             if (info != null) {
-                state = stateFor(info.getDeoptimizationState());
+                state = stateFor(getFrameState(info));
             } else {
                 assert needOnlyOopMaps();
                 state = new LIRFrameState(null, null, null);
@@ -766,7 +409,7 @@
 
         // move the arguments into the correct location
         CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
-        frameMap.callsMethod(linkageCc);
+        res.getFrameMap().callsMethod(linkageCc);
         assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
         Value[] argLocations = new Value[args.length];
         for (int i = 0; i < args.length; i++) {
@@ -775,7 +418,7 @@
             emitMove(loc, arg);
             argLocations[i] = loc;
         }
-        this.hasForeignCall = true;
+        res.setForeignCall(true);
         emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
 
         if (isLegal(linkageCc.getReturn())) {
@@ -785,46 +428,6 @@
         }
     }
 
-    /**
-     * This method tries to create a switch implementation that is optimal for the given switch. It
-     * will either generate a sequential if/then/else cascade, a set of range tests or a table
-     * switch.
-     * 
-     * If the given switch does not contain int keys, it will always create a sequential
-     * implementation.
-     */
-    @Override
-    public void emitSwitch(SwitchNode x) {
-        assert x.defaultSuccessor() != null;
-        LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor());
-        int keyCount = x.keyCount();
-        if (keyCount == 0) {
-            emitJump(defaultTarget);
-        } else {
-            Variable value = load(operand(x.value()));
-            if (keyCount == 1) {
-                assert defaultTarget != null;
-                double probability = x.probability(x.keySuccessor(0));
-                emitCompareBranch(load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability);
-            } else {
-                LabelRef[] keyTargets = new LabelRef[keyCount];
-                Constant[] keyConstants = new Constant[keyCount];
-                double[] keyProbabilities = new double[keyCount];
-                for (int i = 0; i < keyCount; i++) {
-                    keyTargets[i] = getLIRBlock(x.keySuccessor(i));
-                    keyConstants[i] = x.keyAt(i);
-                    keyProbabilities[i] = x.keyProbability(i);
-                }
-                if (value.getKind() != Kind.Int || !x.isSorted()) {
-                    // hopefully only a few entries
-                    emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget);
-                } else {
-                    emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value);
-                }
-            }
-        }
-    }
-
     protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
         int keyCount = keyConstants.length;
         SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
@@ -856,8 +459,13 @@
 
     protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
 
-    public FrameMap frameMap() {
-        return frameMap;
+    public CallingConvention getCallingConvention() {
+        return cc;
+    }
+
+    public DebugInfoBuilder getDebugInfoBuilder() {
+        assert debugInfoBuilder != null;
+        return debugInfoBuilder;
     }
 
     @Override
@@ -883,13 +491,13 @@
                         outOfLoopDominator = outOfLoopDominator.getDominator();
                     }
                     if (outOfLoopDominator != lc.block) {
-                        lc.unpin(lir);
+                        lc.unpin(res.getLIR());
                         lc.block = outOfLoopDominator;
                     }
                 }
 
                 if (lc.index != -1) {
-                    assert lir.lir(lc.block).get(lc.index) == lc.op;
+                    assert res.getLIR().getLIRforBlock(lc.block).get(lc.index) == lc.op;
                     iter.remove();
                 }
             }
@@ -910,7 +518,7 @@
                 }
                 int groupSize = groupEnd - groupBegin;
 
-                List<LIRInstruction> ops = lir.lir(block);
+                List<LIRInstruction> ops = res.getLIR().getLIRforBlock(block);
                 int lastIndex = ops.size() - 1;
                 assert ops.get(lastIndex) instanceof BlockEndOp;
                 int insertionIndex = lastIndex;
@@ -1009,4 +617,12 @@
     public abstract void emitByteSwap(Variable result, Value operand);
 
     public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+    public AbstractBlock<?> getCurrentBlock() {
+        return currentBlock;
+    }
+
+    void setCurrentBlock(AbstractBlock<?> block) {
+        currentBlock = block;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,789 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.gen;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.api.meta.Value.*;
+import static com.oracle.graal.lir.LIR.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.gen.LIRGenerator.LoadConstant;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
+
+/**
+ * This class traverses the HIR instructions and generates LIR instructions from them.
+ */
+public abstract class NodeLIRGenerator implements NodeLIRGeneratorTool {
+
+    private final NodeMap<Value> nodeOperands;
+    private final DebugInfoBuilder debugInfoBuilder;
+
+    private final int traceLevel;
+    private final boolean printIRWithLIR;
+
+    protected final LIRGenerator gen;
+
+    private ValueNode currentInstruction;
+    private ValueNode lastInstructionPrinted; // Debugging only
+
+    protected LIRGenerationResult res;
+
+    public NodeLIRGenerator(StructuredGraph graph, LIRGenerationResult res, LIRGenerator gen) {
+        this.res = res;
+        this.nodeOperands = graph.createNodeMap();
+        this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
+        this.gen = gen;
+        this.traceLevel = LIRGenerator.Options.TraceLIRGeneratorLevel.getValue();
+        this.printIRWithLIR = LIRGenerator.Options.PrintIRWithLIR.getValue();
+        gen.setDebugInfoBuilder(debugInfoBuilder);
+    }
+
+    @SuppressWarnings("hiding")
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        return new DebugInfoBuilder(nodeOperands);
+    }
+
+    /**
+     * Returns the operand that has been previously initialized by
+     * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code
+     * generation error to ask for the operand of ValueNode that doesn't have one yet.
+     *
+     * @param node A node that produces a result value.
+     */
+    @Override
+    public Value operand(ValueNode node) {
+        Value operand = getOperand(node);
+        assert operand != null : String.format("missing operand for %1s", node);
+        return operand;
+    }
+
+    @Override
+    public boolean hasOperand(ValueNode node) {
+        return getOperand(node) != null;
+    }
+
+    private Value getOperand(ValueNode node) {
+        if (nodeOperands == null) {
+            return null;
+        }
+        Value operand = nodeOperands.get(node);
+        if (operand == null) {
+            operand = getConstantOperand(node);
+        }
+        return operand;
+    }
+
+    private Value getConstantOperand(ValueNode node) {
+        if (!ConstantNodeRecordsUsages) {
+            Constant value = node.asConstant();
+            if (value != null) {
+                if (gen.canInlineConstant(value)) {
+                    return setResult(node, value);
+                } else {
+                    Variable loadedValue;
+                    if (gen.constantLoads == null) {
+                        gen.constantLoads = new HashMap<>();
+                    }
+                    LoadConstant load = gen.constantLoads.get(value);
+                    assert gen.getCurrentBlock() instanceof Block;
+                    if (load == null) {
+                        int index = res.getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
+                        loadedValue = gen.emitMove(value);
+                        LIRInstruction op = res.getLIR().getLIRforBlock(gen.getCurrentBlock()).get(index);
+                        gen.constantLoads.put(value, new LoadConstant(loadedValue, (Block) gen.getCurrentBlock(), index, op));
+                    } else {
+                        Block dominator = ControlFlowGraph.commonDominator(load.block, (Block) gen.getCurrentBlock());
+                        loadedValue = load.variable;
+                        if (dominator != load.block) {
+                            load.unpin(res.getLIR());
+                        } else {
+                            assert load.block != gen.getCurrentBlock() || load.index < res.getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
+                        }
+                        load.block = dominator;
+                    }
+                    return loadedValue;
+                }
+            }
+        } else {
+            // Constant is loaded by ConstantNode.generate()
+        }
+        return null;
+    }
+
+    public ValueNode valueForOperand(Value value) {
+        for (Entry<Node, Value> entry : getNodeOperands().entries()) {
+            if (entry.getValue().equals(value)) {
+                return (ValueNode) entry.getKey();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Value setResult(ValueNode x, Value operand) {
+        assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable());
+        assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert operand != null && isLegal(operand) : "operand must be legal";
+        assert operand.getKind().getStackKind() == x.getKind() || x.getKind() == Kind.Illegal : operand.getKind().getStackKind() + " must match " + x.getKind();
+        assert !(x instanceof VirtualObjectNode);
+        nodeOperands.set(x, operand);
+        return operand;
+    }
+
+    public LabelRef getLIRBlock(FixedNode b) {
+        assert res.getLIR().getControlFlowGraph() instanceof ControlFlowGraph;
+        Block result = ((ControlFlowGraph) res.getLIR().getControlFlowGraph()).blockFor(b);
+        int suxIndex = gen.getCurrentBlock().getSuccessors().indexOf(result);
+        assert suxIndex != -1 : "Block not in successor list of current block";
+
+        assert gen.getCurrentBlock() instanceof Block;
+        return LabelRef.forSuccessor(res.getLIR(), (Block) gen.getCurrentBlock(), suxIndex);
+    }
+
+    public final void append(LIRInstruction op) {
+        if (printIRWithLIR && !TTY.isSuppressed()) {
+            if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
+                lastInstructionPrinted = currentInstruction;
+                InstructionPrinter ip = new InstructionPrinter(TTY.out());
+                ip.printInstructionListing(currentInstruction);
+            }
+        }
+        gen.append(op);
+    }
+
+    public final void doBlockStart(AbstractBlock<?> block) {
+        if (printIRWithLIR) {
+            TTY.print(block.toString());
+        }
+
+        gen.setCurrentBlock(block);
+
+        // set up the list of LIR instructions
+        assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block";
+        res.getLIR().setLIRforBlock(block, new ArrayList<LIRInstruction>());
+
+        append(new LabelOp(new Label(block.getId()), block.isAligned()));
+
+        if (traceLevel >= 1) {
+            TTY.println("BEGIN Generating LIR for block B" + block.getId());
+        }
+    }
+
+    public final void doBlockEnd(AbstractBlock<?> block) {
+
+        if (traceLevel >= 1) {
+            TTY.println("END Generating LIR for block B" + block.getId());
+        }
+
+        gen.setCurrentBlock(null);
+
+        if (printIRWithLIR) {
+            TTY.println();
+        }
+    }
+
+    public void doBlock(Block block, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
+        doBlockStart(block);
+
+        if (block == res.getLIR().getControlFlowGraph().getStartBlock()) {
+            assert block.getPredecessorCount() == 0;
+            emitPrologue(graph);
+        } else {
+            assert block.getPredecessorCount() > 0;
+        }
+
+        List<ScheduledNode> nodes = blockMap.get(block);
+        int instructionsFolded = 0;
+        for (int i = 0; i < nodes.size(); i++) {
+            Node instr = nodes.get(i);
+            if (traceLevel >= 3) {
+                TTY.println("LIRGen for " + instr);
+            }
+            if (instructionsFolded > 0) {
+                instructionsFolded--;
+                continue;
+            }
+            if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
+                // Loading of constants is done lazily by operand()
+
+            } else if (instr instanceof ValueNode) {
+                ValueNode valueNode = (ValueNode) instr;
+                if (!hasOperand(valueNode)) {
+                    if (!peephole(valueNode)) {
+                        instructionsFolded = maybeFoldMemory(nodes, i, valueNode);
+                        if (instructionsFolded == 0) {
+                            try {
+                                doRoot((ValueNode) instr);
+                            } catch (GraalInternalError e) {
+                                throw e.addContext(instr);
+                            } catch (Throwable e) {
+                                throw new GraalInternalError(e).addContext(instr);
+                            }
+                        }
+                    }
+                } else {
+                    // There can be cases in which the result of an instruction is already set
+                    // before by other instructions.
+                }
+            }
+        }
+
+        if (!hasBlockEnd(block)) {
+            NodeClassIterable successors = block.getEndNode().successors();
+            assert successors.count() == block.getSuccessorCount();
+            if (block.getSuccessorCount() != 1) {
+                /*
+                 * If we have more than one successor, we cannot just use the first one. Since
+                 * successors are unordered, this would be a random choice.
+                 */
+                throw new GraalInternalError("Block without BlockEndOp: " + block.getEndNode());
+            }
+            gen.emitJump(getLIRBlock((FixedNode) successors.first()));
+        }
+
+        assert verifyBlock(res.getLIR(), block);
+        doBlockEnd(block);
+    }
+
+    private static final DebugMetric MemoryFoldSuccess = Debug.metric("MemoryFoldSuccess");
+    private static final DebugMetric MemoryFoldFailed = Debug.metric("MemoryFoldFailed");
+    private static final DebugMetric MemoryFoldFailedNonAdjacent = Debug.metric("MemoryFoldedFailedNonAdjacent");
+    private static final DebugMetric MemoryFoldFailedDifferentBlock = Debug.metric("MemoryFoldedFailedDifferentBlock");
+
+    /**
+     * Subclass can provide helper to fold memory operations into other operations.
+     */
+    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
+        return null;
+    }
+
+    private static final Object LOG_OUTPUT_LOCK = new Object();
+
+    /**
+     * Try to find a sequence of Nodes which can be passed to the backend to look for optimized
+     * instruction sequences using memory. Currently this basically is a read with a single
+     * arithmetic user followed by an possible if use. This should generalized to more generic
+     * pattern matching so that it can be more flexibly used.
+     */
+    private int maybeFoldMemory(List<ScheduledNode> nodes, int i, ValueNode access) {
+        MemoryArithmeticLIRLowerer lowerer = getMemoryLowerer();
+        if (lowerer != null && GraalOptions.OptFoldMemory.getValue() && (access instanceof ReadNode || access instanceof FloatingReadNode) && access.usages().count() == 1 && i + 1 < nodes.size()) {
+            try (Scope s = Debug.scope("MaybeFoldMemory", access)) {
+                // This is all bit hacky since it's happening on the linearized schedule. This needs
+                // to be revisited at some point.
+
+                // Find a memory lowerable usage of this operation
+                if (access.usages().first() instanceof MemoryArithmeticLIRLowerable) {
+                    ValueNode operation = (ValueNode) access.usages().first();
+                    if (!nodes.contains(operation)) {
+                        Debug.log("node %1s in different block from %1s", access, operation);
+                        MemoryFoldFailedDifferentBlock.increment();
+                        return 0;
+                    }
+                    ValueNode firstOperation = operation;
+                    if (operation instanceof LogicNode) {
+                        if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) {
+                            ValueNode ifNode = (ValueNode) operation.usages().first();
+                            if (!nodes.contains(ifNode)) {
+                                MemoryFoldFailedDifferentBlock.increment();
+                                Debug.log("if node %1s in different block from %1s", ifNode, operation);
+                                try (Indent indent = Debug.logAndIndent("checking operations")) {
+                                    int start = nodes.indexOf(access);
+                                    int end = nodes.indexOf(operation);
+                                    for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
+                                        Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
+                                    }
+                                }
+                                return 0;
+                            } else {
+                                operation = ifNode;
+                            }
+                        }
+                    }
+                    if (Debug.isLogEnabled()) {
+                        synchronized (LOG_OUTPUT_LOCK) {  // Hack to ensure the output is grouped.
+                            try (Indent indent = Debug.logAndIndent("checking operations")) {
+                                int start = nodes.indexOf(access);
+                                int end = nodes.indexOf(operation);
+                                for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
+                                    Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
+                                }
+                            }
+                        }
+                    }
+                    // Possible lowerable operation in the same block. Check out the dependencies.
+                    int opIndex = nodes.indexOf(operation);
+                    int current = i + 1;
+                    ArrayList<ValueNode> deferred = null;
+                    while (current < opIndex) {
+                        ScheduledNode node = nodes.get(current);
+                        if (node != firstOperation) {
+                            if (node instanceof LocationNode || node instanceof VirtualObjectNode) {
+                                // nothing to do
+                            } else if (node instanceof ConstantNode) {
+                                if (deferred == null) {
+                                    deferred = new ArrayList<>(2);
+                                }
+                                // These nodes are collected and the backend is expended to
+                                // evaluate them before generating the lowered form. This
+                                // basically works around unfriendly scheduling of values which
+                                // are defined in a block but not used there.
+                                deferred.add((ValueNode) node);
+                            } else {
+                                Debug.log("unexpected node %1s", node);
+                                // Unexpected inline node
+                                break;
+                            }
+                        }
+                        current++;
+                    }
+
+                    if (current == opIndex) {
+                        if (lowerer.memoryPeephole((Access) access, (MemoryArithmeticLIRLowerable) operation, deferred)) {
+                            MemoryFoldSuccess.increment();
+                            // if this operation had multiple access inputs, then previous attempts
+                            // would be marked as failures which is wrong. Try to adjust the
+                            // counters to account for this.
+                            for (Node input : operation.inputs()) {
+                                if (input == access) {
+                                    continue;
+                                }
+                                if (input instanceof Access && nodes.contains(input)) {
+                                    MemoryFoldFailedNonAdjacent.add(-1);
+                                }
+                            }
+                            if (deferred != null) {
+                                // Ensure deferred nodes were evaluated
+                                for (ValueNode node : deferred) {
+                                    assert hasOperand(node);
+                                }
+                            }
+                            return opIndex - i;
+                        } else {
+                            // This isn't true failure, it just means there wasn't match for the
+                            // pattern. Usually that means it's just not supported by the backend.
+                            MemoryFoldFailed.increment();
+                            return 0;
+                        }
+                    } else {
+                        MemoryFoldFailedNonAdjacent.increment();
+                    }
+                } else {
+                    // memory usage which isn't considered lowerable. Mostly these are
+                    // uninteresting but it might be worth looking at to ensure that interesting
+                    // nodes are being properly handled.
+                    // Debug.log("usage isn't lowerable %1s", access.usages().first());
+                }
+            }
+        }
+        return 0;
+    }
+
+    protected abstract boolean peephole(ValueNode valueNode);
+
+    private boolean hasBlockEnd(Block block) {
+        List<LIRInstruction> ops = res.getLIR().getLIRforBlock(block);
+        if (ops.size() == 0) {
+            return false;
+        }
+        return ops.get(ops.size() - 1) instanceof BlockEndOp;
+    }
+
+    private void doRoot(ValueNode instr) {
+        if (traceLevel >= 2) {
+            TTY.println("Emitting LIR for instruction " + instr);
+        }
+        currentInstruction = instr;
+
+        Debug.log("Visiting %s", instr);
+        emitNode(instr);
+        Debug.log("Operand for %s = %s", instr, getOperand(instr));
+    }
+
+    protected void emitNode(ValueNode node) {
+        if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) {
+            Debug.log("This node has invalid type, we are emitting dead code(?): %s", node);
+        }
+        if (node instanceof LIRGenLowerable) {
+            ((LIRGenLowerable) node).generate(this);
+        } else if (node instanceof LIRGenResLowerable) {
+            ((LIRGenResLowerable) node).generate(this, res);
+        } else if (node instanceof LIRLowerable) {
+            ((LIRLowerable) node).generate(this);
+        } else if (node instanceof ArithmeticLIRLowerable) {
+            ((ArithmeticLIRLowerable) node).generate(this);
+        } else {
+            throw GraalInternalError.shouldNotReachHere("node is not LIRLowerable: " + node);
+        }
+    }
+
+    protected void emitPrologue(StructuredGraph graph) {
+        CallingConvention incomingArguments = gen.getCallingConvention();
+
+        Value[] params = new Value[incomingArguments.getArgumentCount()];
+        for (int i = 0; i < params.length; i++) {
+            params[i] = toStackKind(incomingArguments.getArgument(i));
+            if (ValueUtil.isStackSlot(params[i])) {
+                StackSlot slot = ValueUtil.asStackSlot(params[i]);
+                if (slot.isInCallerFrame() && !res.getLIR().hasArgInCallerFrame()) {
+                    res.getLIR().setHasArgInCallerFrame();
+                }
+            }
+        }
+
+        emitIncomingValues(params);
+
+        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+            Value paramValue = params[param.index()];
+            assert paramValue.getKind() == param.getKind().getStackKind();
+            setResult(param, gen.emitMove(paramValue));
+        }
+    }
+
+    protected <T extends AbstractBlock<T>> void emitPrologue(ResolvedJavaMethod method, BytecodeParser<T> parser) {
+        CallingConvention incomingArguments = gen.getCallingConvention();
+
+        Value[] params = new Value[incomingArguments.getArgumentCount()];
+        for (int i = 0; i < params.length; i++) {
+            params[i] = toStackKind(incomingArguments.getArgument(i));
+            if (ValueUtil.isStackSlot(params[i])) {
+                StackSlot slot = ValueUtil.asStackSlot(params[i]);
+                if (slot.isInCallerFrame() && !res.getLIR().hasArgInCallerFrame()) {
+                    res.getLIR().setHasArgInCallerFrame();
+                }
+            }
+        }
+
+        emitIncomingValues(params);
+
+        Signature sig = method.getSignature();
+        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        for (int i = 0; i < sig.getParameterCount(!isStatic); i++) {
+            Value paramValue = params[i];
+            assert paramValue.getKind() == sig.getParameterKind(i).getStackKind();
+            // TODO setResult(param, emitMove(paramValue));
+            parser.setParameter(i, gen.emitMove(paramValue));
+        }
+
+        // return arguments;
+    }
+
+    public void emitIncomingValues(Value[] params) {
+        ((LabelOp) res.getLIR().getLIRforBlock(gen.getCurrentBlock()).get(0)).setIncomingValues(params);
+    }
+
+    @Override
+    public void visitReturn(ReturnNode x) {
+        AllocatableValue operand = ILLEGAL;
+        if (x.result() != null) {
+            operand = gen.resultOperandFor(x.result().getKind());
+            gen.emitMove(operand, operand(x.result()));
+        }
+        gen.emitReturn(operand);
+    }
+
+    @Override
+    public void visitMerge(MergeNode x) {
+    }
+
+    @Override
+    public void visitEndNode(AbstractEndNode end) {
+        moveToPhi(end.merge(), end);
+    }
+
+    /**
+     * Runtime specific classes can override this to insert a safepoint at the end of a loop.
+     */
+    @Override
+    public void visitLoopEnd(LoopEndNode x) {
+    }
+
+    private void moveToPhi(MergeNode merge, AbstractEndNode pred) {
+        if (traceLevel >= 1) {
+            TTY.println("MOVE TO PHI from " + pred + " to " + merge);
+        }
+        PhiResolver resolver = new PhiResolver(gen);
+        for (PhiNode phi : merge.phis()) {
+            if (phi.type() == PhiType.Value) {
+                ValueNode curVal = phi.valueAt(pred);
+                resolver.move(operandForPhi(phi), operand(curVal));
+            }
+        }
+        resolver.dispose();
+
+        append(new JumpOp(getLIRBlock(merge)));
+    }
+
+    protected PlatformKind getPhiKind(PhiNode phi) {
+        return phi.getKind();
+    }
+
+    private Value operandForPhi(PhiNode phi) {
+        assert phi.type() == PhiType.Value : "wrong phi type: " + phi;
+        Value result = getOperand(phi);
+        if (result == null) {
+            // allocate a variable for this phi
+            Variable newOperand = gen.newVariable(getPhiKind(phi));
+            setResult(phi, newOperand);
+            return newOperand;
+        } else {
+            return result;
+        }
+    }
+
+    @Override
+    public void emitIf(IfNode x) {
+        emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
+    }
+
+    public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        if (node instanceof IsNullNode) {
+            emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else if (node instanceof CompareNode) {
+            emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else if (node instanceof LogicConstantNode) {
+            emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor);
+        } else if (node instanceof IntegerTestNode) {
+            emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else {
+            throw GraalInternalError.unimplemented(node.toString());
+        }
+    }
+
+    private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        gen.emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        gen.emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        gen.emitIntegerTestBranch(operand(test.x()), operand(test.y()), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) {
+        LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock;
+        gen.emitJump(block);
+    }
+
+    @Override
+    public void emitConditional(ConditionalNode conditional) {
+        Value tVal = operand(conditional.trueValue());
+        Value fVal = operand(conditional.falseValue());
+        setResult(conditional, emitConditional(conditional.condition(), tVal, fVal));
+    }
+
+    public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) {
+        if (node instanceof IsNullNode) {
+            IsNullNode isNullNode = (IsNullNode) node;
+            return gen.emitConditionalMove(operand(isNullNode.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueValue, falseValue);
+        } else if (node instanceof CompareNode) {
+            CompareNode compare = (CompareNode) node;
+            return gen.emitConditionalMove(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue);
+        } else if (node instanceof LogicConstantNode) {
+            return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue);
+        } else if (node instanceof IntegerTestNode) {
+            IntegerTestNode test = (IntegerTestNode) node;
+            return gen.emitIntegerTestMove(operand(test.x()), operand(test.y()), trueValue, falseValue);
+        } else {
+            throw GraalInternalError.unimplemented(node.toString());
+        }
+    }
+
+    @Override
+    public void emitInvoke(Invoke x) {
+        LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget();
+        CallingConvention invokeCc = res.getFrameMap().registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()), callTarget.signature(),
+                        gen.target(), false);
+        res.getFrameMap().callsMethod(invokeCc);
+
+        Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments());
+
+        LabelRef exceptionEdge = null;
+        if (x instanceof InvokeWithExceptionNode) {
+            exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge());
+        }
+        LIRFrameState callState = gen.stateWithExceptionEdge(x, exceptionEdge);
+
+        Value result = invokeCc.getReturn();
+        if (callTarget instanceof DirectCallTargetNode) {
+            emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
+        } else if (callTarget instanceof IndirectCallTargetNode) {
+            emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState);
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        if (isLegal(result)) {
+            setResult(x.asNode(), gen.emitMove(result));
+        }
+
+        if (x instanceof InvokeWithExceptionNode) {
+            gen.emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next()));
+        }
+    }
+
+    protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
+
+    protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
+
+    protected static AllocatableValue toStackKind(AllocatableValue value) {
+        if (value.getKind().getStackKind() != value.getKind()) {
+            // We only have stack-kinds in the LIR, so convert the operand kind for values from the
+            // calling convention.
+            if (isRegister(value)) {
+                return asRegister(value).asValue(value.getKind().getStackKind());
+            } else if (isStackSlot(value)) {
+                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection<ValueNode> arguments) {
+        // for each argument, load it into the correct location
+        Value[] result = new Value[arguments.size()];
+        int j = 0;
+        for (ValueNode arg : arguments) {
+            if (arg != null) {
+                AllocatableValue operand = toStackKind(invokeCc.getArgument(j));
+                gen.emitMove(operand, operand(arg));
+                result[j] = operand;
+                j++;
+            } else {
+                throw GraalInternalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types...");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * This method tries to create a switch implementation that is optimal for the given switch. It
+     * will either generate a sequential if/then/else cascade, a set of range tests or a table
+     * switch.
+     *
+     * If the given switch does not contain int keys, it will always create a sequential
+     * implementation.
+     */
+    @Override
+    public void emitSwitch(SwitchNode x) {
+        assert x.defaultSuccessor() != null;
+        LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor());
+        int keyCount = x.keyCount();
+        if (keyCount == 0) {
+            gen.emitJump(defaultTarget);
+        } else {
+            Variable value = gen.load(operand(x.value()));
+            if (keyCount == 1) {
+                assert defaultTarget != null;
+                double probability = x.probability(x.keySuccessor(0));
+                gen.emitCompareBranch(gen.load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability);
+            } else {
+                LabelRef[] keyTargets = new LabelRef[keyCount];
+                Constant[] keyConstants = new Constant[keyCount];
+                double[] keyProbabilities = new double[keyCount];
+                for (int i = 0; i < keyCount; i++) {
+                    keyTargets[i] = getLIRBlock(x.keySuccessor(i));
+                    keyConstants[i] = x.keyAt(i);
+                    keyProbabilities[i] = x.keyProbability(i);
+                }
+                if (value.getKind() != Kind.Int || !x.isSorted()) {
+                    // hopefully only a few entries
+                    gen.emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget);
+                } else {
+                    gen.emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value);
+                }
+            }
+        }
+    }
+
+    public final NodeMap<Value> getNodeOperands() {
+        assert nodeOperands != null;
+        return nodeOperands;
+    }
+
+    public DebugInfoBuilder getDebugInfoBuilder() {
+        assert debugInfoBuilder != null;
+        return debugInfoBuilder;
+    }
+
+    public void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, double probability) {
+        gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), probability);
+    }
+
+    public final void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) {
+        gen.emitArrayEquals(kind, result, array1, array2, length);
+    }
+
+    public final Variable newVariable(Kind i) {
+        return gen.newVariable(i);
+    }
+
+    public final void emitBitCount(Variable result, Value operand) {
+        gen.emitBitCount(result, operand);
+    }
+
+    public final void emitBitScanForward(Variable result, Value operand) {
+        gen.emitBitScanForward(result, operand);
+    }
+
+    final void emitBitScanReverse(Variable result, Value operand) {
+        gen.emitBitScanReverse(result, operand);
+    }
+
+    @Override
+    public LIRGenerator getLIRGeneratorTool() {
+        return gen;
+    }
+
+    public LIRGenerator getLIRGenerator() {
+        return gen;
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Sun Mar 30 16:08:33 2014 +0200
@@ -25,15 +25,29 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class LowTier extends PhaseSuite<LowTierContext> {
 
+    static class Options {
+
+        // @formatter:off
+        @Option(help = "")
+        public static final OptionValue<Boolean> ProfileCompiledMethods = new OptionValue<>(false);
+        // @formatter:on
+
+    }
+
     public LowTier() {
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
 
+        if (Options.ProfileCompiledMethods.getValue()) {
+            appendPhase(new ProfileCompiledMethodsPhase());
+        }
+
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
 
         appendPhase(new RemoveValueProxyPhase());
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Sun Mar 30 16:08:33 2014 +0200
@@ -65,7 +65,11 @@
 
     public abstract FrameMap newFrameMap();
 
-    public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir);
+    public abstract LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
+
+    public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub);
+
+    public abstract NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen);
 
     /**
      * Creates the assembler used to emit the machine code.
@@ -75,7 +79,7 @@
     /**
      * Creates the object used to fill in the details of a given compilation result.
      */
-    public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory);
+    public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, CompilationResult compilationResult, CompilationResultBuilderFactory factory);
 
     public abstract boolean shouldAllocateRegisters();
 
@@ -87,4 +91,5 @@
      *            argument can be null.
      */
     public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner);
+
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java	Sun Mar 30 16:08:33 2014 +0200
@@ -32,5 +32,5 @@
  */
 public interface LIRGenLowerable {
 
-    void generate(LIRGenerator generator);
+    void generate(NodeLIRGenerator generator);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.target;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
+ * {@link LIRGenerationResult} and {@link LIRInstruction}.
+ */
+public interface LIRGenResLowerable {
+
+    void generate(NodeLIRGeneratorTool generator, LIRGenerationResult genRes);
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.debug;
 
 import static com.oracle.graal.debug.Debug.Initialization.*;
+import static java.util.FormattableFlags.*;
 
 import java.io.*;
 import java.util.*;
@@ -129,7 +130,7 @@
 
     /**
      * Gets a string composed of the names in the current nesting of debug
-     * {@linkplain #scope(String, Object...) scopes} separated by {@code '.'}.
+     * {@linkplain #scope(Object) scopes} separated by {@code '.'}.
      */
     public static String currentScope() {
         if (ENABLED) {
@@ -140,7 +141,7 @@
     }
 
     /**
-     * Represents a debug scope entered by {@link Debug#scope(String, Object...)} or
+     * Represents a debug scope entered by {@link Debug#scope(Object)} or
      * {@link Debug#sandbox(String, DebugConfig, Object...)}. Leaving the scope is achieved via
      * {@link #close()}.
      */
@@ -153,7 +154,7 @@
      * <p>
      * It is recommended to use the try-with-resource statement for managing entering and leaving
      * debug scopes. For example:
-     * 
+     *
      * <pre>
      * try (Scope s = Debug.scope(&quot;InliningGraph&quot;, inlineeGraph)) {
      *     ...
@@ -161,15 +162,68 @@
      *     throw Debug.handle(e);
      * }
      * </pre>
-     * 
+     *
+     * The {@code name} argument is subject to the following type based conversion before having
+     * {@link Object#toString()} called on it:
+     *
+     * <pre>
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * </pre>
+     *
      * @param name the name of the new scope
-     * @param context objects to be appended to the {@linkplain #context() current} debug context
      * @return the scope entered by this method which will be exited when its {@link Scope#close()}
      *         method is called
      */
-    public static Scope scope(CharSequence name, Object... context) {
+    public static Scope scope(Object name) {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @see #scope(Object)
+     * @param context an object to be appended to the {@linkplain #context() current} debug context
+     */
+    public static Scope scope(Object name, Object context) {
         if (ENABLED) {
-            return DebugScope.getInstance().scope(name, null, context);
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @see #scope(Object)
+     * @param context1 first object to be appended to the {@linkplain #context() current} debug
+     *            context
+     * @param context2 second object to be appended to the {@linkplain #context() current} debug
+     *            context
+     */
+    public static Scope scope(Object name, Object context1, Object context2) {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @see #scope(Object)
+     * @param context1 first object to be appended to the {@linkplain #context() current} debug
+     *            context
+     * @param context2 second object to be appended to the {@linkplain #context() current} debug
+     *            context
+     * @param context3 third object to be appended to the {@linkplain #context() current} debug
+     *            context
+     */
+    public static Scope scope(Object name, Object context1, Object context2, Object context3) {
+        if (ENABLED) {
+            return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2, context3);
         } else {
             return null;
         }
@@ -180,7 +234,7 @@
      * <p>
      * It is recommended to use the try-with-resource statement for managing entering and leaving
      * debug scopes. For example:
-     * 
+     *
      * <pre>
      * try (Scope s = Debug.sandbox(&quot;CompilingStub&quot;, null, stubGraph)) {
      *     ...
@@ -188,7 +242,7 @@
      *     throw Debug.handle(e);
      * }
      * </pre>
-     * 
+     *
      * @param name the name of the new scope
      * @param config the debug configuration to use for the new scope
      * @param context objects to be appended to the {@linkplain #context() current} debug context
@@ -221,10 +275,10 @@
     /**
      * Handles an exception in the context of the debug scope just exited. The just exited scope
      * must have the current scope as its parent which will be the case if the try-with-resource
-     * pattern recommended by {@link #scope(String, Object...)} and
+     * pattern recommended by {@link #scope(Object)} and
      * {@link #sandbox(String, DebugConfig, Object...)} is used
-     * 
-     * @see #scope(String, Object...)
+     *
+     * @see #scope(Object)
      * @see #sandbox(String, DebugConfig, Object...)
      */
     public static RuntimeException handle(Throwable exception) {
@@ -242,92 +296,232 @@
     }
 
     /**
-     * Prints an indented message to the current debug scopes's logging stream if logging is enabled
-     * in the scope.
-     * 
-     * @param msg The format string of the log message
-     * @param args The arguments referenced by the log message string
-     * @see Indent#log
+     * Prints a message to the current debug scope's logging stream if logging is enabled.
+     *
+     * @param msg the message to log
+     */
+    public static void log(String msg) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(msg);
+        }
+    }
+
+    /**
+     * Prints a message to the current debug scope's logging stream if logging is enabled.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     */
+    public static void log(String format, Object arg) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(format, arg);
+        }
+    }
+
+    /**
+     * @see #log(String, Object)
      */
-    public static void log(String msg, Object... args) {
+    public static void log(String format, Object arg1, Object arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(format, arg1, arg2);
+        }
+    }
+
+    /**
+     * @see #log(String, Object)
+     */
+    public static void log(String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(format, arg1, arg2, arg3);
+        }
+    }
+
+    /**
+     * @see #log(String, Object)
+     */
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
         if (ENABLED) {
-            DebugScope.getInstance().log(msg, args);
+            DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4);
+        }
+    }
+
+    /**
+     * @see #log(String, Object)
+     */
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4, arg5);
+        }
+    }
+
+    /**
+     * @see #log(String, Object)
+     */
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4, arg5, arg6);
         }
     }
 
     /**
-     * The same as {@link #log}, but without line termination and without indentation.
+     * Prints a message to the current debug scope's logging stream. This method must only be called
+     * if debugging is {@linkplain Debug#isEnabled() enabled} as it incurs allocation at the call
+     * site. If possible, call one of the other {@code log()} methods in this class that take a
+     * fixed number of parameters.
+     *
+     * @param format a format string
+     * @param args the arguments referenced by the format specifiers in {@code format}
      */
-    public static void printf(String msg, Object... args) {
-        if (ENABLED && DebugScope.getInstance().isLogEnabled()) {
-            DebugScope.getInstance().printf(msg, args);
+    public static void logv(String format, Object... args) {
+        if (!ENABLED) {
+            throw new InternalError("Use of Debug.logv() must be guarded by a test of Debug.isEnabled()");
         }
+        DebugScope.getInstance().log(format, args);
     }
 
-    public static void dump(Object object, String msg, Object... args) {
+    /**
+     * This override exists to catch cases when {@link #log(String, Object)} is called with one
+     * argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void log(String format, Object[] args) {
+        assert false : "shouldn't use this";
+        logv(format, args);
+    }
+
+    public static void dump(Object object, String msg) {
         if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
-            DebugScope.getInstance().dump(object, msg, args);
+            DebugScope.getInstance().dump(object, msg);
         }
     }
 
-    private static final class NoLogger implements Indent {
-
-        @Override
-        public void log(String msg, Object... args) {
+    public static void dump(Object object, String format, Object arg) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
+            DebugScope.getInstance().dump(object, format, arg);
         }
-
-        @Override
-        public Indent indent() {
-            return this;
-        }
+    }
 
-        @Override
-        public Indent logAndIndent(String msg, Object... args) {
-            return this;
+    public static void dump(Object object, String format, Object arg1, Object arg2) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
+            DebugScope.getInstance().dump(object, format, arg1, arg2);
         }
+    }
 
-        @Override
-        public Indent outdent() {
-            return this;
-        }
-
-        @Override
-        public void close() {
+    public static void dump(Object object, String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
+            DebugScope.getInstance().dump(object, format, arg1, arg2, arg3);
         }
     }
 
-    private static final NoLogger noLoggerInstance = new NoLogger();
+    /**
+     * This override exists to catch cases when {@link #dump(Object, String, Object)} is called with
+     * one argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void dump(Object object, String format, Object[] args) {
+        assert false : "shouldn't use this";
+        if (ENABLED && DebugScope.getInstance().isDumpEnabled()) {
+            DebugScope.getInstance().dump(object, format, args);
+        }
+    }
 
     /**
-     * Creates a new indentation level (by adding some spaces) based on the last used Indent of the
-     * current DebugScope.
-     * 
-     * @return The new indentation level
-     * @see Indent#indent
+     * Opens a new indentation level (by adding some spaces) based on the current indentation level.
+     * This should be used in a {@linkplain Indent try-with-resources} pattern.
+     *
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     * @see #logAndIndent(String)
+     * @see #logAndIndent(String, Object)
      */
     public static Indent indent() {
         if (ENABLED) {
             DebugScope scope = DebugScope.getInstance();
             return scope.pushIndentLogger();
         }
-        return noLoggerInstance;
+        return null;
+    }
+
+    /**
+     * A convenience function which combines {@link #log(String)} and {@link #indent()}.
+     *
+     * @param msg the message to log
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logAndIndent(String msg) {
+        if (ENABLED) {
+            return logvAndIndent(msg);
+        }
+        return null;
+    }
+
+    /**
+     * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logAndIndent(String format, Object arg) {
+        if (ENABLED) {
+            return logvAndIndent(format, arg);
+        }
+        return null;
     }
 
     /**
-     * A convenience function which combines {@link #log} and {@link #indent()}.
-     * 
-     * @param msg The format string of the log message
-     * @param args The arguments referenced by the log message string
-     * @return The new indentation level
-     * @see Indent#logAndIndent
+     * @see #logAndIndent(String, Object)
+     */
+    public static Indent logAndIndent(String format, Object arg1, Object arg2) {
+        if (ENABLED) {
+            return logvAndIndent(format, arg1, arg2);
+        }
+        return null;
+    }
+
+    /**
+     * @see #logAndIndent(String, Object)
      */
-    public static Indent logAndIndent(String msg, Object... args) {
+    public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) {
+        if (ENABLED) {
+            return logvAndIndent(format, arg1, arg2, arg3);
+        }
+        return null;
+    }
+
+    /**
+     * A convenience function which combines {@link #logv(String, Object...)} and {@link #indent()}.
+     *
+     * @param format a format string
+     * @param args the arguments referenced by the format specifiers in {@code format}
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logvAndIndent(String format, Object... args) {
         if (ENABLED) {
             DebugScope scope = DebugScope.getInstance();
-            scope.log(msg, args);
+            scope.log(format, args);
             return scope.pushIndentLogger();
         }
-        return noLoggerInstance;
+        throw new InternalError("Use of Debug.logvAndIndent() must be guarded by a test of Debug.isEnabled()");
+    }
+
+    /**
+     * This override exists to catch cases when {@link #logAndIndent(String, Object)} is called with
+     * one argument bound to a varargs method parameter. It will bind to this method instead of the
+     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * Object[] inside of another Object[].
+     */
+    @Deprecated
+    public static void logAndIndent(String format, Object[] args) {
+        assert false : "shouldn't use this";
+        logvAndIndent(format, args);
     }
 
     public static Iterable<Object> context() {
@@ -380,18 +574,91 @@
      * A disabled metric has virtually no overhead.
      */
     public static DebugMetric metric(CharSequence name) {
-        if (enabledMetrics != null && enabledMetrics.contains(name.toString())) {
-            return new MetricImpl(name.toString(), false);
-        } else if (ENABLED) {
-            return new MetricImpl(name.toString(), true);
-        } else {
+        if (enabledMetrics == null && !ENABLED) {
             return VOID_METRIC;
         }
+        return createMetric("%s", name, null);
+    }
+
+    public static String applyFormattingFlagsAndWidth(String s, int flags, int width) {
+        if (flags == 0 && width < 0) {
+            return s;
+        }
+        StringBuilder sb = new StringBuilder(s);
+
+        // apply width and justification
+        int len = sb.length();
+        if (len < width) {
+            for (int i = 0; i < width - len; i++) {
+                if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) {
+                    sb.append(' ');
+                } else {
+                    sb.insert(0, ' ');
+                }
+            }
+        }
+
+        String res = sb.toString();
+        if ((flags & UPPERCASE) == UPPERCASE) {
+            res = res.toUpperCase();
+        }
+        return res;
+    }
+
+    /**
+     * Creates a debug metric. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.metric(format, arg, null)
+     * </pre>
+     *
+     * except that the string formatting only happens if metering is enabled.
+     *
+     * @see #metric(String, Object, Object)
+     */
+    public static DebugMetric metric(String format, Object arg) {
+        if (enabledMetrics == null && !ENABLED) {
+            return VOID_METRIC;
+        }
+        return createMetric(format, arg, null);
+    }
+
+    /**
+     * Creates a debug metric. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.metric(String.format(format, arg1, arg2))
+     * </pre>
+     *
+     * except that the string formatting only happens if metering is enabled. In addition, each
+     * argument is subject to the following type based conversion before being passed as an argument
+     * to {@link String#format(String, Object...)}:
+     *
+     * <pre>
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * </pre>
+     *
+     * @see #metric(CharSequence)
+     */
+    public static DebugMetric metric(String format, Object arg1, Object arg2) {
+        if (enabledMetrics == null && !ENABLED) {
+            return VOID_METRIC;
+        }
+        return createMetric(format, arg1, arg2);
+    }
+
+    private static DebugMetric createMetric(String format, Object arg1, Object arg2) {
+        String name = formatDebugName(format, arg1, arg2);
+        boolean conditional = enabledMetrics != null && enabledMetrics.contains(name);
+        return new MetricImpl(name, conditional);
     }
 
     /**
      * Changes the debug configuration for the current thread.
-     * 
+     *
      * @param config new configuration to use for the current thread
      * @return an object that when {@linkplain DebugConfigScope#close() closed} will restore the
      *         debug configuration for the current thread to what it was before this method was
@@ -533,13 +800,72 @@
      * A disabled timer has virtually no overhead.
      */
     public static DebugTimer timer(CharSequence name) {
-        if (enabledTimers != null && enabledTimers.contains(name.toString())) {
-            return new TimerImpl(name.toString(), false);
-        } else if (ENABLED) {
-            return new TimerImpl(name.toString(), true);
-        } else {
+        if (enabledTimers == null && !ENABLED) {
+            return VOID_TIMER;
+        }
+        return createTimer("%s", name, null);
+    }
+
+    /**
+     * Creates a debug timer. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.timer(format, arg, null)
+     * </pre>
+     *
+     * except that the string formatting only happens if timing is enabled.
+     *
+     * @see #timer(String, Object, Object)
+     */
+    public static DebugTimer timer(String format, Object arg) {
+        if (enabledTimers == null && !ENABLED) {
             return VOID_TIMER;
         }
+        return createTimer(format, arg, null);
+    }
+
+    /**
+     * Creates a debug timer. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.timer(String.format(format, arg1, arg2))
+     * </pre>
+     *
+     * except that the string formatting only happens if timing is enabled. In addition, each
+     * argument is subject to the following type based conversion before being passed as an argument
+     * to {@link String#format(String, Object...)}:
+     *
+     * <pre>
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * </pre>
+     *
+     * @see #timer(CharSequence)
+     */
+    public static DebugTimer timer(String format, Object arg1, Object arg2) {
+        if (enabledTimers == null && !ENABLED) {
+            return VOID_TIMER;
+        }
+        return createTimer(format, arg1, arg2);
+    }
+
+    public static Object convertFormatArg(Object arg) {
+        if (arg instanceof Class) {
+            return ((Class) arg).getSimpleName();
+        }
+        return arg;
+    }
+
+    private static String formatDebugName(String format, Object arg1, Object arg2) {
+        return String.format(format, convertFormatArg(arg1), convertFormatArg(arg2));
+    }
+
+    private static DebugTimer createTimer(String format, Object arg1, Object arg2) {
+        String name = formatDebugName(format, arg1, arg2);
+        boolean conditional = enabledTimers != null && enabledTimers.contains(name);
+        return new TimerImpl(name, conditional);
     }
 
     private static final DebugTimer VOID_TIMER = new DebugTimer() {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Sun Mar 30 16:08:33 2014 +0200
@@ -28,10 +28,7 @@
 public interface DebugConfig {
 
     /**
-     * Determines if logging is enabled in the {@linkplain Debug#currentScope() current debug scope}
-     * .
-     * 
-     * @see Debug#log(String, Object...)
+     * Determines if logging is on in the {@linkplain Debug#currentScope() current debug scope} .
      */
     boolean isLogEnabled();
 
@@ -44,7 +41,7 @@
     /**
      * Determines if metering is enabled in the {@linkplain Debug#currentScope() current debug
      * scope}.
-     * 
+     *
      * @see Debug#metric(CharSequence)
      */
     boolean isMeterEnabled();
@@ -52,8 +49,8 @@
     /**
      * Determines if dumping is enabled in the {@linkplain Debug#currentScope() current debug scope}
      * .
-     * 
-     * @see Debug#dump(Object, String, Object...)
+     *
+     * @see Debug#dump(Object, String)
      */
     boolean isDumpEnabled();
 
@@ -70,7 +67,7 @@
 
     /**
      * Removes an object the context used by this configuration to do filtering.
-     * 
+     *
      * This should only removes extra context added by {@link #addToContext(Object)}.
      */
     void removeFromContext(Object o);
@@ -82,7 +79,7 @@
 
     /**
      * Handles notification of an exception occurring within a debug scope.
-     * 
+     *
      * @return the exception object that is to be propagated to parent scope. A value of
      *         {@code null} indicates that {@code e} is to be propagated.
      */
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,80 +23,29 @@
 package com.oracle.graal.debug;
 
 /**
- * Represents an indentation level for logging.
- * <p>
- * Note that calling the logging/indent/outdent methods of this interface updates the last used
- * Indent of the current DebugScope. If no instance of Indent is available (e.g. at the beginning of
- * a method), then the corresponding static methods of the Debug class should be used. They perform
- * logging and indentation based on the last used Indent of the current DebugScope.
+ * Object used to close a debug {@link Debug#indent() indentation} scope.
  * <p>
  * Example usage:
- * 
+ *
  * <pre>
- *      void method() {
- *      
- *          Indent in = Debug.logIndent("header message");
+ *
+ *      try (Indent i1 = Debug.logAndIndent("header message")) {
  *          ...
- *          in.log("message");
- *          ...
- *          Indent in2 = in.logIndent("sub-header message");
- *          ...
- *          {
- *              in2.log("inner message");
- *          }
+ *          Debug.log("message");
  *          ...
- *          in.outdent();
+ *          try (Indent i2 = Debug.logAndIndent(sub-header message")) {
+ *              ...
+ *              Debug.log("inner message");
+ *              ...
+ *          }
  *      }
- * </pre>
- * 
- * Example usage with try-with-resources:
- * 
- * <pre>
- * 
- *      try (Indent in = Debug.logIndent("header message")) {
- *          ...
- *          in.log("message");
- *          ...
- *      }
- * 
+ *
  * </pre>
  */
 public interface Indent extends AutoCloseable {
 
     /**
-     * Prints an indented message to the DebugLevel's logging stream if logging is enabled.
-     * 
-     * @param msg The format string of the log message
-     * @param args The arguments referenced by the log message string
-     * @see Debug#log
-     */
-    void log(String msg, Object... args);
-
-    /**
-     * Creates a new indentation level (by adding some spaces).
-     * 
-     * @return The new indentation level
-     * @see Debug#indent
+     * Closes the current indentation scope.
      */
-    Indent indent();
-
-    /**
-     * A convenience function which combines {@link #log} and {@link #indent}.
-     * 
-     * @param msg The format string of the log message
-     * @param args The arguments referenced by the log message string
-     * @return The new indentation level
-     * @see Debug#logAndIndent
-     */
-    Indent logAndIndent(String msg, Object... args);
-
-    /**
-     * Restores the previous indent level. Calling this method is important to restore the correct
-     * last used Indent in the current DebugScope.
-     * 
-     * @return The indent level from which this Indent was created.
-     */
-    Indent outdent();
-
     void close();
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Sun Mar 30 16:08:33 2014 +0200
@@ -52,7 +52,6 @@
             }
         }
 
-        @Override
         public void log(String msg, Object... args) {
             if (isLogEnabled()) {
                 printScopeName();
@@ -61,29 +60,16 @@
             }
         }
 
-        @Override
-        public Indent indent() {
+        IndentImpl indent() {
             lastUsedIndent = new IndentImpl(this);
             return lastUsedIndent;
         }
 
         @Override
-        public Indent logAndIndent(String msg, Object... args) {
-            log(msg, args);
-            return indent();
-        }
-
-        @Override
-        public Indent outdent() {
+        public void close() {
             if (parentIndent != null) {
                 lastUsedIndent = parentIndent;
             }
-            return lastUsedIndent;
-        }
-
-        @Override
-        public void close() {
-            outdent();
         }
     }
 
@@ -194,7 +180,7 @@
         }
     }
 
-    public void dump(Object object, String formatString, Object[] args) {
+    public void dump(Object object, String formatString, Object... args) {
         if (isDumpEnabled()) {
             DebugConfig config = getConfig();
             if (config != null) {
@@ -209,7 +195,7 @@
     /**
      * This method exists mainly to allow a debugger (e.g., Eclipse) to force dump a graph.
      */
-    public static void dump(Object object, String message) {
+    public static void forceDump(Object object, String message) {
         DebugConfig config = getConfig();
         if (config != null) {
             for (DebugDumpHandler dumpHandler : config.dumpHandlers()) {
@@ -224,7 +210,7 @@
     /**
      * Creates and enters a new debug scope which is either a child of the current scope or a
      * disjoint top level scope.
-     * 
+     *
      * @param name the name of the new scope
      * @param sandboxConfig the configuration to use for a new top level scope, or null if the new
      *            scope should be a child scope
@@ -387,7 +373,7 @@
     }
 
     public Indent pushIndentLogger() {
-        lastUsedIndent = (IndentImpl) lastUsedIndent.indent();
+        lastUsedIndent = lastUsedIndent.indent();
         return lastUsedIndent;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2009, 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.gpu;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Represents the output from compiling a method generated by Graal, but executing in a memory and
+ * computational subsystem outside the Graal host system.
+ * 
+ * Output may include the compiled machine code, associated data and references, relocation
+ * information, deoptimization information, as this result is generated from a structure graph on
+ * the Graal host system.
+ */
+public class ExternalCompilationResult extends CompilationResult {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Address of the point of entry to the external compilation result.
+     */
+    private long entryPoint;
+    private StructuredGraph hostGraph;
+
+    /**
+     * Set the address for the point of entry to the external compilation result.
+     * 
+     * @param addr the address of the entry point
+     */
+    public void setEntryPoint(long addr) {
+        entryPoint = addr;
+    }
+
+    /**
+     * Return the address for the point of entry to the external compilation result.
+     * 
+     * @return address value
+     */
+    public long getEntryPoint() {
+        return entryPoint;
+    }
+
+    /**
+     * Gets the {@linkplain #getTargetCode() code} in this compilation result as a string.
+     */
+    public String getCodeString() {
+        return new String(getTargetCode(), 0, getTargetCodeSize());
+    }
+
+    public void setHostGraph(StructuredGraph hostGraph) {
+        this.hostGraph = hostGraph;
+    }
+
+    public StructuredGraph getHostGraph() {
+        return hostGraph;
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Sun Mar 30 16:08:33 2014 +0200
@@ -234,7 +234,7 @@
         }
 
         isLeafNode = (this.inputOffsets.length == 0 && this.successorOffsets.length == 0);
-        nodeIterableCount = Debug.metric("NodeIterable_" + shortName);
+        nodeIterableCount = Debug.metric("NodeIterable_%s", shortName);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Sun Mar 30 16:08:33 2014 +0200
@@ -72,8 +72,18 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        return new AMD64HotSpotLIRGenerator(graph, stub, getProviders(), getRuntime().getConfig(), frameMap, cc, lir);
+    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+        return new AMD64HotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
+    }
+
+    @Override
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        return new AMD64HotSpotLIRGenerationResult(lir, frameMap, stub);
+    }
+
+    @Override
+    public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        return new AMD64HotSpotNodeLIRGenerator(graph, lirGenRes, lirGen);
     }
 
     /**
@@ -192,17 +202,17 @@
     }
 
     @Override
-    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
         // Omit the frame if the method:
         // - has no spill slots or other slots allocated during register allocation
         // - has no callee-saved registers
         // - has no incoming arguments passed on the stack
         // - has no deoptimization points
         // - makes no foreign calls (which require an aligned stack)
-        AMD64HotSpotLIRGenerator gen = (AMD64HotSpotLIRGenerator) lirGen;
-        FrameMap frameMap = gen.frameMap;
-        LIR lir = gen.lir;
-        assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+        AMD64HotSpotLIRGenerationResult gen = (AMD64HotSpotLIRGenerationResult) lirGenRen;
+        FrameMap frameMap = gen.getFrameMap();
+        LIR lir = gen.getLIR();
+        assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
         boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall();
 
         Stub stub = gen.getStub();
@@ -210,14 +220,14 @@
         HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null, omitFrame);
         CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
         crb.setFrameSize(frameMap.frameSize());
-        StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot;
+        StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
         if (deoptimizationRescueSlot != null && stub == null) {
             crb.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
         }
 
         if (stub != null) {
             Set<Register> definedRegisters = gatherDefinedRegisters(lir);
-            updateStub(stub, definedRegisters, gen.calleeSaveInfo, frameMap);
+            updateStub(stub, definedRegisters, gen.getCalleeSaveInfo(), frameMap);
         }
 
         return crb;
@@ -318,4 +328,5 @@
         };
         return new HotSpotNativeFunctionInterface(getProviders(), factory, this, config.dllLoad, config.dllLookup, config.rtldDefault);
     }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+
+public class AMD64HotSpotLIRGenerationResult extends LIRGenerationResultBase {
+
+    /**
+     * The slot reserved for storing the original return address when a frame is marked for
+     * deoptimization. The return address slot in the callee is overwritten with the address of a
+     * deoptimization stub.
+     */
+    private StackSlot deoptimizationRescueSlot;
+    private final Object stub;
+
+    /**
+     * Map from debug infos that need to be updated with callee save information to the operations
+     * that provide the information.
+     */
+    private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = new HashMap<>();
+
+    public AMD64HotSpotLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        super(lir, frameMap);
+        this.stub = stub;
+    }
+
+    StackSlot getDeoptimizationRescueSlot() {
+        return deoptimizationRescueSlot;
+    }
+
+    public final void setDeoptimizationRescueSlot(StackSlot deoptimizationRescueSlot) {
+        this.deoptimizationRescueSlot = deoptimizationRescueSlot;
+    }
+
+    Stub getStub() {
+        return (Stub) stub;
+    }
+
+    Map<LIRFrameState, SaveRegistersOp> getCalleeSaveInfo() {
+        return calleeSaveInfo;
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,60 +24,45 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.CompareAndSwapCompressedOp;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.LoadCompressedPointer;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedConstantOp;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedPointer;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.NoOp;
-import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
-import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
+import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
  */
 public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
 
-    private final HotSpotVMConfig config;
+    final HotSpotVMConfig config;
 
-    private final Object stub;
-
-    protected AMD64HotSpotLIRGenerator(StructuredGraph graph, Object stub, HotSpotProviders providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
+    protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
         assert config.basicLockSize == 8;
         this.config = config;
-        this.stub = stub;
     }
 
     @Override
@@ -86,13 +71,6 @@
     }
 
     /**
-     * The slot reserved for storing the original return address when a frame is marked for
-     * deoptimization. The return address slot in the callee is overwritten with the address of a
-     * deoptimization stub.
-     */
-    StackSlot deoptimizationRescueSlot;
-
-    /**
      * Utility for emitting the instruction to save RBP.
      */
     class SaveRbp {
@@ -106,13 +84,13 @@
 
         public SaveRbp(NoOp placeholder) {
             this.placeholder = placeholder;
-            this.reservedSlot = frameMap.allocateSpillSlot(Kind.Long);
+            this.reservedSlot = res.getFrameMap().allocateSpillSlot(Kind.Long);
             assert reservedSlot.getRawOffset() == -16 : reservedSlot.getRawOffset();
         }
 
         /**
          * Replaces this operation with the appropriate move for saving rbp.
-         * 
+         *
          * @param useStack specifies if rbp must be saved to the stack
          */
         public AllocatableValue finalize(boolean useStack) {
@@ -120,16 +98,16 @@
             if (useStack) {
                 dst = reservedSlot;
             } else {
-                frameMap.freeSpillSlot(reservedSlot);
+                res.getFrameMap().freeSpillSlot(reservedSlot);
                 dst = newVariable(Kind.Long);
             }
 
-            placeholder.replace(lir, new MoveFromRegOp(dst, rbp.asValue(Kind.Long)));
+            placeholder.replace(res.getLIR(), new MoveFromRegOp(dst, rbp.asValue(Kind.Long)));
             return dst;
         }
     }
 
-    private SaveRbp saveRbp;
+    SaveRbp saveRbp;
 
     /**
      * List of epilogue operations that need to restore RBP.
@@ -144,45 +122,9 @@
         }
     }
 
-    @SuppressWarnings("hiding")
-    @Override
-    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
-        HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long);
-        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
-    }
-
     @Override
     public StackSlot getLockSlot(int lockDepth) {
-        return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth);
-    }
-
-    @Override
-    protected void emitPrologue(StructuredGraph graph) {
-
-        CallingConvention incomingArguments = cc;
-
-        Value[] params = new Value[incomingArguments.getArgumentCount() + 1];
-        for (int i = 0; i < params.length - 1; i++) {
-            params[i] = toStackKind(incomingArguments.getArgument(i));
-            if (isStackSlot(params[i])) {
-                StackSlot slot = ValueUtil.asStackSlot(params[i]);
-                if (slot.isInCallerFrame() && !lir.hasArgInCallerFrame()) {
-                    lir.setHasArgInCallerFrame();
-                }
-            }
-        }
-        params[params.length - 1] = rbp.asValue(Kind.Long);
-
-        emitIncomingValues(params);
-
-        saveRbp = new SaveRbp(new NoOp(currentBlock, lir.lir(currentBlock).size()));
-        append(saveRbp.placeholder);
-
-        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
-            Value paramValue = params[param.index()];
-            assert paramValue.getKind() == param.kind().getStackKind();
-            setResult(param, emitMove(paramValue));
-        }
+        return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth);
     }
 
     private Register findPollOnReturnScratchRegister() {
@@ -198,7 +140,7 @@
     private Register pollOnReturnScratchRegister;
 
     @Override
-    protected void emitReturn(Value input) {
+    public void emitReturn(Value input) {
         if (pollOnReturnScratchRegister == null) {
             pollOnReturnScratchRegister = findPollOnReturnScratchRegister();
         }
@@ -208,14 +150,13 @@
     @Override
     protected boolean needOnlyOopMaps() {
         // Stubs only need oop maps
-        return stub != null;
+        return ((AMD64HotSpotLIRGenerationResult) res).getStub() != null;
     }
 
-    /**
-     * Map from debug infos that need to be updated with callee save information to the operations
-     * that provide the information.
-     */
-    Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = new HashMap<>();
+    @Override
+    public void emitData(AllocatableValue dst, byte[] data) {
+        append(new LeaDataOp(dst, data));
+    }
 
     private LIRFrameState currentRuntimeCallInfo;
 
@@ -235,8 +176,8 @@
         append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save));
     }
 
-    Stub getStub() {
-        return (Stub) stub;
+    public Stub getStub() {
+        return ((AMD64HotSpotLIRGenerationResult) res).getStub();
     }
 
     @Override
@@ -248,12 +189,12 @@
         if (destroysRegisters) {
             if (getStub() != null) {
                 if (getStub().preservesRegisters()) {
-                    Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters();
+                    Register[] savedRegisters = res.getFrameMap().registerConfig.getAllocatableRegisters();
                     savedRegisterLocations = new StackSlot[savedRegisters.length];
                     for (int i = 0; i < savedRegisters.length; i++) {
                         PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
                         assert kind != Kind.Illegal;
-                        StackSlot spillSlot = frameMap.allocateSpillSlot(kind);
+                        StackSlot spillSlot = res.getFrameMap().allocateSpillSlot(kind);
                         savedRegisterLocations[i] = spillSlot;
                     }
                     save = emitSaveRegisters(savedRegisters, savedRegisterLocations);
@@ -264,7 +205,7 @@
         Variable result;
 
         if (linkage.canDeoptimize()) {
-            assert info != null || stub != null;
+            assert info != null || ((AMD64HotSpotLIRGenerationResult) res).getStub() != null;
             Register thread = getProviders().getRegisters().getThreadRegister();
             append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
             result = super.emitForeignCall(linkage, info, args);
@@ -276,8 +217,8 @@
         if (destroysRegisters) {
             if (getStub() != null) {
                 if (getStub().preservesRegisters()) {
-                    assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
-                    calleeSaveInfo.put(currentRuntimeCallInfo, save);
+                    assert !((AMD64HotSpotLIRGenerationResult) res).getCalleeSaveInfo().containsKey(currentRuntimeCallInfo);
+                    ((AMD64HotSpotLIRGenerationResult) res).getCalleeSaveInfo().put(currentRuntimeCallInfo, save);
 
                     emitRestoreRegisters(save);
                 } else {
@@ -296,53 +237,18 @@
     }
 
     protected boolean zapRegisters() {
-        Register[] zappedRegisters = frameMap.registerConfig.getAllocatableRegisters();
+        Register[] zappedRegisters = res.getFrameMap().registerConfig.getAllocatableRegisters();
         Constant[] zapValues = new Constant[zappedRegisters.length];
         for (int i = 0; i < zappedRegisters.length; i++) {
             PlatformKind kind = target().arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory());
             assert kind != Kind.Illegal;
             zapValues[i] = zapValueForKind(kind);
         }
-        calleeSaveInfo.put(currentRuntimeCallInfo, emitZapRegisters(zappedRegisters, zapValues));
+        ((AMD64HotSpotLIRGenerationResult) res).getCalleeSaveInfo().put(currentRuntimeCallInfo, emitZapRegisters(zappedRegisters, zapValues));
         return true;
     }
 
     @Override
-    public void visitSafepointNode(SafepointNode i) {
-        LIRFrameState info = state(i);
-        append(new AMD64HotSpotSafepointOp(info, config, this));
-    }
-
-    @SuppressWarnings("hiding")
-    @Override
-    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
-        Kind kind = x.newValue().kind();
-        assert kind == x.expectedValue().kind();
-
-        Value expected = loadNonConst(operand(x.expectedValue()));
-        Variable newVal = load(operand(x.newValue()));
-
-        int disp = 0;
-        AMD64AddressValue address;
-        Value index = operand(x.offset());
-        if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) {
-            assert !getCodeCache().needsDataPatch(asConstant(index));
-            disp += (int) ValueUtil.asConstant(index).asLong();
-            address = new AMD64AddressValue(kind, load(operand(x.object())), disp);
-        } else {
-            address = new AMD64AddressValue(kind, load(operand(x.object())), load(index), Scale.Times1, disp);
-        }
-
-        RegisterValue rax = AMD64.rax.asValue(kind);
-        emitMove(rax, expected);
-        append(new CompareAndSwapOp(rax, address, rax, newVal));
-
-        Variable result = newVariable(x.kind());
-        emitMove(result, rax);
-        setResult(x, result);
-    }
-
-    @Override
     public void emitTailcall(Value[] args, Value address) {
         append(new AMD64TailcallOp(args, address));
     }
@@ -350,7 +256,7 @@
     @Override
     public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) {
         Value[] argLocations = new Value[args.length];
-        frameMap.callsMethod(nativeCallingConvention);
+        res.getFrameMap().callsMethod(nativeCallingConvention);
         // TODO(mg): in case a native function uses floating point varargs, the ABI requires that
         // RAX contains the length of the varargs
         AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue();
@@ -366,33 +272,6 @@
     }
 
     @Override
-    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
-        if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
-            append(new AMD64HotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
-        } else {
-            assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
-            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
-            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
-            Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant();
-            append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod));
-        }
-    }
-
-    @Override
-    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        if (callTarget instanceof HotSpotIndirectCallTargetNode) {
-            AllocatableValue metaspaceMethod = AMD64.rbx.asValue();
-            emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
-            AllocatableValue targetAddress = AMD64.rax.asValue();
-            emitMove(targetAddress, operand(callTarget.computedAddress()));
-            append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
-        } else {
-            super.emitIndirectCall(callTarget, result, parameters, temps, callState);
-        }
-    }
-
-    @Override
     public void emitUnwind(Value exception) {
         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
         CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
@@ -427,32 +306,12 @@
     }
 
     @Override
-    public void emitPatchReturnAddress(ValueNode address) {
-        append(new AMD64HotSpotPatchReturnAddressOp(load(operand(address))));
-    }
-
-    @Override
-    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
-        Variable handler = load(operand(handlerInCallerPc));
-        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
-        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
-        assert outgoingCc.getArgumentCount() == 2;
-        RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0);
-        RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1);
-        emitMove(exceptionFixed, operand(exception));
-        emitMove(exceptionPcFixed, operand(exceptionPc));
-        Register thread = getProviders().getRegisters().getThreadRegister();
-        AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, config.threadIsMethodHandleReturnOffset, thread);
-        append(op);
-    }
-
-    @Override
     public void beforeRegisterAllocation() {
         super.beforeRegisterAllocation();
-        boolean hasDebugInfo = lir.hasDebugInfo();
+        boolean hasDebugInfo = res.getLIR().hasDebugInfo();
         AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
         if (hasDebugInfo) {
-            deoptimizationRescueSlot = frameMap.allocateSpillSlot(Kind.Long);
+            ((AMD64HotSpotLIRGenerationResult) res).setDeoptimizationRescueSlot(res.getFrameMap().allocateSpillSlot(Kind.Long));
         }
 
         for (AMD64HotSpotEpilogueOp op : epilogueOps) {
@@ -560,38 +419,4 @@
         }
     }
 
-    @Override
-    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
-        Kind kind = node.getNewValue().kind();
-        assert kind == node.getExpectedValue().kind();
-        Value expected = loadNonConst(operand(node.getExpectedValue()));
-        Variable newValue = load(operand(node.getNewValue()));
-        AMD64AddressValue addressValue = asAddressValue(address);
-        RegisterValue raxRes = AMD64.rax.asValue(kind);
-        emitMove(raxRes, expected);
-        if (config.useCompressedOops && node.isCompressible()) {
-            Variable scratch = newVariable(Kind.Long);
-            Register heapBaseReg = getProviders().getRegisters().getHeapBaseRegister();
-            append(new CompareAndSwapCompressedOp(raxRes, addressValue, raxRes, newValue, scratch, config.getOopEncoding(), heapBaseReg));
-        } else {
-            append(new CompareAndSwapOp(raxRes, addressValue, raxRes, newValue));
-        }
-        Variable result = newVariable(node.kind());
-        append(new CondMoveOp(result, Condition.EQ, load(Constant.TRUE), Constant.FALSE));
-        setResult(node, result);
-    }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        if (i.getState() != null && i.getState().bci == FrameState.AFTER_BCI) {
-            Debug.log("Ignoring InfopointNode for AFTER_BCI");
-        } else {
-            super.visitInfopointNode(i);
-        }
-    }
-
-    public void emitPrefetchAllocate(ValueNode address, ValueNode distance) {
-        AMD64AddressValue addr = emitAddress(operand(address), 0, loadNonConst(operand(distance)), 1);
-        append(new AMD64PrefetchOp(addr, config.allocatePrefetchInstr));
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.data.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Specialized code gen for comparison with compressed memory.
+ */
+
+public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole {
+    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
+        @Alive({COMPOSITE}) protected AMD64AddressValue x;
+        @Use({CONST}) protected Value y;
+        @State protected LIRFrameState state;
+
+        public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) {
+            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            Constant constant = (Constant) y;
+            if (constant.isNull()) {
+                masm.cmpl(x.toAddress(), 0);
+            } else {
+                if (y.getKind() == Kind.Object) {
+                    crb.recordInlineDataInCode(new OopData(0, constant.asObject(), true));
+                } else if (y.getKind() == Kind.Long) {
+                    crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), constant.getPrimitiveAnnotation(), true));
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+                if (state != null) {
+                    crb.recordImplicitException(masm.position(), state);
+                }
+                masm.cmpl(x.toAddress(), 0xdeaddead);
+            }
+        }
+    }
+
+    AMD64HotSpotMemoryPeephole(AMD64NodeLIRGenerator gen) {
+        super(gen);
+    }
+
+    @Override
+    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        assert left == access || right == access;
+        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
+            ValueNode other = left == access ? right : left;
+            Kind kind = access.nullCheckLocation().getValueKind();
+
+            if (other.isConstant() && kind == Kind.Object && access.isCompressible()) {
+                ensureEvaluated(other);
+                gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access)));
+                Condition finalCondition = right == access ? cond.mirror() : cond;
+                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+                return true;
+            }
+        }
+
+        return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
+import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.amd64.AMD64HotSpotLIRGenerator.SaveRbp;
+import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.CompareAndSwapCompressedOp;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.NoOp;
+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.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+
+/**
+ * LIR generator specialized for AMD64 HotSpot.
+ */
+public class AMD64HotSpotNodeLIRGenerator extends AMD64NodeLIRGenerator implements HotSpotNodeLIRGenerator {
+
+    public AMD64HotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult res, LIRGenerator gen) {
+        super(graph, res, gen);
+        memoryPeephole = new AMD64HotSpotMemoryPeephole(this);
+    }
+
+    private AMD64HotSpotLIRGenerator getGen() {
+        return (AMD64HotSpotLIRGenerator) gen;
+    }
+
+    private SaveRbp getSaveRbp() {
+        return getGen().saveRbp;
+    }
+
+    private void setSaveRbp(SaveRbp saveRbp) {
+        getGen().saveRbp = saveRbp;
+    }
+
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        HotSpotLockStack lockStack = new HotSpotLockStack(res.getFrameMap(), Kind.Long);
+        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+
+        CallingConvention incomingArguments = gen.getCallingConvention();
+
+        Value[] params = new Value[incomingArguments.getArgumentCount() + 1];
+        for (int i = 0; i < params.length - 1; i++) {
+            params[i] = toStackKind(incomingArguments.getArgument(i));
+            if (isStackSlot(params[i])) {
+                StackSlot slot = ValueUtil.asStackSlot(params[i]);
+                if (slot.isInCallerFrame() && !res.getLIR().hasArgInCallerFrame()) {
+                    res.getLIR().setHasArgInCallerFrame();
+                }
+            }
+        }
+        params[params.length - 1] = rbp.asValue(Kind.Long);
+
+        emitIncomingValues(params);
+
+        setSaveRbp(((AMD64HotSpotLIRGenerator) gen).new SaveRbp(new NoOp(gen.getCurrentBlock(), res.getLIR().getLIRforBlock(gen.getCurrentBlock()).size())));
+        append(getSaveRbp().placeholder);
+
+        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+            Value paramValue = params[param.index()];
+            assert paramValue.getKind() == param.getKind().getStackKind();
+            setResult(param, gen.emitMove(paramValue));
+        }
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        LIRFrameState info = gen.state(i);
+        append(new AMD64HotSpotSafepointOp(info, getGen().config, this));
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
+        if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
+            append(new AMD64HotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
+        } else {
+            assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
+            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
+            Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant();
+            append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod));
+        }
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        if (callTarget instanceof HotSpotIndirectCallTargetNode) {
+            AllocatableValue metaspaceMethod = AMD64.rbx.asValue();
+            gen.emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
+            AllocatableValue targetAddress = AMD64.rax.asValue();
+            gen.emitMove(targetAddress, operand(callTarget.computedAddress()));
+            append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
+        } else {
+            super.emitIndirectCall(callTarget, result, parameters, temps, callState);
+        }
+    }
+
+    @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        append(new AMD64HotSpotPatchReturnAddressOp(gen.load(operand(address))));
+    }
+
+    @Override
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        Variable handler = gen.load(operand(handlerInCallerPc));
+        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
+        assert outgoingCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1);
+        gen.emitMove(exceptionFixed, operand(exception));
+        gen.emitMove(exceptionPcFixed, operand(exceptionPc));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset,
+                        thread);
+        append(op);
+    }
+
+    @Override
+    public void visitInfopointNode(InfopointNode i) {
+        if (i.getState() != null && i.getState().bci == FrameState.AFTER_BCI) {
+            Debug.log("Ignoring InfopointNode for AFTER_BCI");
+        } else {
+            super.visitInfopointNode(i);
+        }
+    }
+
+    public void emitPrefetchAllocate(ValueNode address, ValueNode distance) {
+        AMD64AddressValue addr = getGen().emitAddress(operand(address), 0, gen.loadNonConst(operand(distance)), 1);
+        append(new AMD64PrefetchOp(addr, getGen().config.allocatePrefetchInstr));
+    }
+
+    @Override
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        Kind kind = x.newValue().getKind();
+        assert kind == x.expectedValue().getKind();
+
+        Value expected = gen.loadNonConst(operand(x.expectedValue()));
+        Variable newVal = gen.load(operand(x.newValue()));
+
+        int disp = 0;
+        AMD64AddressValue address;
+        Value index = operand(x.offset());
+        if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) {
+            assert !gen.getCodeCache().needsDataPatch(asConstant(index));
+            disp += (int) ValueUtil.asConstant(index).asLong();
+            address = new AMD64AddressValue(kind, gen.load(operand(x.object())), disp);
+        } else {
+            address = new AMD64AddressValue(kind, gen.load(operand(x.object())), gen.load(index), Scale.Times1, disp);
+        }
+
+        RegisterValue raxLocal = AMD64.rax.asValue(kind);
+        gen.emitMove(raxLocal, expected);
+        append(new CompareAndSwapOp(raxLocal, address, raxLocal, newVal));
+
+        Variable result = newVariable(x.getKind());
+        gen.emitMove(result, raxLocal);
+        setResult(x, result);
+    }
+
+    @Override
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
+        Kind kind = node.getNewValue().getKind();
+        assert kind == node.getExpectedValue().getKind();
+        Value expected = gen.loadNonConst(operand(node.getExpectedValue()));
+        Variable newValue = gen.load(operand(node.getNewValue()));
+        AMD64AddressValue addressValue = getGen().asAddressValue(address);
+        RegisterValue raxRes = AMD64.rax.asValue(kind);
+        gen.emitMove(raxRes, expected);
+        if (getGen().config.useCompressedOops && node.isCompressible()) {
+            Variable scratch = newVariable(Kind.Long);
+            Register heapBaseReg = getGen().getProviders().getRegisters().getHeapBaseRegister();
+            append(new CompareAndSwapCompressedOp(raxRes, addressValue, raxRes, newValue, scratch, getGen().config.getOopEncoding(), heapBaseReg));
+        } else {
+            append(new CompareAndSwapOp(raxRes, addressValue, raxRes, newValue));
+        }
+        Variable result = newVariable(node.getKind());
+        append(new CondMoveOp(result, Condition.EQ, gen.load(Constant.TRUE), Constant.FALSE));
+        setResult(node, result);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Sun Mar 30 16:08:33 2014 +0200
@@ -48,6 +48,8 @@
      */
     private final Register[] callerSaved;
 
+    private final boolean allAllocatableAreCallerSaved;
+
     private final HashMap<PlatformKind, Register[]> categorized = new HashMap<>();
 
     private final RegisterAttributes[] attributesMap;
@@ -152,6 +154,7 @@
         callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]);
         assert callerSaved.length == allocatable.length || RegisterPressure.getValue() != null;
 
+        allAllocatableAreCallerSaved = true;
         attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters);
     }
 
@@ -161,6 +164,11 @@
     }
 
     @Override
+    public boolean areAllAllocatableRegistersCallerSaved() {
+        return allAllocatableAreCallerSaved;
+    }
+
+    @Override
     public Register getRegisterForRole(int index) {
         throw new UnsupportedOperationException();
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Sun Mar 30 16:08:33 2014 +0200
@@ -47,11 +47,11 @@
 
     private final HotSpotVMConfig config;
 
-    public AMD64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
+    public AMD64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, NodeLIRGeneratorTool tool) {
         this.state = state;
         this.config = config;
         if (isPollingPageFar(config) || ImmutableCode.getValue()) {
-            temp = tool.newVariable(tool.target().wordKind);
+            temp = tool.getLIRGeneratorTool().newVariable(tool.getLIRGeneratorTool().target().wordKind);
         } else {
             // Don't waste a register if it's unneeded
             temp = Value.ILLEGAL;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -44,26 +44,27 @@
     }
 
     @Override
-    public void generate(LIRGenerator generator) {
-        AMD64LIRGenerator gen = (AMD64LIRGenerator) generator;
+    public void generate(NodeLIRGenerator generator) {
+        AMD64NodeLIRGenerator gen = (AMD64NodeLIRGenerator) generator;
         Value[] parameter = new Value[args.count()];
         JavaType[] parameterTypes = new JavaType[args.count()];
         for (int i = 0; i < args.count(); i++) {
             parameter[i] = generator.operand(args.get(i));
-            parameterTypes[i] = args.get(i).stamp().javaType(gen.getMetaAccess());
+            parameterTypes[i] = args.get(i).stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess());
         }
-        ResolvedJavaType returnType = stamp().javaType(gen.getMetaAccess());
-        CallingConvention cc = generator.getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes, generator.target(), false);
-        gen.emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
-        if (this.kind() != Kind.Void) {
-            generator.setResult(this, gen.emitMove(cc.getReturn()));
+        ResolvedJavaType returnType = stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess());
+        CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes,
+                        generator.getLIRGeneratorTool().target(), false);
+        ((AMD64LIRGenerator) gen.getLIRGeneratorTool()).emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
+        if (this.getKind() != Kind.Void) {
+            generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
         }
     }
 
     private static int countFloatingTypeArguments(NodeInputList<ValueNode> args) {
         int count = 0;
         for (ValueNode n : args) {
-            if (n.kind() == Kind.Double || n.kind() == Kind.Float) {
+            if (n.getKind() == Kind.Double || n.getKind() == Kind.Float) {
                 count++;
             }
         }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java	Sun Mar 30 16:08:33 2014 +0200
@@ -42,6 +42,7 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.printer.*;
+import com.oracle.graal.gpu.*;
 
 /**
  * Implements compile and dispatch of Java code containing lambda constructs. Currently only used by
@@ -82,7 +83,7 @@
         NodeIterable<MethodCallTargetNode> calls = graph.getNodes(MethodCallTargetNode.class);
         assert calls.count() == 1;
         ResolvedJavaMethod lambdaMethod = calls.first().targetMethod();
-        Debug.log("target ... " + lambdaMethod);
+        Debug.log("target ... %s", lambdaMethod);
 
         if (lambdaMethod == null) {
             Debug.log("Did not find call in accept()");
@@ -115,7 +116,7 @@
                 getHSAILBackend().executeKernel(code, jobSize, args);
                 return true;
             } catch (InvalidInstalledCodeException iice) {
-                Debug.log("WARNING: Invalid installed code at exec time." + iice);
+                Debug.log("WARNING: Invalid installed code at exec time: %s", iice);
                 iice.printStackTrace();
                 return false;
             }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,30 +26,45 @@
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.api.meta.LocationIdentity.*;
 
 import java.lang.reflect.*;
 import java.util.*;
 
 import com.amd.okra.*;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.code.CompilationResult.Call;
+import com.oracle.graal.api.code.CompilationResult.CodeAnnotation;
+import com.oracle.graal.api.code.CompilationResult.DataPatch;
+import com.oracle.graal.api.code.CompilationResult.ExceptionHandler;
+import com.oracle.graal.api.code.CompilationResult.Infopoint;
+import com.oracle.graal.api.code.CompilationResult.Mark;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.hsail.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.gpu.*;
 import com.oracle.graal.graph.*;
 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.hsail.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.hsail.*;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
@@ -59,6 +74,8 @@
 
     private Map<String, String> paramTypeMap = new HashMap<>();
     private final boolean deviceInitialized;
+    // TODO: get maximum Concurrency from okra
+    private int maxDeoptIndex = 8 * 40 * 64;   // see gpu_hsail.hpp
 
     public HSAILHotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) {
         super(runtime, providers);
@@ -79,12 +96,24 @@
 
     /**
      * Initializes the GPU device.
-     * 
+     *
      * @return whether or not initialization was successful
      */
     private static native boolean initialize();
 
     /**
+     * Control how many threads run on simulator (used only from junit tests).
+     */
+    public void setSimulatorSingleThreaded() {
+        String simThrEnv = System.getenv("SIMTHREADS");
+        if (simThrEnv == null || !simThrEnv.equals("1")) {
+            setSimulatorSingleThreaded0();
+        }
+    }
+
+    private static native void setSimulatorSingleThreaded0();
+
+    /**
      * Determines if the GPU device (or simulator) is available and initialized.
      */
     public boolean isDeviceInitialized() {
@@ -118,7 +147,7 @@
 
     /**
      * Compiles a given method to HSAIL code.
-     * 
+     *
      * @param makeBinary specifies whether a GPU binary should also be generated for the HSAIL code.
      *            If true, the returned value is guaranteed to have a non-zero
      *            {@linkplain ExternalCompilationResult#getEntryPoint() entry point}.
@@ -127,13 +156,37 @@
     public ExternalCompilationResult compileKernel(ResolvedJavaMethod method, boolean makeBinary) {
         StructuredGraph graph = new StructuredGraph(method);
         HotSpotProviders providers = getProviders();
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        MetaAccessProvider metaAccess = getProviders().getMetaAccess();
+
+        // changed this from default to help us generate deopts when needed
+        OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL;
+        optimisticOpts.remove(OptimisticOptimizations.Optimization.UseExceptionProbabilityForOperations);
+        new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), optimisticOpts).apply(graph);
         PhaseSuite<HighTierContext> graphBuilderSuite = providers.getSuites().getDefaultGraphBuilderSuite();
-        graphBuilderSuite.appendPhase(new NonNullParametersPhase());
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
+
+        // append special HSAILNonNullParametersPhase
+        int numArgs = cc.getArguments().length;
+        graphBuilderSuite.appendPhase(new HSAILNonNullParametersPhase(numArgs));
+
         Suites suites = providers.getSuites().getDefaultSuites();
-        ExternalCompilationResult hsailCode = compileGraph(graph, null, cc, method, providers, this, this.getTarget(), null, graphBuilderSuite, OptimisticOptimizations.NONE, getProfilingInfo(graph),
-                        null, suites, new ExternalCompilationResult(), CompilationResultBuilderFactory.Default);
+        ExternalCompilationResult hsailCode = compileGraph(graph, null, cc, method, providers, this, this.getTarget(), null, graphBuilderSuite, optimisticOpts, getProfilingInfo(graph), null, suites,
+                        new ExternalCompilationResult(), CompilationResultBuilderFactory.Default);
+
+        // this code added to dump infopoints
+        try (Scope s = Debug.scope("CodeGen")) {
+            if (Debug.isLogEnabled()) {
+                // show infopoints
+                List<Infopoint> infoList = hsailCode.getInfopoints();
+                Debug.log("%d HSAIL infopoints", infoList.size());
+                for (Infopoint info : infoList) {
+                    Debug.log(info.toString());
+                    Debug.log(info.debugInfo.frame().toString());
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
         if (makeBinary) {
             if (!deviceInitialized) {
@@ -152,6 +205,26 @@
         return hsailCode;
     }
 
+    private static class HSAILNonNullParametersPhase extends Phase {
+        // we use this to limit the stamping to exclude the final argument in an obj stream method
+        private int numArgs;
+
+        public HSAILNonNullParametersPhase(int numArgs) {
+            this.numArgs = numArgs;
+        }
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            int argCount = 0;
+            for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+                argCount++;
+                if (argCount < numArgs && param.stamp() instanceof ObjectStamp) {
+                    param.setStamp(StampFactory.declaredNonNull(((ObjectStamp) param.stamp()).type()));
+                }
+            }
+        }
+    }
+
     /**
      * Generates a GPU binary from HSAIL code.
      */
@@ -161,23 +234,127 @@
      * Installs the {@linkplain ExternalCompilationResult#getEntryPoint() GPU binary} associated
      * with some given HSAIL code in the code cache and returns a {@link HotSpotNmethod} handle to
      * the installed code.
-     * 
+     *
      * @param hsailCode HSAIL compilation result for which a GPU binary has been generated
      * @return a handle to the binary as installed in the HotSpot code cache
      */
     public final HotSpotNmethod installKernel(ResolvedJavaMethod method, ExternalCompilationResult hsailCode) {
         assert hsailCode.getEntryPoint() != 0L;
-        return getProviders().getCodeCache().addExternalMethod(method, hsailCode);
+        // code below here lifted from HotSpotCodeCacheProviders.addExternalMethod
+        // used to be return getProviders().getCodeCache().addExternalMethod(method, hsailCode);
+        HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method;
+        if (hsailCode.getId() == -1) {
+            hsailCode.setId(javaMethod.allocateCompileId(hsailCode.getEntryBCI()));
+        }
+        CompilationResult compilationResult = hsailCode;
+        StructuredGraph hostGraph = hsailCode.getHostGraph();
+        if (hostGraph != null) {
+            // TODO get rid of the unverified entry point in the host code
+            try (Scope ds = Debug.scope("GeneratingHostGraph")) {
+                HotSpotBackend hostBackend = getRuntime().getHostBackend();
+                JavaType[] parameterTypes = new JavaType[hostGraph.getNodes(ParameterNode.class).count()];
+                Debug.log("Param count: %d", parameterTypes.length);
+                for (int i = 0; i < parameterTypes.length; i++) {
+                    ParameterNode parameter = hostGraph.getParameter(i);
+                    Debug.log("Param [%d]=%d", i, parameter);
+                    parameterTypes[i] = parameter.stamp().javaType(hostBackend.getProviders().getMetaAccess());
+                    Debug.log(" %s", parameterTypes[i]);
+                }
+                CallingConvention cc = hostBackend.getProviders().getCodeCache().getRegisterConfig().getCallingConvention(Type.JavaCallee, method.getSignature().getReturnType(null), parameterTypes,
+                                hostBackend.getTarget(), false);
+                CompilationResult hostCode = compileGraph(hostGraph, null, cc, method, hostBackend.getProviders(), hostBackend, this.getTarget(), null,
+                                hostBackend.getProviders().getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, null, null,
+                                hostBackend.getProviders().getSuites().getDefaultSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                compilationResult = merge(hostCode, hsailCode);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+
+        HotSpotNmethod code = new HotSpotNmethod(javaMethod, hsailCode.getName(), false, true);
+        HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(getTarget(), javaMethod, compilationResult);
+        CodeInstallResult result = getRuntime().getCompilerToVM().installCode(compiled, code, null);
+        if (result != CodeInstallResult.OK) {
+            return null;
+        }
+        return code;
+    }
+
+    private static ExternalCompilationResult merge(CompilationResult hostCode, ExternalCompilationResult hsailCode) {
+        ExternalCompilationResult result = new ExternalCompilationResult();
+
+        // from hsail code
+        result.setEntryPoint(hsailCode.getEntryPoint());
+        result.setId(hsailCode.getId());
+        result.setEntryBCI(hsailCode.getEntryBCI());
+        assert hsailCode.getMarks().isEmpty();
+        assert hsailCode.getExceptionHandlers().isEmpty();
+        assert hsailCode.getDataReferences().isEmpty();
+
+        // from host code
+        result.setFrameSize(hostCode.getFrameSize());
+        result.setCustomStackAreaOffset(hostCode.getCustomStackAreaOffset());
+        result.setRegisterRestoreEpilogueOffset(hostCode.getRegisterRestoreEpilogueOffset());
+        result.setTargetCode(hostCode.getTargetCode(), hostCode.getTargetCodeSize());
+        for (CodeAnnotation annotation : hostCode.getAnnotations()) {
+            result.addAnnotation(annotation);
+        }
+        CompilationResult.Mark[] noMarks = {};
+        for (Mark mark : hostCode.getMarks()) {
+            result.recordMark(mark.pcOffset, mark.id, noMarks);
+        }
+        for (ExceptionHandler handler : hostCode.getExceptionHandlers()) {
+            result.recordExceptionHandler(handler.pcOffset, handler.handlerPos);
+        }
+        for (DataPatch patch : hostCode.getDataReferences()) {
+            if (patch.data != null) {
+                if (patch.inline) {
+                    result.recordInlineData(patch.pcOffset, patch.data);
+                } else {
+                    result.recordDataReference(patch.pcOffset, patch.data);
+                }
+            }
+        }
+        for (Infopoint infopoint : hostCode.getInfopoints()) {
+            if (infopoint instanceof Call) {
+                Call call = (Call) infopoint;
+                result.recordCall(call.pcOffset, call.size, call.target, call.debugInfo, call.direct);
+            } else {
+                result.recordInfopoint(infopoint.pcOffset, infopoint.debugInfo, infopoint.reason);
+            }
+        }
+
+        // merged
+        Assumptions mergedAssumptions = new Assumptions(true);
+        if (hostCode.getAssumptions() != null) {
+            for (Assumption assumption : hostCode.getAssumptions().getAssumptions()) {
+                if (assumption != null) {
+                    mergedAssumptions.record(assumption);
+                }
+            }
+        }
+        if (hsailCode.getAssumptions() != null) {
+            for (Assumption assumption : hsailCode.getAssumptions().getAssumptions()) {
+                if (assumption != null) {
+                    mergedAssumptions.record(assumption);
+                }
+            }
+        }
+        if (!mergedAssumptions.isEmpty()) {
+            result.setAssumptions(mergedAssumptions);
+        }
+        return result;
     }
 
     public boolean executeKernel(HotSpotInstalledCode kernel, int jobSize, Object[] args) throws InvalidInstalledCodeException {
         if (!deviceInitialized) {
             throw new GraalInternalError("Cannot execute GPU kernel if device is not initialized");
         }
-        return executeKernel0(kernel, jobSize, args);
+        Object[] oopsSaveArea = new Object[maxDeoptIndex * 16];
+        return executeKernel0(kernel, jobSize, args, oopsSaveArea);
     }
 
-    private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args) throws InvalidInstalledCodeException;
+    private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Object[] oopsSave) throws InvalidInstalledCodeException;
 
     /**
      * Use the HSAIL register set when the compilation target is HSAIL.
@@ -188,8 +365,18 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        return new HSAILHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir);
+    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+        return new HSAILHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
+    }
+
+    @Override
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        return new HSAILHotSpotLIRGenerationResult(lir, frameMap);
+    }
+
+    @Override
+    public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        return new HSAILHotSpotNodeLIRGenerator(graph, lirGenRes, lirGen);
     }
 
     class HotSpotFrameContext implements FrameContext {
@@ -209,17 +396,32 @@
         }
     }
 
+    /**
+     * a class to allow us to save lirGen.
+     */
+    static class HSAILCompilationResultBuilder extends CompilationResultBuilder {
+        public HSAILHotSpotLIRGenerationResult lirGenRes;
+
+        public HSAILCompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext,
+                        CompilationResult compilationResult, HSAILHotSpotLIRGenerationResult lirGenRes) {
+            super(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult);
+            this.lirGenRes = lirGenRes;
+        }
+    }
+
     @Override
     protected Assembler createAssembler(FrameMap frameMap) {
         return new HSAILAssembler(getTarget());
     }
 
     @Override
-    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
-        FrameMap frameMap = lirGen.frameMap;
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+        FrameMap frameMap = lirGenRes.getFrameMap();
         Assembler masm = createAssembler(frameMap);
         HotSpotFrameContext frameContext = new HotSpotFrameContext();
-        CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
+        // save lirGen for later use by setHostGraph
+        CompilationResultBuilder crb = new HSAILCompilationResultBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult,
+                        (HSAILHotSpotLIRGenerationResult) lirGenRes);
         crb.setFrameSize(frameMap.frameSize());
         return crb;
     }
@@ -227,10 +429,12 @@
     @Override
     public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod method) {
         assert method != null : lir + " is not associated with a method";
+
+        boolean usesDeoptInfo = true;     // TODO: make this conditional on something?
+
         // Emit the prologue.
-        Assembler asm = crb.asm;
-        asm.emitString0("version 0:95: $full : $large;");
-        asm.emitString("");
+        HSAILAssembler asm = (HSAILAssembler) crb.asm;
+        asm.emitString0("version 0:95: $full : $large;\n");
 
         Signature signature = method.getSignature();
         int sigParamCount = signature.getParameterCount(false);
@@ -275,10 +479,8 @@
             }
         }
 
-        asm.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method);
-        asm.emitString("");
-        asm.emitString0("kernel &run (");
-        asm.emitString("");
+        asm.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method + "\n");
+        asm.emitString0("kernel &run ( \n");
 
         FrameMap frameMap = crb.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
@@ -297,7 +499,7 @@
         /**
          * Compute the hsail size mappings up to but not including the last non-constant parameter
          * (which is the gid).
-         * 
+         *
          */
         String[] paramHsailSizes = new String[totalParamCount];
         for (int i = 0; i < totalParamCount; i++) {
@@ -310,11 +512,17 @@
         for (int i = 0; i < totalParamCount; i++) {
             String str = "align 8 kernarg_" + paramHsailSizes[i] + " " + paramNames[i];
 
-            if (i != totalParamCount - 1) {
+            if (usesDeoptInfo || (i != totalParamCount - 1)) {
                 str += ",";
             }
             asm.emitString(str);
         }
+
+        if (usesDeoptInfo) {
+            // add in the deoptInfo parameter
+            asm.emitString("kernarg_u64 " + asm.getDeoptInfoName());
+        }
+
         asm.emitString(") {");
 
         /*
@@ -333,10 +541,28 @@
         String workItemReg = "$s" + Integer.toString(asRegister(cc.getArgument(nonConstantParamCount)).encoding());
         asm.emitString("workitemabsid_u32 " + workItemReg + ", 0;");
 
+        final int offsetToDeoptSaveStates = getRuntime().getConfig().hsailSaveStatesOffset0;
+        final int sizeofKernelDeopt = getRuntime().getConfig().hsailSaveStatesOffset1 - getRuntime().getConfig().hsailSaveStatesOffset0;
+        final int offsetToDeopt = getRuntime().getConfig().hsailDeoptOffset;
+        final int offsetToNeverRanArray = getRuntime().getConfig().hsailNeverRanArrayOffset;
+        final int offsetToDeoptNextIndex = getRuntime().getConfig().hsailDeoptNextIndexOffset;
+        final String deoptInProgressLabel = "@LHandleDeoptInProgress";
+
+        if (usesDeoptInfo) {
+            AllocatableValue scratch64 = HSAIL.d16.asValue(Kind.Object);
+            AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
+            HSAILAddress deoptInfoAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeopt).toAddress();
+            asm.emitLoadKernelArg(scratch64, asm.getDeoptInfoName(), "u64");
+            asm.emitComment("// Check if a deopt has occurred and abort if true before doing any work");
+            asm.emitLoadAcquire(scratch32, deoptInfoAddr);
+            asm.emitCompare(scratch32, Constant.forInt(0), "ne", false, false);
+            asm.cbr(deoptInProgressLabel);
+        }
+
         /*
          * Note the logic used for this spillseg size is to leave space and then go back and patch
          * in the correct size once we have generated all the instructions. This should probably be
-         * done in a more robust way by implementing something like codeBuffer.insertString.
+         * done in a more robust way by implementing something like asm.insertString.
          */
         int spillsegDeclarationPosition = asm.position() + 1;
         String spillsegTemplate = "align 4 spill_u8 %spillseg[123456];";
@@ -373,9 +599,14 @@
                     if (narrowOopBase == 0) {
                         asm.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift");
                     } else if (narrowOopShift == 0) {
+                        // not sure if we ever get add with 0 shift but just in case
+                        asm.emitString("cmp_eq_b1_u64  $c0, " + tmpReg + ", 0x0; // avoid add if compressed is null");
                         asm.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase");
+                        asm.emitString("cmov_b64 " + iterationObjArgReg + ", $c0, 0x0, " + iterationObjArgReg + "; // avoid add if compressed is null");
                     } else {
+                        asm.emitString("cmp_eq_b1_u64  $c0, " + tmpReg + ", 0x0; // avoid shift-add if compressed is null");
                         asm.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase");
+                        asm.emitString("cmov_b64 " + iterationObjArgReg + ", $c0, 0x0, " + iterationObjArgReg + "; // avoid shift-add if compressed is null");
                     }
                 }
 
@@ -397,9 +628,289 @@
             spillsegStringFinal = spillsegTemplate.replace("123456", String.format("%6d", maxStackSize));
         }
         asm.emitString(spillsegStringFinal, spillsegDeclarationPosition);
+        // Emit the epilogue.
 
-        // Emit the epilogue.
-        asm.emitString0("};");
-        asm.emitString("");
+        final int offsetToDeoptimizationWorkItem = getRuntime().getConfig().hsailDeoptimizationWorkItem;
+        final int offsetToDeoptimizationReason = getRuntime().getConfig().hsailDeoptimizationReason;
+        final int offsetToDeoptimizationFrame = getRuntime().getConfig().hsailDeoptimizationFrame;
+        final int offsetToFramePc = getRuntime().getConfig().hsailFramePcOffset;
+        final int offsetToNumSaves = getRuntime().getConfig().hsailFrameNumSRegOffset;
+        final int offsetToSaveArea = getRuntime().getConfig().hsailFrameSaveAreaOffset;
+
+        // TODO: keep track of whether we need it
+        if (usesDeoptInfo) {
+            AllocatableValue scratch64 = HSAIL.d16.asValue(Kind.Object);
+            AllocatableValue cuSaveAreaPtr = HSAIL.d17.asValue(Kind.Object);
+            AllocatableValue waveMathScratch1 = HSAIL.d18.asValue(Kind.Object);
+            AllocatableValue waveMathScratch2 = HSAIL.d19.asValue(Kind.Object);
+
+            AllocatableValue actionAndReasonReg = HSAIL.s32.asValue(Kind.Int);
+            AllocatableValue codeBufferOffsetReg = HSAIL.s33.asValue(Kind.Int);
+            AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
+            AllocatableValue workidreg = HSAIL.s35.asValue(Kind.Int);
+            AllocatableValue dregOopMapReg = HSAIL.s39.asValue(Kind.Int);
+
+            HSAILAddress deoptNextIndexAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptNextIndex).toAddress();
+            HSAILAddress neverRanArrayAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToNeverRanArray).toAddress();
+
+            // The just-started lanes that see the deopt flag will jump here
+            asm.emitString0(deoptInProgressLabel + ":\n");
+            asm.emitLoad(Kind.Object, waveMathScratch1, neverRanArrayAddr);
+            asm.emitWorkItemAbsId(workidreg);
+            asm.emitConvert(waveMathScratch2, workidreg, Kind.Object, Kind.Int);
+            asm.emit("add", waveMathScratch1, waveMathScratch1, waveMathScratch2);
+            HSAILAddress neverRanStoreAddr = new HSAILAddressValue(Kind.Byte, waveMathScratch1, 0).toAddress();
+            asm.emitStore(Kind.Byte, Constant.forInt(1), neverRanStoreAddr);
+            asm.emitString("ret;");
+
+            // The deoptimizing lanes will jump here
+            asm.emitString0(asm.getDeoptLabelName() + ":\n");
+            String labelExit = asm.getDeoptLabelName() + "_Exit";
+
+            HSAILAddress deoptInfoAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeopt).toAddress();
+            asm.emitLoadKernelArg(scratch64, asm.getDeoptInfoName(), "u64");
+
+            // Set deopt occurred flag
+            asm.emitMov(scratch32, Constant.forInt(1));
+            asm.emitStoreRelease(scratch32, deoptInfoAddr);
+
+            asm.emitComment("// Determine next deopt save slot");
+            asm.emitAtomicAdd(scratch32, deoptNextIndexAddr, Constant.forInt(1));
+            // scratch32 now holds next index to use
+            // set error condition if no room in save area
+            asm.emitComment("// assert room to save deopt");
+            asm.emitCompare(scratch32, Constant.forInt(maxDeoptIndex), "lt", false, false);
+            asm.cbr("@L_StoreDeopt");
+            // if assert fails, store a guaranteed negative workitemid in top level deopt occurred
+            // flag
+            asm.emitWorkItemAbsId(scratch32);
+            asm.emit("mad", scratch32, scratch32, Constant.forInt(-1), Constant.forInt(-1));
+            asm.emitStore(scratch32, deoptInfoAddr);
+            asm.emitString("ret;");
+
+            asm.emitString0("@L_StoreDeopt" + ":\n");
+
+            // Store deopt for this workitem into its slot in the HSAILComputeUnitSaveStates array
+
+            asm.emitComment("// Convert id's for ptr math");
+            asm.emitConvert(cuSaveAreaPtr, scratch32, Kind.Object, Kind.Int);
+            asm.emitComment("// multiply by sizeof KernelDeoptArea");
+            asm.emit("mul", cuSaveAreaPtr, cuSaveAreaPtr, Constant.forInt(sizeofKernelDeopt));
+            asm.emitComment("// Add computed offset to deoptInfoPtr base");
+            asm.emit("add", cuSaveAreaPtr, cuSaveAreaPtr, scratch64);
+            // Add offset to _deopt_save_states[0]
+            asm.emit("add", scratch64, cuSaveAreaPtr, Constant.forInt(offsetToDeoptSaveStates));
+
+            HSAILAddress workItemAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptimizationWorkItem).toAddress();
+            HSAILAddress actionReasonStoreAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptimizationReason).toAddress();
+
+            asm.emitComment("// Get _deopt_info._first_frame");
+            asm.emit("add", waveMathScratch1, scratch64, Constant.forInt(offsetToDeoptimizationFrame));
+            // Now scratch64 is the _deopt_info._first_frame
+            HSAILAddress pcStoreAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToFramePc).toAddress();
+            HSAILAddress regCountsAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToNumSaves).toAddress();
+            HSAILAddress dregOopMapAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToNumSaves + 2).toAddress();
+
+            asm.emitComment("// store deopting workitem");
+            asm.emitWorkItemAbsId(scratch32);
+            asm.emitStore(Kind.Int, scratch32, workItemAddr);
+            asm.emitComment("// store actionAndReason");
+            asm.emitStore(Kind.Int, actionAndReasonReg, actionReasonStoreAddr);
+            asm.emitComment("// store PC");
+            asm.emitStore(Kind.Int, codeBufferOffsetReg, pcStoreAddr);
+            asm.emitComment("// store regCounts");
+            asm.emitStore(Kind.Short, Constant.forInt(32 + (16 << 8) + (0 << 16)), regCountsAddr);
+            asm.emitComment("// store dreg ref map bits");
+            asm.emitStore(Kind.Short, dregOopMapReg, dregOopMapAddr);
+
+            // get the union of registers needed to be saved at the infopoints
+            // usedRegs array assumes d15 has the highest register number we wish to save
+            // and initially has all registers as false
+            boolean[] infoUsedRegs = new boolean[HSAIL.d15.number + 1];
+            List<Infopoint> infoList = crb.compilationResult.getInfopoints();
+            for (Infopoint info : infoList) {
+                BytecodeFrame frame = info.debugInfo.frame();
+                for (int i = 0; i < frame.numLocals + frame.numStack; i++) {
+                    Value val = frame.values[i];
+                    if (isLegal(val) && isRegister(val)) {
+                        Register reg = asRegister(val);
+                        infoUsedRegs[reg.number] = true;
+                    }
+                }
+            }
+
+            // loop storing each of the 32 s registers that are used by infopoints
+            // we always store in a fixed location, even if some registers are not stored
+            asm.emitComment("// store used s regs");
+            int ofst = offsetToSaveArea;
+            for (Register sreg : HSAIL.sRegisters) {
+                if (infoUsedRegs[sreg.number]) {
+                    Kind kind = Kind.Int;
+                    HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
+                    AllocatableValue sregValue = sreg.asValue(kind);
+                    asm.emitStore(kind, sregValue, addr);
+                }
+                ofst += 4;
+            }
+
+            // loop storing each of the 16 d registers that are used by infopoints
+            asm.emitComment("// store used d regs");
+            for (Register dreg : HSAIL.dRegisters) {
+                if (infoUsedRegs[dreg.number]) {
+                    Kind kind = Kind.Long;
+                    HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
+                    AllocatableValue dregValue = dreg.asValue(kind);
+                    asm.emitStore(kind, dregValue, addr);
+                }
+                ofst += 8;
+            }
+
+            // for now, ignore saving the spill variables but that would come here
+
+            asm.emitString0(labelExit + ":\n");
+
+            // and emit the return
+            crb.frameContext.leave(crb);
+            asm.exit();
+        }
+
+        asm.emitString0("}; \n");
+
+        ExternalCompilationResult compilationResult = (ExternalCompilationResult) crb.compilationResult;
+        HSAILHotSpotLIRGenerationResult lirGenRes = ((HSAILCompilationResultBuilder) crb).lirGenRes;
+        compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), getRuntime().getConfig()));
     }
+
+    private static StructuredGraph prepareHostGraph(ResolvedJavaMethod method, List<DeoptimizeOp> deopts, HotSpotProviders providers, HotSpotVMConfig config) {
+        if (deopts.isEmpty()) {
+            return null;
+        }
+        StructuredGraph hostGraph = new StructuredGraph(method, -2);
+        ParameterNode deoptId = hostGraph.unique(new ParameterNode(0, StampFactory.intValue()));
+        ParameterNode hsailFrame = hostGraph.unique(new ParameterNode(1, StampFactory.forKind(providers.getCodeCache().getTarget().wordKind)));
+        ParameterNode reasonAndAction = hostGraph.unique(new ParameterNode(2, StampFactory.intValue()));
+        ParameterNode speculation = hostGraph.unique(new ParameterNode(3, StampFactory.object()));
+        AbstractBeginNode[] branches = new AbstractBeginNode[deopts.size() + 1];
+        int[] keys = new int[deopts.size()];
+        int[] keySuccessors = new int[deopts.size() + 1];
+        double[] keyProbabilities = new double[deopts.size() + 1];
+        int i = 0;
+        Collections.sort(deopts, new Comparator<DeoptimizeOp>() {
+            public int compare(DeoptimizeOp o1, DeoptimizeOp o2) {
+                return o1.getCodeBufferPos() - o2.getCodeBufferPos();
+            }
+        });
+        for (DeoptimizeOp deopt : deopts) {
+            keySuccessors[i] = i;
+            keyProbabilities[i] = 1.0 / deopts.size();
+            keys[i] = deopt.getCodeBufferPos();
+            assert keys[i] >= 0;
+            branches[i] = createHostDeoptBranch(deopt, hsailFrame, reasonAndAction, speculation, providers, config);
+
+            i++;
+        }
+        keyProbabilities[deopts.size()] = 0; // default
+        keySuccessors[deopts.size()] = deopts.size();
+        branches[deopts.size()] = createHostCrashBranch(hostGraph, deoptId);
+        IntegerSwitchNode switchNode = hostGraph.add(new IntegerSwitchNode(deoptId, branches, keys, keyProbabilities, keySuccessors));
+        StartNode start = hostGraph.start();
+        start.setNext(switchNode);
+        /*
+         * printf.setNext(printf2); printf2.setNext(switchNode);
+         */
+        hostGraph.setGuardsStage(GuardsStage.AFTER_FSA);
+        return hostGraph;
+    }
+
+    private static AbstractBeginNode createHostCrashBranch(StructuredGraph hostGraph, ValueNode deoptId) {
+        VMErrorNode vmError = hostGraph.add(new VMErrorNode("Error in HSAIL deopt. DeoptId=%d", deoptId));
+        // ConvertNode.convert(hostGraph, Kind.Long, deoptId)));
+        vmError.setNext(hostGraph.add(new ReturnNode(ConstantNode.defaultForKind(hostGraph.method().getSignature().getReturnKind(), hostGraph))));
+        return BeginNode.begin(vmError);
+    }
+
+    private static AbstractBeginNode createHostDeoptBranch(DeoptimizeOp deopt, ParameterNode hsailFrame, ValueNode reasonAndAction, ValueNode speculation, HotSpotProviders providers,
+                    HotSpotVMConfig config) {
+        BeginNode branch = hsailFrame.graph().add(new BeginNode());
+        DynamicDeoptimizeNode deoptimization = hsailFrame.graph().add(new DynamicDeoptimizeNode(reasonAndAction, speculation));
+        deoptimization.setStateBefore(createFrameState(deopt.getFrameState().topFrame, hsailFrame, providers, config));
+        branch.setNext(deoptimization);
+        return branch;
+    }
+
+    private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config) {
+        StructuredGraph hostGraph = hsailFrame.graph();
+        ValueNode[] locals = new ValueNode[lowLevelFrame.numLocals];
+        for (int i = 0; i < lowLevelFrame.numLocals; i++) {
+            locals[i] = getNodeForValueFromFrame(lowLevelFrame.getLocalValue(i), hsailFrame, hostGraph, providers, config);
+        }
+        List<ValueNode> stack = new ArrayList<>(lowLevelFrame.numStack);
+        for (int i = 0; i < lowLevelFrame.numStack; i++) {
+            stack.add(getNodeForValueFromFrame(lowLevelFrame.getStackValue(i), hsailFrame, hostGraph, providers, config));
+        }
+        ValueNode[] locks = new ValueNode[lowLevelFrame.numLocks];
+        MonitorIdNode[] monitorIds = new MonitorIdNode[lowLevelFrame.numLocks];
+        for (int i = 0; i < lowLevelFrame.numLocks; i++) {
+            HotSpotMonitorValue lockValue = (HotSpotMonitorValue) lowLevelFrame.getLockValue(i);
+            locks[i] = getNodeForValueFromFrame(lockValue, hsailFrame, hostGraph, providers, config);
+            monitorIds[i] = getMonitorIdForHotSpotMonitorValueFromFrame(lockValue, hsailFrame, hostGraph);
+        }
+        FrameState frameState = hostGraph.add(new FrameState(lowLevelFrame.getMethod(), lowLevelFrame.getBCI(), locals, stack, locks, monitorIds, lowLevelFrame.rethrowException, false));
+        if (lowLevelFrame.caller() != null) {
+            frameState.setOuterFrameState(createFrameState(lowLevelFrame.caller(), hsailFrame, providers, config));
+        }
+        return frameState;
+    }
+
+    @SuppressWarnings({"unused"})
+    private static MonitorIdNode getMonitorIdForHotSpotMonitorValueFromFrame(HotSpotMonitorValue lockValue, ParameterNode hsailFrame, StructuredGraph hsailGraph) {
+        if (lockValue.isEliminated()) {
+            return null;
+        }
+        throw GraalInternalError.unimplemented();
+    }
+
+    private static ValueNode getNodeForValueFromFrame(Value localValue, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) {
+        ValueNode valueNode;
+        if (localValue instanceof Constant) {
+            valueNode = ConstantNode.forConstant((Constant) localValue, providers.getMetaAccess(), hostGraph);
+        } else if (localValue instanceof VirtualObject) {
+            throw GraalInternalError.unimplemented();
+        } else if (localValue instanceof StackSlot) {
+            throw GraalInternalError.unimplemented();
+        } else if (localValue instanceof HotSpotMonitorValue) {
+            HotSpotMonitorValue hotSpotMonitorValue = (HotSpotMonitorValue) localValue;
+            return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config);
+        } else if (localValue instanceof RegisterValue) {
+            RegisterValue registerValue = (RegisterValue) localValue;
+            int regNumber = registerValue.getRegister().number;
+            valueNode = getNodeForRegisterFromFrame(regNumber, localValue.getKind(), hsailFrame, hostGraph, providers, config);
+        } else if (Value.ILLEGAL.equals(localValue)) {
+            valueNode = null;
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+        return valueNode;
+    }
+
+    private static ValueNode getNodeForRegisterFromFrame(int regNumber, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) {
+        ValueNode valueNode;
+        LocationNode location;
+        if (regNumber >= HSAIL.s0.number && regNumber <= HSAIL.s31.number) {
+            int intSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Int);
+            long offset = config.hsailFrameSaveAreaOffset + intSize * (regNumber - HSAIL.s0.number);
+            location = ConstantLocationNode.create(FINAL_LOCATION, valueKind, offset, hostGraph);
+        } else if (regNumber >= HSAIL.d0.number && regNumber <= HSAIL.d15.number) {
+            int longSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Long);
+            long offset = config.hsailFrameSaveAreaOffset + longSize * (regNumber - HSAIL.d0.number);
+            LocationNode numSRegsLocation = ConstantLocationNode.create(FINAL_LOCATION, Kind.Byte, config.hsailFrameNumSRegOffset, hostGraph);
+            ValueNode numSRegs = hostGraph.unique(new FloatingReadNode(hsailFrame, numSRegsLocation, null, StampFactory.forKind(Kind.Byte)));
+            location = IndexedLocationNode.create(FINAL_LOCATION, valueKind, offset, numSRegs, hostGraph, 4);
+        } else {
+            throw GraalInternalError.shouldNotReachHere("unknown hsail register: " + regNumber);
+        }
+        valueNode = hostGraph.unique(new FloatingReadNode(hsailFrame, location, null, StampFactory.forKind(valueKind)));
+        return valueNode;
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerationResult.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.hsail;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp;
+
+public class HSAILHotSpotLIRGenerationResult extends LIRGenerationResultBase {
+
+    private List<DeoptimizeOp> deopts = new ArrayList<>();
+
+    public HSAILHotSpotLIRGenerationResult(LIR lir, FrameMap frameMap) {
+        super(lir, frameMap);
+    }
+
+    public List<DeoptimizeOp> getDeopts() {
+        return deopts;
+    }
+
+    public void addDeopt(DeoptimizeOp deopt) {
+        deopts.add(deopt);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,58 +23,69 @@
 
 package com.oracle.graal.hotspot.hsail;
 
-import sun.misc.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
 
 import com.oracle.graal.api.code.*;
-import static com.oracle.graal.api.code.ValueUtil.asConstant;
-import static com.oracle.graal.api.code.ValueUtil.isConstant;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.hsail.*;
+import com.oracle.graal.graph.*;
 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.hsail.*;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.*;
-import com.oracle.graal.lir.hsail.HSAILMove.*;
-import com.oracle.graal.phases.util.*;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall1ArgOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall2ArgOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCallNoArgOp;
+import com.oracle.graal.lir.hsail.HSAILMove.LoadCompressedPointer;
+import com.oracle.graal.lir.hsail.HSAILMove.LoadOp;
+import com.oracle.graal.lir.hsail.HSAILMove.StoreCompressedPointer;
+import com.oracle.graal.lir.hsail.HSAILMove.StoreConstantOp;
+import com.oracle.graal.lir.hsail.HSAILMove.StoreOp;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.phases.util.*;
 
 /**
  * The HotSpot specific portion of the HSAIL LIR generator.
  */
 public class HSAILHotSpotLIRGenerator extends HSAILLIRGenerator {
 
-    private final HotSpotVMConfig config;
+    final HotSpotVMConfig config;
 
-    public HSAILHotSpotLIRGenerator(StructuredGraph graph, Providers providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
+    public HSAILHotSpotLIRGenerator(Providers providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
         this.config = config;
     }
 
-    private int getLogMinObjectAlignment() {
+    @Override
+    public HotSpotProviders getProviders() {
+        return (HotSpotProviders) super.getProviders();
+    }
+
+    int getLogMinObjectAlignment() {
         return config.logMinObjAlignment();
     }
 
-    private int getNarrowOopShift() {
+    int getNarrowOopShift() {
         return config.narrowOopShift;
     }
 
-    private long getNarrowOopBase() {
+    long getNarrowOopBase() {
         return config.narrowOopBase;
     }
 
-    private int getLogKlassAlignment() {
+    int getLogKlassAlignment() {
         return config.logKlassAlignment;
     }
 
-    private int getNarrowKlassShift() {
+    int getNarrowKlassShift() {
         return config.narrowKlassShift;
     }
 
-    private long getNarrowKlassBase() {
+    long getNarrowKlassBase() {
         return config.narrowKlassBase;
     }
 
@@ -88,41 +99,6 @@
     }
 
     /**
-     * Appends either a {@link CompareAndSwapOp} or a {@link CompareAndSwapCompressedOp} depending
-     * on whether the memory location of a given {@link LoweredCompareAndSwapNode} contains a
-     * compressed oop. For the {@link CompareAndSwapCompressedOp} case, allocates a number of
-     * scratch registers. The result {@link #operand(ValueNode) operand} for {@code node} complies
-     * with the API for {@link Unsafe#compareAndSwapInt(Object, long, int, int)}.
-     * 
-     * @param address the memory location targeted by the operation
-     */
-    @Override
-    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
-        Kind kind = node.getNewValue().kind();
-        assert kind == node.getExpectedValue().kind();
-        Variable expected = load(operand(node.getExpectedValue()));
-        Variable newValue = load(operand(node.getNewValue()));
-        HSAILAddressValue addressValue = asAddressValue(address);
-        Variable casResult = newVariable(kind);
-        if (config.useCompressedOops && node.isCompressible()) {
-            // make 64-bit scratch variables for expected and new
-            Variable scratchExpected64 = newVariable(Kind.Long);
-            Variable scratchNewValue64 = newVariable(Kind.Long);
-            // make 32-bit scratch variables for expected and new and result
-            Variable scratchExpected32 = newVariable(Kind.Int);
-            Variable scratchNewValue32 = newVariable(Kind.Int);
-            Variable scratchCasResult32 = newVariable(Kind.Int);
-            append(new CompareAndSwapCompressedOp(casResult, addressValue, expected, newValue, scratchExpected64, scratchNewValue64, scratchExpected32, scratchNewValue32, scratchCasResult32,
-                            getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
-        } else {
-            append(new CompareAndSwapOp(casResult, addressValue, expected, newValue));
-        }
-        Variable nodeResult = newVariable(node.kind());
-        append(new CondMoveOp(mapKindToCompareOp(kind), casResult, expected, nodeResult, Condition.EQ, Constant.INT_1, Constant.INT_0));
-        setResult(node, nodeResult);
-    }
-
-    /**
      * Returns whether or not the input access should be (de)compressed.
      */
     private boolean isCompressedOperation(Kind kind, Access access) {
@@ -163,6 +139,9 @@
                 if (isCompressed) {
                     if ((c.getKind() == Kind.Object) && c.isNull()) {
                         append(new StoreConstantOp(Kind.Int, storeAddress, Constant.forInt(0), state));
+                    } else if (c.getKind() == Kind.Long) {
+                        Constant value = compress(c, config.getKlassEncoding());
+                        append(new StoreConstantOp(Kind.Int, storeAddress, value, state));
                     } else {
                         throw GraalInternalError.shouldNotReachHere("can't handle: " + access);
                     }
@@ -185,11 +164,25 @@
         }
     }
 
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting) {
+        emitDeoptimizeInner(actionAndReason, state(deopting), "emitDeoptimize");
+    }
+
+    /***
+     * We need 64-bit and 32-bit scratch registers for the codegen $s0 can be live at this block.
+     */
+    private void emitDeoptimizeInner(Value actionAndReason, LIRFrameState lirFrameState, String emitName) {
+        DeoptimizeOp deopt = new DeoptimizeOp(actionAndReason, lirFrameState, emitName, getMetaAccess());
+        ((HSAILHotSpotLIRGenerationResult) res).addDeopt(deopt);
+        append(deopt);
+    }
+
     /***
      * This is a very temporary solution to emitForeignCall. We don't really support foreign calls
      * yet, but we do want to generate dummy code for them. The ForeignCallXXXOps just end up
      * emitting a comment as to what Foreign call they would have made.
-     **/
+     */
     @Override
     public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
         Variable result = newVariable(Kind.Object);  // linkage.getDescriptor().getResultType());
@@ -226,4 +219,14 @@
         // this version of emitForeignCall not used for now
     }
 
+    /**
+     * @return a compressed version of the incoming constant lifted from AMD64HotSpotLIRGenerator
+     */
+    protected static Constant compress(Constant c, CompressEncoding encoding) {
+        if (c.getKind() == Kind.Long) {
+            return Constant.forIntegerKind(Kind.Int, (int) (((c.asLong() - encoding.base) >> encoding.shift) & 0xffffffffL), c.getPrimitiveAnnotation());
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,21 +27,92 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import java.util.HashMap;
 
 public class HSAILHotSpotLoweringProvider extends HotSpotLoweringProvider {
 
+    abstract static class LoweringStrategy {
+        abstract void lower(Node n, LoweringTool tool);
+    }
+
+    static LoweringStrategy PassThruStrategy = new LoweringStrategy() {
+        @Override
+        void lower(Node n, LoweringTool tool) {
+            return;
+        }
+    };
+
+    static LoweringStrategy RejectStrategy = new LoweringStrategy() {
+        @Override
+        void lower(Node n, LoweringTool tool) {
+            throw new GraalInternalError("Node implementing Lowerable not handled in HSAIL Backend: " + n);
+        }
+    };
+
+    // strategy to replace an UnwindNode with a DeoptNode
+    static LoweringStrategy UnwindNodeStrategy = new LoweringStrategy() {
+        @Override
+        void lower(Node n, LoweringTool tool) {
+            StructuredGraph graph = (StructuredGraph) n.graph();
+            UnwindNode unwind = (UnwindNode) n;
+            ValueNode exception = unwind.exception();
+            if (exception instanceof ForeignCallNode) {
+                // build up action and reason
+                String callName = ((ForeignCallNode) exception).getDescriptor().getName();
+                DeoptimizationReason reason;
+                switch (callName) {
+                    case "createOutOfBoundsException":
+                        reason = DeoptimizationReason.BoundsCheckException;
+                        break;
+                    case "createNullPointerException":
+                        reason = DeoptimizationReason.NullCheckException;
+                        break;
+                    default:
+                        reason = DeoptimizationReason.None;
+                }
+                unwind.replaceAtPredecessor(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, reason)));
+                unwind.safeDelete();
+            } else {
+                // unwind whose exception is not an instance of ForeignCallNode
+                throw new GraalInternalError("UnwindNode seen without ForeignCallNode: " + exception);
+            }
+        }
+    };
+
+    private static HashMap<Class<?>, LoweringStrategy> strategyMap = new HashMap<>();
+    static {
+        strategyMap.put(ConvertNode.class, PassThruStrategy);
+        strategyMap.put(FloatConvertNode.class, PassThruStrategy);
+        strategyMap.put(NewInstanceNode.class, RejectStrategy);
+        strategyMap.put(NewArrayNode.class, RejectStrategy);
+        strategyMap.put(NewMultiArrayNode.class, RejectStrategy);
+        strategyMap.put(DynamicNewArrayNode.class, RejectStrategy);
+        strategyMap.put(MonitorEnterNode.class, RejectStrategy);
+        strategyMap.put(MonitorExitNode.class, RejectStrategy);
+        strategyMap.put(UnwindNode.class, UnwindNodeStrategy);
+    }
+
+    private static LoweringStrategy getStrategy(Node n) {
+        return strategyMap.get(n.getClass());
+    }
+
     public HSAILHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
         super(runtime, metaAccess, foreignCalls, registers);
     }
 
     @Override
     public void lower(Node n, LoweringTool tool) {
-        if (n instanceof ConvertNode) {
-            return;
+        LoweringStrategy strategy = getStrategy(n);
+        // if not in map, let superclass handle it
+        if (strategy == null) {
+            super.lower(n, tool);
         } else {
-            super.lower(n, tool);
+            strategy.lower(n, tool);
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.hotspot.hsail;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.hsail.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.hsail.*;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
+import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapCompressedOp;
+import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * The HotSpot specific portion of the HSAIL LIR generator.
+ */
+public class HSAILHotSpotNodeLIRGenerator extends HSAILNodeLIRGenerator {
+
+    public HSAILHotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        super(graph, lirGenRes, lirGen);
+    }
+
+    private HSAILHotSpotLIRGenerator getGen() {
+        return (HSAILHotSpotLIRGenerator) gen;
+    }
+
+    /**
+     * Appends either a {@link CompareAndSwapOp} or a {@link CompareAndSwapCompressedOp} depending
+     * on whether the memory location of a given {@link LoweredCompareAndSwapNode} contains a
+     * compressed oop. For the {@link CompareAndSwapCompressedOp} case, allocates a number of
+     * scratch registers. The result {@link #operand(ValueNode) operand} for {@code node} complies
+     * with the API for {@link Unsafe#compareAndSwapInt(Object, long, int, int)}.
+     *
+     * @param address the memory location targeted by the operation
+     */
+    @Override
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
+        Kind kind = node.getNewValue().getKind();
+        assert kind == node.getExpectedValue().getKind();
+        Variable expected = gen.load(operand(node.getExpectedValue()));
+        Variable newValue = gen.load(operand(node.getNewValue()));
+        HSAILAddressValue addressValue = getGen().asAddressValue(address);
+        Variable casResult = newVariable(kind);
+        if (getGen().config.useCompressedOops && node.isCompressible()) {
+            // make 64-bit scratch variables for expected and new
+            Variable scratchExpected64 = newVariable(Kind.Long);
+            Variable scratchNewValue64 = newVariable(Kind.Long);
+            // make 32-bit scratch variables for expected and new and result
+            Variable scratchExpected32 = newVariable(Kind.Int);
+            Variable scratchNewValue32 = newVariable(Kind.Int);
+            Variable scratchCasResult32 = newVariable(Kind.Int);
+            append(new CompareAndSwapCompressedOp(casResult, addressValue, expected, newValue, scratchExpected64, scratchNewValue64, scratchExpected32, scratchNewValue32, scratchCasResult32,
+                            getGen().getNarrowOopBase(), getGen().getNarrowOopShift(), getGen().getLogMinObjectAlignment()));
+        } else {
+            append(new CompareAndSwapOp(casResult, addressValue, expected, newValue));
+        }
+        Variable nodeResult = newVariable(node.getKind());
+        append(new CondMoveOp(HSAILLIRGenerator.mapKindToCompareOp(kind), casResult, expected, nodeResult, Condition.EQ, Constant.INT_1, Constant.INT_0));
+        setResult(node, nodeResult);
+    }
+
+    @Override
+    protected void emitNode(ValueNode node) {
+        if (node instanceof CurrentJavaThreadNode) {
+            throw new GraalInternalError("HSAILHotSpotLIRGenerator cannot handle node: " + node);
+        } else {
+            super.emitNode(node);
+        }
+    }
+
+    /**
+     * @return a compressed version of the incoming constant lifted from AMD64HotSpotLIRGenerator
+     */
+    protected static Constant compress(Constant c, CompressEncoding encoding) {
+        if (c.getKind() == Kind.Long) {
+            return Constant.forIntegerKind(Kind.Int, (int) (((c.asLong() - encoding.base) >> encoding.shift) & 0xffffffffL), c.getPrimitiveAnnotation());
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,6 +39,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.gpu.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -327,13 +328,13 @@
     }
 
     @Override
-    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
         // Omit the frame of the method:
         // - has no spill slots or other slots allocated during register allocation
         // - has no callee-saved registers
         // - has no incoming arguments passed on the stack
         // - has no instructions with debug info
-        FrameMap frameMap = lirGen.frameMap;
+        FrameMap frameMap = lirGenRes.getFrameMap();
         Assembler masm = createAssembler(frameMap);
         PTXFrameContext frameContext = new PTXFrameContext();
         CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
@@ -342,13 +343,23 @@
     }
 
     @Override
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        return new LIRGenerationResultBase(lir, frameMap);
+    }
+
+    @Override
     protected Assembler createAssembler(FrameMap frameMap) {
         return new PTXMacroAssembler(getTarget(), frameMap.registerConfig);
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        return new PTXHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir);
+    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+        return new PTXHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
+    }
+
+    @Override
+    public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        return new PTXHotSpotNodeLIRGenerator(graph, lirGenRes, lirGen);
     }
 
     private static void emitKernelEntry(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod codeCacheOwner) {
@@ -367,14 +378,14 @@
         asm.emitString("");
 
         // Get the start block
-        Block startBlock = lir.getControlFlowGraph().getStartBlock();
+        AbstractBlock<?> startBlock = lir.getControlFlowGraph().getStartBlock();
         // Keep a list of ParameterOp instructions to delete from the
         // list of instructions in the block.
         ArrayList<LIRInstruction> deleteOps = new ArrayList<>();
 
         // Emit .param arguments to kernel entry based on ParameterOp
         // instruction.
-        for (LIRInstruction op : lir.lir(startBlock)) {
+        for (LIRInstruction op : lir.getLIRforBlock(startBlock)) {
             if (op instanceof PTXParameterOp) {
                 op.emitCode(crb);
                 deleteOps.add(op);
@@ -383,7 +394,7 @@
 
         // Delete ParameterOp instructions.
         for (LIRInstruction op : deleteOps) {
-            lir.lir(startBlock).remove(op);
+            lir.getLIRforBlock(startBlock).remove(op);
         }
 
         // Start emiting body of the PTX kernel.
@@ -398,8 +409,8 @@
 
         RegisterAnalysis registerAnalysis = new RegisterAnalysis();
 
-        for (Block b : lir.codeEmittingOrder()) {
-            for (LIRInstruction op : lir.lir(b)) {
+        for (AbstractBlock<?> b : lir.codeEmittingOrder()) {
+            for (LIRInstruction op : lir.getLIRforBlock(b)) {
                 if (op instanceof LabelOp) {
                     // Don't consider this as a definition
                 } else {
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,36 +23,24 @@
 
 package com.oracle.graal.hotspot.ptx;
 
-import com.oracle.graal.api.code.CallingConvention;
-import com.oracle.graal.api.code.StackSlot;
-import com.oracle.graal.api.meta.DeoptimizationAction;
-import com.oracle.graal.api.meta.DeoptimizationReason;
-import com.oracle.graal.api.meta.Value;
-import com.oracle.graal.compiler.ptx.PTXLIRGenerator;
-import com.oracle.graal.graph.GraalInternalError;
-import com.oracle.graal.hotspot.HotSpotLIRGenerator;
-import com.oracle.graal.hotspot.HotSpotVMConfig;
-import com.oracle.graal.hotspot.meta.HotSpotProviders;
-import com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode;
-import com.oracle.graal.lir.FrameMap;
-import com.oracle.graal.lir.LIR;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.ptx.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
 
 /**
  * LIR generator specialized for PTX HotSpot.
  */
 public class PTXHotSpotLIRGenerator extends PTXLIRGenerator implements HotSpotLIRGenerator {
 
-    protected PTXHotSpotLIRGenerator(StructuredGraph graph, HotSpotProviders providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
+    protected PTXHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
         assert config.basicLockSize == 8;
     }
 
-    public void emitPrefetchAllocate(ValueNode address, ValueNode distance) {
-        // nop
-    }
-
     public void emitTailcall(Value[] args, Value address) {
         throw GraalInternalError.unimplemented();
     }
@@ -61,18 +49,6 @@
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitPatchReturnAddress(ValueNode address) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
-        throw GraalInternalError.unimplemented();
-    }
-
     public StackSlot getLockSlot(int lockDepth) {
         throw GraalInternalError.unimplemented();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.hotspot.ptx;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.ptx.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * LIR generator specialized for PTX HotSpot.
+ */
+public class PTXHotSpotNodeLIRGenerator extends PTXNodeLIRGenerator implements HotSpotNodeLIRGenerator {
+
+    protected PTXHotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        super(graph, lirGenRes, lirGen);
+    }
+
+    public void emitPrefetchAllocate(ValueNode address, ValueNode distance) {
+        // nop
+    }
+
+    public void emitPatchReturnAddress(ValueNode address) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        throw GraalInternalError.unimplemented();
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java	Sun Mar 30 16:08:33 2014 +0200
@@ -74,6 +74,11 @@
     }
 
     @Override
+    public boolean areAllAllocatableRegistersCallerSaved() {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
     public Register getRegisterForRole(int index) {
         throw GraalInternalError.unimplemented("PTXHotSpotRegisterConfig.getRegisterForRole()");
     }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -235,7 +235,7 @@
         for (javaParametersIndex = 0; javaParametersIndex < javaParameters.length; javaParametersIndex++) {
             ParameterNode javaParameter = javaParameters[javaParametersIndex];
             int javaParameterOffset = javaParameterOffsetsInKernelParametersBuffer[javaParametersIndex];
-            LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.kind(), javaParameterOffset, getGraph());
+            LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.getKind(), javaParameterOffset, getGraph());
             append(new WriteNode(buf, javaParameter, location, BarrierType.NONE, false, false));
             updateDimArg(method, sig, sigIndex++, args, javaParameter);
         }
@@ -244,13 +244,13 @@
             append(new WriteNode(buf, nullWord, location, BarrierType.NONE, false, false));
         }
 
-        FrameStateBuilder fsb = new FrameStateBuilder(method, getGraph(), true);
+        HIRFrameStateBuilder fsb = new HIRFrameStateBuilder(method, getGraph(), true);
         FrameState fs = fsb.create(0);
         getGraph().start().setStateAfter(fs);
 
         ValueNode[] launchArgsArray = args.values().toArray(new ValueNode[args.size()]);
         ForeignCallNode result = append(new ForeignCallNode(providers.getForeignCalls(), CALL_KERNEL, launchArgsArray));
-        result.setDeoptimizationState(fs);
+        result.setStateAfter(fs);
 
         InvokeNode getObjectResult = null;
         ValueNode returnValue;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,6 +22,12 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import static com.oracle.graal.api.code.CallingConvention.Type.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.sparc.SPARC.*;
+import static java.lang.reflect.Modifier.*;
+
 import java.util.*;
 
 import sun.misc.*;
@@ -30,26 +36,27 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.*;
-import com.oracle.graal.compiler.gen.LIRGenerator;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpne;
+import com.oracle.graal.asm.sparc.SPARCAssembler.CC;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Save;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Stx;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cmp;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Nop;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.RestoreWindow;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
+import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
-import com.oracle.graal.hotspot.stubs.Stub;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
 
-import static com.oracle.graal.sparc.SPARC.*;
-import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
-import static com.oracle.graal.api.code.CallingConvention.Type.*;
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-import static java.lang.reflect.Modifier.*;
-
 /**
  * HotSpot SPARC specific backend.
  */
@@ -72,8 +79,13 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        return new SPARCHotSpotLIRGenerator(graph, stub, getProviders(), getRuntime().getConfig(), frameMap, cc, lir);
+    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+        return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
+    }
+
+    @Override
+    public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        return new SPARCHotSpotNodeLIRGenerator(graph, lirGenRes, lirGen);
     }
 
     /**
@@ -152,10 +164,10 @@
     }
 
     @Override
-    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
-        SPARCHotSpotLIRGenerator gen = (SPARCHotSpotLIRGenerator) lirGen;
-        FrameMap frameMap = gen.frameMap;
-        assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+        SPARCHotSpotLIRGenerationResult gen = (SPARCHotSpotLIRGenerationResult) lirGenRes;
+        FrameMap frameMap = gen.getFrameMap();
+        assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
 
         Stub stub = gen.getStub();
         Assembler masm = createAssembler(frameMap);
@@ -163,7 +175,7 @@
         HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
         CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, frameContext, compilationResult);
         crb.setFrameSize(frameMap.frameSize());
-        StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot;
+        StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
         if (deoptimizationRescueSlot != null && stub == null) {
             crb.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
         }
@@ -179,6 +191,11 @@
     }
 
     @Override
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        return new LIRGenerationResultBase(lir, frameMap);
+    }
+
+    @Override
     public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
         SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
         FrameMap frameMap = crb.frameMap;
@@ -233,4 +250,5 @@
     public NativeFunctionInterface getNativeFunctionInterface() {
         throw GraalInternalError.unimplemented("No NativeFunctionInterface of SPARC");
     }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.hotspot.stubs.*;
+
+public interface SPARCHotSpotLIRGenerationResult extends LIRGenerationResult {
+
+    StackSlot getDeoptimizationRescueSlot();
+
+    Stub getStub();
+
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,11 +23,7 @@
 package com.oracle.graal.hotspot.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.sparc.SPARC.*;
-
-import java.lang.reflect.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -36,27 +32,22 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
 import com.oracle.graal.lir.sparc.SPARCMove.LoadOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
 
-    private final HotSpotVMConfig config;
-    private final Object stub;
+    final HotSpotVMConfig config;
 
-    public SPARCHotSpotLIRGenerator(StructuredGraph graph, Object stub, HotSpotProviders providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) {
-        super(graph, providers, frameMap, cc, lir);
+    public SPARCHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        super(providers, cc, lirGenRes);
         this.config = config;
-        this.stub = stub;
     }
 
     @Override
@@ -69,28 +60,21 @@
      * deoptimization. The return address slot in the callee is overwritten with the address of a
      * deoptimization stub.
      */
-    StackSlot deoptimizationRescueSlot;
-
-    @SuppressWarnings("hiding")
-    @Override
-    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
-        HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long);
-        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
-    }
+    private StackSlot deoptimizationRescueSlot;
 
     @Override
     public StackSlot getLockSlot(int lockDepth) {
-        return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth);
+        return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth);
     }
 
     @Override
     protected boolean needOnlyOopMaps() {
         // Stubs only need oop maps
-        return stub != null;
+        return getStub() != null;
     }
 
-    Stub getStub() {
-        return (Stub) stub;
+    public Stub getStub() {
+        return ((SPARCHotSpotLIRGenerationResult) res).getStub();
     }
 
     @Override
@@ -113,74 +97,17 @@
     }
 
     @Override
-    protected void emitReturn(Value input) {
+    public void emitReturn(Value input) {
         append(new SPARCHotSpotReturnOp(input, getStub() != null));
     }
 
     @Override
-    public void visitSafepointNode(SafepointNode i) {
-        LIRFrameState info = state(i);
-        append(new SPARCHotSpotSafepointOp(info, config, this));
-    }
-
-    @Override
-    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
-        Kind kind = x.newValue().kind();
-        assert kind == x.expectedValue().kind();
-
-        Variable address = load(operand(x.object()));
-        Value offset = operand(x.offset());
-        Variable cmpValue = (Variable) loadNonConst(operand(x.expectedValue()));
-        Variable newValue = load(operand(x.newValue()));
-
-        if (ValueUtil.isConstant(offset)) {
-            assert !getCodeCache().needsDataPatch(asConstant(offset));
-            Variable longAddress = newVariable(Kind.Long);
-            emitMove(longAddress, address);
-            address = emitAdd(longAddress, asConstant(offset));
-        } else {
-            if (isLegal(offset)) {
-                address = emitAdd(address, offset);
-            }
-        }
-
-        append(new CompareAndSwapOp(address, cmpValue, newValue));
-
-        Variable result = newVariable(x.kind());
-        emitMove(result, newValue);
-        setResult(x, result);
-    }
-
-    @Override
     public void emitTailcall(Value[] args, Value address) {
         // append(new AMD64TailcallOp(args, address));
         throw GraalInternalError.unimplemented();
     }
 
     @Override
-    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
-        if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
-            append(new SPARCHotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
-        } else {
-            assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
-            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
-            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
-            Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant();
-            append(new SPARCHotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod));
-        }
-    }
-
-    @Override
-    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        AllocatableValue metaspaceMethod = g5.asValue();
-        emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
-        AllocatableValue targetAddress = g3.asValue();
-        emitMove(targetAddress, operand(callTarget.computedAddress()));
-        append(new SPARCIndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
-    }
-
-    @Override
     public void emitUnwind(Value exception) {
         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
         CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
@@ -214,26 +141,6 @@
         append(new SPARCHotSpotDeoptimizeCallerOp());
     }
 
-    @Override
-    public void emitPatchReturnAddress(ValueNode address) {
-        append(new SPARCHotSpotPatchReturnAddressOp(load(operand(address))));
-    }
-
-    @Override
-    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
-        Variable handler = load(operand(handlerInCallerPc));
-        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
-        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
-        assert linkageCc.getArgumentCount() == 2;
-        RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0);
-        RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1);
-        emitMove(exceptionFixed, operand(exception));
-        emitMove(exceptionPcFixed, operand(exceptionPc));
-        Register thread = getProviders().getRegisters().getThreadRegister();
-        SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, config.threadIsMethodHandleReturnOffset, thread);
-        append(op);
-    }
-
     private static boolean isCompressCandidate(Access access) {
         return access != null && access.isCompressible();
     }
@@ -321,8 +228,7 @@
         return null;
     }
 
-    public void emitPrefetchAllocate(ValueNode address, ValueNode distance) {
-        SPARCAddressValue addr = emitAddress(operand(address), 0, loadNonConst(operand(distance)), 1);
-        append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr));
+    public StackSlot getDeoptimizationRescueSlot() {
+        return deoptimizationRescueSlot;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.sparc.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+
+public class SPARCHotSpotNodeLIRGenerator extends SPARCNodeLIRGenerator implements HotSpotNodeLIRGenerator {
+
+    public SPARCHotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) {
+        super(graph, lirGenRes, lirGen);
+    }
+
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        HotSpotLockStack lockStack = new HotSpotLockStack(res.getFrameMap(), Kind.Long);
+        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
+    }
+
+    private SPARCHotSpotLIRGenerator getGen() {
+        return (SPARCHotSpotLIRGenerator) gen;
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        LIRFrameState info = gen.state(i);
+        append(new SPARCHotSpotSafepointOp(info, getGen().config, gen));
+    }
+
+    @Override
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        Kind kind = x.newValue().getKind();
+        assert kind == x.expectedValue().getKind();
+
+        Variable address = gen.load(operand(x.object()));
+        Value offset = operand(x.offset());
+        Variable cmpValue = (Variable) gen.loadNonConst(operand(x.expectedValue()));
+        Variable newValue = gen.load(operand(x.newValue()));
+
+        if (ValueUtil.isConstant(offset)) {
+            assert !gen.getCodeCache().needsDataPatch(asConstant(offset));
+            Variable longAddress = newVariable(Kind.Long);
+            gen.emitMove(longAddress, address);
+            address = getGen().emitAdd(longAddress, asConstant(offset));
+        } else {
+            if (isLegal(offset)) {
+                address = getGen().emitAdd(address, offset);
+            }
+        }
+
+        append(new CompareAndSwapOp(address, cmpValue, newValue));
+
+        Variable result = newVariable(x.getKind());
+        gen.emitMove(result, newValue);
+        setResult(x, result);
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
+        if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
+            append(new SPARCHotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
+        } else {
+            assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
+            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
+            Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant();
+            append(new SPARCHotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod));
+        }
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        AllocatableValue metaspaceMethod = g5.asValue();
+        gen.emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
+        AllocatableValue targetAddress = g3.asValue();
+        gen.emitMove(targetAddress, operand(callTarget.computedAddress()));
+        append(new SPARCIndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
+    }
+
+    @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        append(new SPARCHotSpotPatchReturnAddressOp(gen.load(operand(address))));
+    }
+
+    @Override
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        Variable handler = gen.load(operand(handlerInCallerPc));
+        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
+        assert linkageCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1);
+        gen.emitMove(exceptionFixed, operand(exception));
+        gen.emitMove(exceptionPcFixed, operand(exceptionPc));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset,
+                        thread);
+        append(op);
+    }
+
+    public void emitPrefetchAllocate(ValueNode address, ValueNode distance) {
+        SPARCAddressValue addr = getGen().emitAddress(operand(address), 0, getGen().loadNonConst(operand(distance)), 1);
+        append(new SPARCPrefetchOp(addr, getGen().config.allocatePrefetchInstr));
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Sun Mar 30 16:08:33 2014 +0200
@@ -144,6 +144,11 @@
     }
 
     @Override
+    public boolean areAllAllocatableRegistersCallerSaved() {
+        return false;
+    }
+
+    @Override
     public Register getRegisterForRole(int index) {
         throw new UnsupportedOperationException();
     }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -67,7 +67,7 @@
     public void testStaticFinalObjectAOT() {
         StructuredGraph result = compile("getStaticFinalObject", true);
         assertEquals(1, getConstantNodes(result).count());
-        assertEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().kind());
+        assertEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().getKind());
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
         assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
@@ -76,7 +76,7 @@
     public void testStaticFinalObject() {
         StructuredGraph result = compile("getStaticFinalObject", false);
         assertEquals(1, getConstantNodes(result).count());
-        assertEquals(Kind.Object, getConstantNodes(result).first().kind());
+        assertEquals(Kind.Object, getConstantNodes(result).first().getKind());
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
         assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
@@ -121,7 +121,7 @@
         StructuredGraph result = compile("getPrimitiveClassObject", true);
         NodeIterable<ConstantNode> filter = getConstantNodes(result);
         assertEquals(1, filter.count());
-        assertEquals(getCodeCache().getTarget().wordKind, filter.first().kind());
+        assertEquals(getCodeCache().getTarget().wordKind, filter.first().getKind());
 
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
         assertEquals(0, result.getNodes().filter(ReadNode.class).count());
@@ -181,7 +181,7 @@
         assertEquals(1, result.getNodes(PiNode.class).count());
         assertEquals(1, getConstantNodes(result).count());
         ConstantNode constant = getConstantNodes(result).first();
-        assertEquals(Kind.Long, constant.kind());
+        assertEquals(Kind.Long, constant.getKind());
         assertEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant());
     }
 
@@ -192,7 +192,7 @@
         assertEquals(0, result.getNodes(PiNode.class).count());
         assertEquals(1, getConstantNodes(result).count());
         ConstantNode constant = getConstantNodes(result).first();
-        assertEquals(Kind.Object, constant.kind());
+        assertEquals(Kind.Object, constant.getKind());
         assertEquals(Boolean.TRUE, constant.asConstant().asObject());
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Sun Mar 30 16:08:33 2014 +0200
@@ -31,6 +31,7 @@
 import static com.oracle.graal.phases.common.InliningUtil.*;
 
 import java.io.*;
+import java.lang.management.*;
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
@@ -39,19 +40,23 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.CompilerThreadFactory.CompilerThread;
+import com.oracle.graal.baseline.*;
+import com.oracle.graal.compiler.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.phases.*;
+import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
 public class CompilationTask implements Runnable, Comparable {
 
     private static final long TIMESTAMP_START = System.currentTimeMillis();
@@ -106,6 +111,12 @@
 
     private boolean blocking;
 
+    /**
+     * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the
+     * current compiler thread, e.g. total allocated bytes.
+     */
+    private final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
+
     public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) {
         this.backend = backend;
         this.method = method;
@@ -128,6 +139,7 @@
         return entryBCI;
     }
 
+    @SuppressFBWarnings(value = "NN_NAKED_NOTIFY")
     public void run() {
         withinEnqueue.set(Boolean.FALSE);
         try {
@@ -208,9 +220,11 @@
          */
 
         HotSpotVMConfig config = backend.getRuntime().getConfig();
+        final long threadId = Thread.currentThread().getId();
         long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue();
         long previousCompilationTime = CompilationTime.getCurrentValue();
         HotSpotInstalledCode installedCode = null;
+
         try (TimerCloseable a = CompilationTime.start()) {
             if (!tryToChangeStatus(CompilationStatus.Queued, CompilationStatus.Running)) {
                 return;
@@ -235,36 +249,45 @@
 
             CompilationResult result = null;
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
-            long start = System.currentTimeMillis();
+            final long start = System.currentTimeMillis();
+            final long allocatedBytesBefore = threadMXBean.getThreadAllocatedBytes(threadId);
+
             try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
-                Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
-                if (GraalOptions.CacheGraphs.getValue()) {
-                    graphCache = new HashMap<>();
-                }
 
-                HotSpotProviders providers = backend.getProviders();
-                Replacements replacements = providers.getReplacements();
-                graph = replacements.getMethodSubstitution(method);
-                if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
-                    graph = new StructuredGraph(method, entryBCI);
+                if (UseBaselineCompiler.getValue() == true) {
+                    HotSpotProviders providers = backend.getProviders();
+                    BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess());
+                    result = baselineCompiler.generate(method, -1, backend, new CompilationResult(), method, CompilationResultBuilderFactory.Default);
                 } else {
-                    // Compiling method substitution - must clone the graph
-                    graph = graph.copy();
+                    Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
+                    if (GraalOptions.CacheGraphs.getValue()) {
+                        graphCache = new HashMap<>();
+                    }
+
+                    HotSpotProviders providers = backend.getProviders();
+                    Replacements replacements = providers.getReplacements();
+                    graph = replacements.getMethodSubstitution(method);
+                    if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
+                        graph = new StructuredGraph(method, entryBCI);
+                    } else {
+                        // Compiling method substitution - must clone the graph
+                        graph = graph.copy();
+                    }
+                    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.
+                        JavaType[] parameterTypes = new JavaType[]{providers.getMetaAccess().lookupJavaType(long.class)};
+                        CallingConvention tmp = providers.getCodeCache().getRegisterConfig().getCallingConvention(JavaCallee, providers.getMetaAccess().lookupJavaType(void.class), parameterTypes,
+                                        backend.getTarget(), false);
+                        cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
+                    }
+                    Suites suites = getSuites(providers);
+                    ProfilingInfo profilingInfo = getProfilingInfo();
+                    OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
+                    result = compileGraph(graph, null, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
+                                    method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default);
                 }
-                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.
-                    JavaType[] parameterTypes = new JavaType[]{providers.getMetaAccess().lookupJavaType(long.class)};
-                    CallingConvention tmp = providers.getCodeCache().getRegisterConfig().getCallingConvention(JavaCallee, providers.getMetaAccess().lookupJavaType(void.class), parameterTypes,
-                                    backend.getTarget(), false);
-                    cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
-                }
-                Suites suites = getSuites(providers);
-                ProfilingInfo profilingInfo = getProfilingInfo();
-                OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
-                result = compileGraph(graph, null, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
-                                method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default);
                 result.setId(getId());
                 result.setEntryBCI(entryBCI);
             } catch (Throwable e) {
@@ -272,10 +295,18 @@
             } finally {
                 filter.remove();
                 final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
-                if (printAfterCompilation) {
-                    TTY.println(getMethodDescription() + String.format(" | %4dms %5dB", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1)));
-                } else if (printCompilation) {
-                    TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1)));
+
+                if (printAfterCompilation || printCompilation) {
+                    final long stop = System.currentTimeMillis();
+                    final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1;
+                    final long allocatedBytesAfter = threadMXBean.getThreadAllocatedBytes(threadId);
+                    final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
+
+                    if (printAfterCompilation) {
+                        TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes));
+                    } else if (printCompilation) {
+                        TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB %5dkB", id, "", "", "", stop - start, targetCodeSize, allocatedBytes));
+                    }
                 }
             }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Sun Mar 30 16:08:33 2014 +0200
@@ -113,8 +113,8 @@
                 return value;
             }
         };
-        for (Block block : lir.codeEmittingOrder()) {
-            for (LIRInstruction op : lir.lir(block)) {
+        for (AbstractBlock<?> block : lir.codeEmittingOrder()) {
+            for (LIRInstruction op : lir.getLIRforBlock(block)) {
                 if (op instanceof LabelOp) {
                     // Don't consider this as a definition
                 } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,13 +26,11 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
  * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
- * to abstract methods from {@link LIRGenerator} and {@link LIRGeneratorTool}.
+ * to abstract methods from {@link LIRGenerator} and {@link NodeLIRGeneratorTool}.
  */
 public interface HotSpotLIRGenerator {
 
@@ -46,14 +44,6 @@
 
     void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
 
-    void emitPatchReturnAddress(ValueNode address);
-
-    void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc);
-
-    void emitPrefetchAllocate(ValueNode address, ValueNode distance);
-
-    void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
-
     /**
      * Gets a stack slot for a lock at a given lock nesting depth.
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
+ * to abstract methods from {@link LIRGenerator} and {@link NodeLIRGeneratorTool}.
+ */
+public interface HotSpotNodeLIRGenerator {
+
+    void emitPatchReturnAddress(ValueNode address);
+
+    void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc);
+
+    void emitPrefetchAllocate(ValueNode address, ValueNode distance);
+
+    void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Sun Mar 30 16:08:33 2014 +0200
@@ -76,6 +76,18 @@
         }
     }
 
+    public PlatformKind getRegister(int idx) {
+        int refMapIndex = idx * 2;
+        if (registerRefMap.get(refMapIndex)) {
+            if (registerRefMap.get(refMapIndex + 1)) {
+                return NarrowOopStamp.NarrowOop;
+            } else {
+                return Kind.Object;
+            }
+        }
+        return null;
+    }
+
     public void setStackSlot(int offset, PlatformKind kind) {
         int idx = offset / frameSlotSize;
         if (kind == Kind.Object) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sun Mar 30 16:08:33 2014 +0200
@@ -1005,6 +1005,24 @@
     @HotSpotVMField(name = "ThreadShadow::_pending_failed_speculation", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingFailedSpeculationOffset;
 
     /**
+     * Offsets of Hsail deoptimization fields (defined in gpu_hsail.hpp). Used to propagate
+     * exceptions from Hsail back to C++ runtime.
+     */
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[0]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset0;
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[1]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset1;
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_occurred", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptOffset;
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_never_ran_array", type = "jboolean *", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNeverRanArrayOffset;
+    @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_next_index", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptNextIndexOffset;
+
+    @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_workitemid", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationWorkItem;
+    @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_actionAndReason", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationReason;
+    @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_first_frame", type = "HSAILFrame", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationFrame;
+
+    @HotSpotVMField(name = "HSAILFrame::_pc_offset", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFramePcOffset;
+    @HotSpotVMField(name = "HSAILFrame::_num_s_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumSRegOffset;
+    @HotSpotVMField(name = "HSAILFrame::_save_area[0]", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameSaveAreaOffset;
+
+    /**
      * Mark word right shift to get identity hash code.
      */
     @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public int identityHashCodeShift;
@@ -1022,8 +1040,15 @@
     @HotSpotVMField(name = "Method::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int methodAccessFlagsOffset;
     @HotSpotVMField(name = "Method::_constMethod", type = "ConstMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodConstMethodOffset;
     @HotSpotVMField(name = "Method::_intrinsic_id", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodIntrinsicIdOffset;
+    @HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset;
     @HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset;
 
+    @HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite;
+    @HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive;
+    @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline;
+    @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline;
+    @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden;
+
     @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
     @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
 
@@ -1276,6 +1301,7 @@
     @HotSpotVMConstant(name = "DataLayout::call_type_data_tag") @Stable public int dataLayoutCallTypeDataTag;
     @HotSpotVMConstant(name = "DataLayout::virtual_call_type_data_tag") @Stable public int dataLayoutVirtualCallTypeDataTag;
     @HotSpotVMConstant(name = "DataLayout::parameters_type_data_tag") @Stable public int dataLayoutParametersTypeDataTag;
+    @HotSpotVMConstant(name = "DataLayout::speculative_trap_data_tag") @Stable public int dataLayoutSpeculativeTrapDataTag;
 
     @HotSpotVMFlag(name = "BciProfileWidth") @Stable public int bciProfileWidth;
     @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Sun Mar 30 16:08:33 2014 +0200
@@ -99,12 +99,12 @@
     long getKlassImplementor(long metaspaceKlass);
 
     /**
-     * Initializes a {@link HotSpotResolvedJavaMethod} object from a metaspace Method object.
+     * Determines if a given metaspace method is ignored by security stack walks.
      * 
      * @param metaspaceMethod the metaspace Method object
-     * @param method address of a metaspace Method object
+     * @return true if the method is ignored
      */
-    void initializeMethod(long metaspaceMethod, HotSpotResolvedJavaMethod method);
+    boolean methodIsIgnoredBySecurityStackWalk(long metaspaceMethod);
 
     /**
      * Converts a name to a metaspace klass.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Sun Mar 30 16:08:33 2014 +0200
@@ -104,8 +104,7 @@
     @Override
     public native boolean hasFinalizableSubclass(long metaspaceKlass);
 
-    @Override
-    public native void initializeMethod(long metaspaceMethod, HotSpotResolvedJavaMethod method);
+    public native boolean methodIsIgnoredBySecurityStackWalk(long metaspaceMethod);
 
     @Override
     public native long getClassInitializer(long metaspaceKlass);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,7 +33,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.CompilerThreadFactory.CompilerThread;
 import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/OopData.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/OopData.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 
 /**
@@ -39,6 +40,7 @@
 
     public OopData(int alignment, Object object, boolean compressed) {
         super(alignment);
+        assert !compressed || HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
         this.object = object;
         this.compressed = compressed;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.debug;
 
 import java.io.*;
-import java.text.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
@@ -36,8 +35,8 @@
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
@@ -45,22 +44,24 @@
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.nodes.*;
 
+import edu.umd.cs.findbugs.annotations.*;
+
 /**
  * This class contains infrastructure to maintain counters based on {@link DynamicCounterNode}s. The
  * infrastructure is enabled by specifying either the GenericDynamicCounters or
  * BenchmarkDynamicCounters option.<br/>
- * 
+ *
  * The counters are kept in a special area allocated for each native JavaThread object, and the
  * number of counters is configured using {@code -XX:GraalCounterSize=value}.
  * {@code -XX:+/-GraalCountersExcludeCompiler} configures whether to exclude compiler threads
  * (defaults to true).
- * 
+ *
  * The subsystems that use the logging need to have their own options to turn on the counters, and
  * insert DynamicCounterNodes when they're enabled.
- * 
+ *
  * Counters will be displayed as a rate (per second) if their group name starts with "~", otherwise
  * they will be displayed as a total number.
- * 
+ *
  * <h1>Example</h1> In order to create statistics about allocations within the DaCapo pmd benchmark
  * the following steps are necessary:
  * <ul>
@@ -83,6 +84,8 @@
         //@formatter:off
         @Option(help = "Turn on the benchmark counters, and displays the results on VM shutdown")
         private static final OptionValue<Boolean> GenericDynamicCounters = new OptionValue<>(false);
+        @Option(help = "Turn on the benchmark counters, and displays the results every n milliseconds")
+        private static final OptionValue<Integer> TimedDynamicCounters = new OptionValue<>(-1);
 
         @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" +
                        "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" +
@@ -103,13 +106,15 @@
     public static long[] delta;
     public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>();
 
+    @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
     public static int getIndex(DynamicCounterNode counter) {
         if (!enabled) {
             throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName());
         }
         String name = counter.getName();
         String group = counter.getGroup();
-        name = counter.isWithContext() ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name + "#" + group;
+        name = counter.isWithContext() && counter.graph().method() != null ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name +
+                        "#" + group;
         Integer index = indexes.get(name);
         if (index == null) {
             synchronized (BenchmarkCounters.class) {
@@ -129,15 +134,15 @@
         return index;
     }
 
-    public static synchronized void dump(PrintStream out, double seconds, long[] counters) {
+    public static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
         if (!groups.isEmpty()) {
             out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======");
             for (String group : new TreeSet<>(groups)) {
                 if (group != null) {
                     if (DUMP_STATIC) {
-                        dumpCounters(out, seconds, counters, true, group);
+                        dumpCounters(out, seconds, counters, true, group, maxRows);
                     }
-                    dumpCounters(out, seconds, counters, false, group);
+                    dumpCounters(out, seconds, counters, false, group, maxRows);
                 }
             }
             out.println("============================");
@@ -150,9 +155,10 @@
         delta = counters;
     }
 
-    private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group) {
+    private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group, int maxRows) {
         TreeMap<Long, String> sorted = new TreeMap<>();
 
+        // collect the numbers
         long[] array;
         if (staticCounter) {
             array = new long[indexes.size()];
@@ -165,6 +171,7 @@
                 array[i] -= delta[i];
             }
         }
+        // sort the counters by putting them into a sorted map
         long sum = 0;
         for (Map.Entry<String, Integer> entry : indexes.entrySet()) {
             int index = entry.getValue();
@@ -175,41 +182,51 @@
         }
 
         if (sum > 0) {
-            NumberFormat format = NumberFormat.getInstance(Locale.US);
             long cutoff = sorted.size() < 10 ? 1 : Math.max(1, sum / 100);
+            int cnt = sorted.size();
+
+            // remove everything below cutoff and keep at most maxRows
+            Iterator<Map.Entry<Long, String>> iter = sorted.entrySet().iterator();
+            while (iter.hasNext()) {
+                Map.Entry<Long, String> entry = iter.next();
+                long counter = entry.getKey() / array.length;
+                if (counter < cutoff || cnt > maxRows) {
+                    iter.remove();
+                }
+                cnt--;
+            }
+
             if (staticCounter) {
                 out.println("=========== " + group + " (static counters):");
                 for (Map.Entry<Long, String> entry : sorted.entrySet()) {
                     long counter = entry.getKey() / array.length;
-                    if (counter >= cutoff) {
-                        out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
-                    }
+                    out.format(Locale.US, "%,19d %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
                 }
-                out.println(sum + ": total");
+                out.format(Locale.US, "%,19d total\n", sum);
             } else {
                 if (group.startsWith("~")) {
                     out.println("=========== " + group + " (dynamic counters), time = " + seconds + " s:");
                     for (Map.Entry<Long, String> entry : sorted.entrySet()) {
                         long counter = entry.getKey() / array.length;
-                        if (counter >= cutoff) {
-                            out.println(format.format((long) (counter / seconds)) + "/s \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
-                        }
+                        out.format(Locale.US, "%,19d/s %3d%%  %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue());
                     }
-                    out.println(format.format((long) (sum / seconds)) + "/s: total");
+                    out.format(Locale.US, "%,19d/s total\n", (long) (sum / seconds));
                 } else {
                     out.println("=========== " + group + " (dynamic counters):");
                     for (Map.Entry<Long, String> entry : sorted.entrySet()) {
                         long counter = entry.getKey() / array.length;
-                        if (counter >= cutoff) {
-                            out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
-                        }
+                        out.format(Locale.US, "%,19d %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
                     }
-                    out.println(format.format(sum) + ": total");
+                    out.format(Locale.US, "%,19d total\n", sum);
                 }
             }
         }
     }
 
+    private static long percentage(long counter, long sum) {
+        return (counter * 200 + 1) / sum / 2;
+    }
+
     public abstract static class CallbackOutputStream extends OutputStream {
 
         protected final PrintStream delegate;
@@ -282,7 +299,7 @@
                     case 2:
                         if (waitingForEnd) {
                             waitingForEnd = false;
-                            BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters());
+                            BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters(), 100);
                         }
                         break;
                 }
@@ -309,20 +326,43 @@
         if (Options.GenericDynamicCounters.getValue()) {
             enabled = true;
         }
-        if (Options.GenericDynamicCounters.getValue() || Options.BenchmarkDynamicCounters.getValue() != null) {
+        if (Options.TimedDynamicCounters.getValue() > 0) {
+            Thread thread = new Thread() {
+                long lastTime = System.nanoTime();
+                PrintStream out = System.out;
+
+                @Override
+                public void run() {
+                    while (true) {
+                        try {
+                            Thread.sleep(Options.TimedDynamicCounters.getValue());
+                        } catch (InterruptedException e) {
+                        }
+                        long time = System.nanoTime();
+                        dump(out, (time - lastTime) / 1000000000d, compilerToVM.collectCounters(), 10);
+                        lastTime = time;
+                    }
+                }
+            };
+            thread.setDaemon(true);
+            thread.setPriority(Thread.MAX_PRIORITY);
+            thread.start();
+            enabled = true;
+        }
+        if (enabled) {
             clear(compilerToVM.collectCounters());
         }
     }
 
     public static void shutdown(CompilerToVM compilerToVM, long compilerStartTime) {
         if (Options.GenericDynamicCounters.getValue()) {
-            dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters());
+            dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters(), 100);
         }
     }
 
     public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) {
         StructuredGraph graph = counter.graph();
-        if (excludedClassPrefix == null || !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
+        if (excludedClassPrefix == null || (counter.graph().method() != null && !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix))) {
 
             ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.logging;
 
+import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
@@ -94,16 +95,15 @@
         }
     }
 
-    // CheckStyle: stop system..print check
     protected void print() {
         long sum = 0;
+        PrintStream out = System.out;
         for (Map.Entry<Method, AtomicLong> entry : calls.entrySet()) {
             Method method = entry.getKey();
             long count = entry.getValue().get();
             sum += count;
-            System.out.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count);
+            out.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count);
         }
-        System.out.println(delegate.getClass().getSimpleName() + " calls: " + sum);
+        out.println(delegate.getClass().getSimpleName() + " calls: " + sum);
     }
-    // CheckStyle: resume system..print check
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Sun Mar 30 16:08:33 2014 +0200
@@ -259,9 +259,9 @@
         StructuredGraph graph = loadField.graph();
         HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
         ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object();
-        assert loadField.kind() != Kind.Illegal;
+        assert loadField.getKind() != Kind.Illegal;
         BarrierType barrierType = getFieldLoadBarrierType(field);
-        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
+        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.getKind() == Kind.Object)));
         graph.replaceFixedWithFixed(loadField, memoryRead);
         memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
 
@@ -296,9 +296,9 @@
     private static void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
         // Separate out GC barrier semantics
         StructuredGraph graph = cas.graph();
-        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
+        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().getKind(), cas.displacement(), cas.offset(), graph, 1);
         LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas),
-                        cas.expected().kind() == Kind.Object));
+                        cas.expected().getKind() == Kind.Object));
         atomicNode.setStateAfter(cas.stateAfter());
         graph.replaceFixedWithFixed(cas, atomicNode);
     }
@@ -372,7 +372,7 @@
             graph.replaceFixedWithFixed(load, valueAnchorNode);
             graph.addAfterFixed(valueAnchorNode, memoryRead);
         } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
-            assert load.kind() != Kind.Illegal;
+            assert load.getKind() != Kind.Illegal;
             boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
             if (addReadBarrier(load)) {
                 unsafeLoadSnippets.lower(load, tool);
@@ -392,7 +392,7 @@
         LocationNode location = createLocation(store);
         ValueNode object = store.object();
         BarrierType barrierType = getUnsafeStoreBarrierType(store);
-        WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object));
+        WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().getKind() == Kind.Object));
         write.setStateAfter(store.stateAfter());
         graph.replaceFixedWithFixed(store, write);
     }
@@ -401,7 +401,7 @@
         StructuredGraph graph = loadHub.graph();
         if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
             Kind wordKind = runtime.getTarget().wordKind;
-            assert loadHub.kind() == wordKind;
+            assert loadHub.getKind() == wordKind;
             ValueNode object = loadHub.object();
             GuardingNode guard = loadHub.getGuard();
             FloatingReadNode hub = createReadHub(graph, wordKind, object, guard);
@@ -447,7 +447,7 @@
                         omittedValues.set(valuePos);
                     } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
                         // Constant.illegal is always the defaultForKind, so it is skipped
-                        Kind valueKind = value.kind();
+                        Kind valueKind = value.getKind();
                         Kind entryKind = virtual.entryKind(i);
 
                         // Truffle requires some leniency in terms of what can be put where:
@@ -483,7 +483,7 @@
                         assert value instanceof VirtualObjectNode;
                         ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
                         if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                            assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object;
+                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
                             WriteNode write;
                             if (virtual instanceof VirtualInstanceNode) {
                                 VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
@@ -520,9 +520,9 @@
             // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
             int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
             for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
-                int size = FrameStateBuilder.stackSlots(osrLocal.kind());
+                int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind());
                 int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
-                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1);
+                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1);
                 ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
                 osrLocal.replaceAndDelete(load);
                 graph.addBeforeFixed(migrationEnd, load);
@@ -606,7 +606,7 @@
     }
 
     private static boolean addReadBarrier(UnsafeLoadNode load) {
-        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object &&
+        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
                         !ObjectStamp.isObjectAlwaysNull(load.object())) {
             ResolvedJavaType type = ObjectStamp.typeOrNull(load.object());
             if (type != null && !type.isArray()) {
@@ -669,7 +669,7 @@
 
     private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
         BarrierType barrierType = BarrierType.NONE;
-        if (store.value().kind() == Kind.Object) {
+        if (store.value().getKind() == Kind.Object) {
             ResolvedJavaType type = ObjectStamp.typeOrNull(store.object());
             if (type != null && !type.isArray()) {
                 barrierType = BarrierType.IMPRECISE;
@@ -682,7 +682,7 @@
 
     private static BarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) {
         BarrierType barrierType = BarrierType.NONE;
-        if (cas.expected().kind() == Kind.Object) {
+        if (cas.expected().getKind() == Kind.Object) {
             ResolvedJavaType type = ObjectStamp.typeOrNull(cas.object());
             if (type != null && !type.isArray()) {
                 barrierType = BarrierType.IMPRECISE;
@@ -763,6 +763,15 @@
             arrayLength = readArrayLength;
         }
 
+        if (arrayLength.isConstant() && n.index().isConstant()) {
+            int l = arrayLength.asConstant().asInt();
+            int i = n.index().asConstant().asInt();
+            if (i >= 0 && i < l) {
+                // unneeded range check
+                return null;
+            }
+        }
+
         return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,11 +23,15 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.debug.Debug.*;
+import static java.util.FormattableFlags.*;
+
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.*;
 
-public abstract class HotSpotMethod extends CompilerObject implements JavaMethod {
+public abstract class HotSpotMethod extends CompilerObject implements JavaMethod, Formattable {
 
     private static final long serialVersionUID = 7167491397941960839L;
     protected String name;
@@ -54,4 +58,9 @@
         String fmt = String.format("HotSpotMethod<%%%c.%%n(%%p)%s>", h, suffix);
         return format(fmt, this);
     }
+
+    public void formatTo(Formatter formatter, int flags, int width, int precision) {
+        String base = (flags & ALTERNATE) == ALTERNATE ? getName() : toString();
+        formatter.format(applyFormattingFlagsAndWidth(base, flags & ~ALTERNATE, width));
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.HotSpotMethodDataAccessor.Tag;
 
 /**
  * Access to a HotSpot MethodData structure (defined in methodData.hpp).
@@ -57,7 +58,11 @@
         new RetData(),
         new BranchData(),
         new MultiBranchData(),
-        new ArgInfoData()
+        new ArgInfoData(),
+        null, // call_type_data_tag
+        null, // virtual_call_type_data_tag
+        null, // parameters_type_data_tag
+        null  // speculative_trap_data_tag
     };
     // @formatter:on
 
@@ -146,9 +151,10 @@
 
     private HotSpotMethodDataAccessor getData(int position) {
         assert position >= 0 : "out of bounds";
-        int tag = AbstractMethodData.readTag(this, position);
-        assert tag >= 0 && tag < PROFILE_DATA_ACCESSORS.length : "illegal tag " + tag;
-        return PROFILE_DATA_ACCESSORS[tag];
+        final Tag tag = AbstractMethodData.readTag(this, position);
+        HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag.getValue()];
+        assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag;
+        return accessor;
     }
 
     private int readUnsignedByte(int position, int offsetInBytes) {
@@ -258,20 +264,21 @@
          */
         private static final int EXCEPTIONS_MASK = 0x2;
 
-        private final int tag;
+        private final Tag tag;
         private final int staticSize;
 
-        protected AbstractMethodData(int tag, int staticSize) {
+        protected AbstractMethodData(Tag tag, int staticSize) {
             this.tag = tag;
             this.staticSize = staticSize;
         }
 
-        public int getTag() {
+        public Tag getTag() {
             return tag;
         }
 
-        public static int readTag(HotSpotMethodData data, int position) {
-            return data.readUnsignedByte(position, config.dataLayoutTagOffset);
+        public static Tag readTag(HotSpotMethodData data, int position) {
+            final int tag = data.readUnsignedByte(position, config.dataLayoutTagOffset);
+            return Tag.getEnum(tag);
         }
 
         @Override
@@ -337,7 +344,7 @@
         private final TriState exceptionSeen;
 
         protected NoMethodData(TriState exceptionSeen) {
-            super(runtime().getConfig().dataLayoutNoTag, NO_DATA_SIZE);
+            super(Tag.No, NO_DATA_SIZE);
             this.exceptionSeen = exceptionSeen;
         }
 
@@ -363,10 +370,10 @@
         private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01;
 
         private BitData() {
-            super(runtime().getConfig().dataLayoutBitDataTag, BIT_DATA_SIZE);
+            super(Tag.BitData, BIT_DATA_SIZE);
         }
 
-        protected BitData(int tag, int staticSize) {
+        protected BitData(Tag tag, int staticSize) {
             super(tag, staticSize);
         }
 
@@ -387,10 +394,10 @@
         private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0);
 
         public CounterData() {
-            super(runtime().getConfig().dataLayoutCounterDataTag, COUNTER_DATA_SIZE);
+            super(Tag.CounterData, COUNTER_DATA_SIZE);
         }
 
-        protected CounterData(int tag, int staticSize) {
+        protected CounterData(Tag tag, int staticSize) {
             super(tag, staticSize);
         }
 
@@ -416,10 +423,10 @@
         protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1);
 
         public JumpData() {
-            super(runtime().getConfig().dataLayoutJumpDataTag, JUMP_DATA_SIZE);
+            super(Tag.JumpData, JUMP_DATA_SIZE);
         }
 
-        protected JumpData(int tag, int staticSize) {
+        protected JumpData(Tag tag, int staticSize) {
             super(tag, staticSize);
         }
 
@@ -465,7 +472,7 @@
         protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2);
         protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3);
 
-        protected AbstractTypeData(int tag, int staticSize) {
+        protected AbstractTypeData(Tag tag, int staticSize) {
             super(tag, staticSize);
         }
 
@@ -548,7 +555,7 @@
         private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
 
         public TypeCheckData() {
-            super(runtime().getConfig().dataLayoutReceiverTypeDataTag, TYPE_CHECK_DATA_SIZE);
+            super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE);
         }
 
         @Override
@@ -569,12 +576,12 @@
         private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
 
         public VirtualCallData() {
-            super(runtime().getConfig().dataLayoutVirtualCallDataTag, VIRTUAL_CALL_DATA_SIZE);
+            super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE);
         }
 
         @Override
         public int getExecutionCount(HotSpotMethodData data, int position) {
-            int typeProfileWidth = config.typeProfileWidth;
+            final int typeProfileWidth = config.typeProfileWidth;
 
             long total = 0;
             for (int i = 0; i < typeProfileWidth; i++) {
@@ -670,7 +677,7 @@
         private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth;
 
         public RetData() {
-            super(runtime().getConfig().dataLayoutRetDataTag, RET_DATA_SIZE);
+            super(Tag.RetData, RET_DATA_SIZE);
         }
     }
 
@@ -680,7 +687,7 @@
         private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2);
 
         public BranchData() {
-            super(runtime().getConfig().dataLayoutBranchDataTag, BRANCH_DATA_SIZE);
+            super(Tag.BranchData, BRANCH_DATA_SIZE);
         }
 
         @Override
@@ -712,7 +719,7 @@
         private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0);
         protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1);
 
-        public ArrayData(int tag, int staticSize) {
+        public ArrayData(Tag tag, int staticSize) {
             super(tag, staticSize);
         }
 
@@ -740,7 +747,7 @@
         private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1);
 
         public MultiBranchData() {
-            super(runtime().getConfig().dataLayoutMultiBranchDataTag, MULTI_BRANCH_DATA_SIZE);
+            super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE);
         }
 
         @Override
@@ -822,7 +829,7 @@
         private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1);
 
         public ArgInfoData() {
-            super(runtime().getConfig().dataLayoutArgInfoDataTag, ARG_INFO_DATA_SIZE);
+            super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,8 +22,12 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
 
 /**
  * Interface for accessor objects that encapsulate the logic for accessing the different kinds of
@@ -33,11 +37,54 @@
 public interface HotSpotMethodDataAccessor {
 
     /**
-     * Returns the tag stored in the LayoutData header.
+     * {@code DataLayout} tag values.
+     */
+    enum Tag {
+        No(config().dataLayoutNoTag),
+        BitData(config().dataLayoutBitDataTag),
+        CounterData(config().dataLayoutCounterDataTag),
+        JumpData(config().dataLayoutJumpDataTag),
+        ReceiverTypeData(config().dataLayoutReceiverTypeDataTag),
+        VirtualCallData(config().dataLayoutVirtualCallDataTag),
+        RetData(config().dataLayoutRetDataTag),
+        BranchData(config().dataLayoutBranchDataTag),
+        MultiBranchData(config().dataLayoutMultiBranchDataTag),
+        ArgInfoData(config().dataLayoutArgInfoDataTag),
+        CallTypeData(config().dataLayoutCallTypeDataTag),
+        VirtualCallTypeData(config().dataLayoutVirtualCallTypeDataTag),
+        ParametersTypeData(config().dataLayoutParametersTypeDataTag),
+        SpeculativeTrapData(config().dataLayoutSpeculativeTrapDataTag);
+
+        private final int value;
+
+        private Tag(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        private static HotSpotVMConfig config() {
+            return runtime().getConfig();
+        }
+
+        public static Tag getEnum(int value) {
+            for (Tag e : values()) {
+                if (e.value == value) {
+                    return e;
+                }
+            }
+            throw GraalInternalError.shouldNotReachHere("unknown enum value " + value);
+        }
+    }
+
+    /**
+     * Returns the {@link Tag} stored in the LayoutData header.
      * 
-     * @return An integer >= 0 or -1 if not supported.
+     * @return tag stored in the LayoutData header
      */
-    int getTag();
+    Tag getTag();
 
     /**
      * Returns the BCI stored in the LayoutData header.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Sun Mar 30 16:08:33 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,10 +53,6 @@
     private final HotSpotResolvedObjectType holder;
     private final HotSpotConstantPool constantPool;
     private final HotSpotSignature signature;
-    private boolean callerSensitive;
-    private boolean forceInline;
-    private boolean dontInline;
-    private boolean ignoredBySecurityStackWalk;
     private HotSpotMethodData methodData;
     private byte[] code;
     private SpeculationLog speculationLog;
@@ -109,8 +105,6 @@
 
         final int signatureIndex = unsafe.getChar(constMethod + config.constMethodSignatureIndexOffset);
         this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex);
-
-        runtime().getCompilerToVM().initializeMethod(metaspaceMethod, this);
     }
 
     /**
@@ -139,11 +133,20 @@
     }
 
     /**
+     * Returns this method's flags ({@code Method::_flags}).
+     * 
+     * @return flags of this method
+     */
+    private int getFlags() {
+        return unsafe.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset);
+    }
+
+    /**
      * Returns this method's constant method flags ({@code ConstMethod::_flags}).
      * 
      * @return flags of this method's ConstMethod
      */
-    private long getConstMethodFlags() {
+    private int getConstMethodFlags() {
         return unsafe.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset);
     }
 
@@ -169,8 +172,7 @@
      * modifiers as well as the HotSpot internal modifiers.
      */
     public int getAllModifiers() {
-        HotSpotVMConfig config = runtime().getConfig();
-        return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset);
+        return unsafe.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset);
     }
 
     @Override
@@ -245,19 +247,36 @@
     }
 
     /**
-     * Returns true if this method has a CallerSensitive annotation.
+     * Returns true if this method has a {@code CallerSensitive} annotation.
      * 
      * @return true if CallerSensitive annotation present, false otherwise
      */
     public boolean isCallerSensitive() {
-        return callerSensitive;
+        return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0;
+    }
+
+    /**
+     * Returns true if this method has a {@code ForceInline} annotation.
+     * 
+     * @return true if ForceInline annotation present, false otherwise
+     */
+    public boolean isForceInline() {
+        return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0;
+    }
+
+    /**
+     * Returns true if this method has a {@code DontInline} annotation.
+     * 
+     * @return true if DontInline annotation present, false otherwise
+     */
+    public boolean isDontInline() {
+        return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0;
     }
 
     /**
      * Manually adds a DontInline annotation to this method.
      */
     public void setNotInlineable() {
-        dontInline = true;
         runtime().getCompilerToVM().doNotInlineOrCompile(metaspaceMethod);
     }
 
@@ -268,7 +287,7 @@
      * @return true if special method ignored by security stack walks, false otherwise
      */
     public boolean ignoredBySecurityStackWalk() {
-        return ignoredBySecurityStackWalk;
+        return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(metaspaceMethod);
     }
 
     public boolean hasBalancedMonitors() {
@@ -502,7 +521,7 @@
 
     @Override
     public boolean canBeInlined() {
-        if (dontInline) {
+        if (isDontInline()) {
             return false;
         }
         return runtime().getCompilerToVM().canInlineMethod(metaspaceMethod);
@@ -510,7 +529,7 @@
 
     @Override
     public boolean shouldBeInlined() {
-        if (forceInline) {
+        if (isForceInline()) {
             return true;
         }
         return runtime().getCompilerToVM().shouldInlineMethod(metaspaceMethod);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Sun Mar 30 16:08:33 2014 +0200
@@ -122,7 +122,7 @@
     public int getParameterSlots(boolean withReceiver) {
         int argSlots = 0;
         for (int i = 0; i < getParameterCount(false); i++) {
-            argSlots += FrameStateBuilder.stackSlots(getParameterKind(i));
+            argSlots += HIRFrameStateBuilder.stackSlots(getParameterKind(i));
         }
         return argSlots + (withReceiver ? 1 : 0);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -79,12 +79,12 @@
 
             // box result
             BoxNode boxedResult;
-            if (callNode.kind() != Kind.Void) {
-                if (callNode.kind() == Kind.Object) {
+            if (callNode.getKind() != Kind.Void) {
+                if (callNode.getKind() == Kind.Object) {
                     throw new IllegalArgumentException("Return type not supported: " + returnType.getName());
                 }
-                ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(callNode.kind().toBoxedJavaClass());
-                boxedResult = g.unique(new BoxNode(callNode, type, callNode.kind()));
+                ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(callNode.getKind().toBoxedJavaClass());
+                boxedResult = g.unique(new BoxNode(callNode, type, callNode.getKind()));
             } else {
                 boxedResult = g.unique(new BoxNode(ConstantNode.forLong(0, g), providers.getMetaAccess().lookupJavaType(Long.class), Kind.Long));
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,13 +30,14 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for
  * the entire execution of the associated method.
  */
-public final class AllocaNode extends FixedWithNextNode implements LIRGenLowerable {
+public final class AllocaNode extends FixedWithNextNode implements LIRGenResLowerable {
 
     /**
      * The number of slots in block.
@@ -57,9 +58,9 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        StackSlot array = gen.frameMap().allocateStackSlots(slots, objects, null);
-        Value result = gen.emitAddress(array);
+    public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) {
+        StackSlot array = res.getFrameMap().allocateStackSlots(slots, objects, null);
+        Value result = gen.getLIRGeneratorTool().emitAddress(array);
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -57,11 +57,11 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGenerator gen) {
         assert lockDepth != -1;
-        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         StackSlot slot = hsGen.getLockSlot(lockDepth);
-        Value result = gen.emitAddress(slot);
+        Value result = gen.getLIRGeneratorTool().emitAddress(slot);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,18 +22,17 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
-
-import com.oracle.graal.nodes.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
- * Converts a compile-time constant Java string into a malloc'ed C string. The malloc'ed string is
- * never reclaimed so this should only be used for strings in permanent code such as compiled stubs.
+ * Converts a compile-time constant Java string into a C string installed with the generated code.
  */
-public final class CStringNode extends FloatingNode implements Lowerable {
+public final class CStringNode extends FloatingNode implements LIRGenLowerable {
 
     private final String string;
 
@@ -42,16 +41,29 @@
         this.string = string;
     }
 
-    @Override
-    public void lower(LoweringTool tool) {
-        byte[] formatBytes = string.getBytes();
-        long cstring = unsafe.allocateMemory(formatBytes.length + 1);
-        for (int i = 0; i < formatBytes.length; i++) {
-            unsafe.putByte(cstring + i, formatBytes[i]);
+    public void generate(NodeLIRGenerator gen) {
+        gen.setResult(this, emitCString(gen, string));
+    }
+
+    public static AllocatableValue emitCString(NodeLIRGeneratorTool gen, String value) {
+        AllocatableValue dst = gen.getLIRGeneratorTool().newVariable(gen.getLIRGeneratorTool().target().wordKind);
+        gen.getLIRGeneratorTool().emitData(dst, toCString(value));
+        return dst;
+    }
+
+    /**
+     * Converts a string to a null terminated byte array of ASCII characters.
+     * 
+     * @param s a String that must only contain ASCII characters
+     */
+    public static byte[] toCString(String s) {
+        byte[] bytes = new byte[s.length() + 1];
+        for (int i = 0; i < s.length(); i++) {
+            assert s.charAt(i) < 128 : "non-ascii string: " + s;
+            bytes[i] = (byte) s.charAt(i);
         }
-        unsafe.putByte(cstring + formatBytes.length, (byte) 0);
-        ConstantNode replacement = ConstantNode.forLong(cstring, graph());
-        graph().replaceFloating(this, replacement);
+        bytes[s.length()] = 0;
+        return bytes;
     }
 
     @NodeIntrinsic(setStampFromReturnType = true)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -41,9 +41,9 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        Register rawThread = ((HotSpotLIRGenerator) gen).getProviders().getRegisters().getThreadRegister();
-        gen.setResult(this, rawThread.asValue(this.kind()));
+    public void generate(NodeLIRGeneratorTool gen) {
+        Register rawThread = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).getProviders().getRegisters().getThreadRegister();
+        gen.setResult(this, rawThread.asValue(this.getKind()));
     }
 
     private static int eetopOffset() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,16 +24,15 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
  * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}.
  */
-public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable {
+public final class CurrentLockNode extends FixedWithNextNode implements LIRLowerable {
 
     private int lockDepth;
 
@@ -43,12 +42,12 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         assert lockDepth != -1;
-        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         StackSlot slot = hsGen.getLockSlot(lockDepth);
         // The register allocator cannot handle stack -> register moves so we use an LEA here
-        Value result = gen.emitMove(gen.emitAddress(slot));
+        Value result = gen.getLIRGeneratorTool().emitMove(gen.getLIRGeneratorTool().emitAddress(slot));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -45,8 +45,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        ((HotSpotLIRGenerator) gen).emitDeoptimizeCaller(action, reason);
+    public void generate(NodeLIRGeneratorTool gen) {
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizeCaller(action, reason);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -31,13 +31,14 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
  * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray
  * instruction.
  */
-public final class DimensionsNode extends FixedWithNextNode implements LIRGenLowerable {
+public final class DimensionsNode extends FixedWithNextNode implements LIRGenResLowerable {
 
     private final int rank;
 
@@ -47,12 +48,12 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) {
         int size = rank * 4;
-        int wordSize = gen.target().wordSize;
+        int wordSize = gen.getLIRGeneratorTool().target().wordSize;
         int slots = roundUp(size, wordSize) / wordSize;
-        StackSlot array = gen.frameMap().allocateStackSlots(slots, new BitSet(0), null);
-        Value result = gen.emitAddress(array);
+        StackSlot array = res.getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
+        Value result = gen.getLIRGeneratorTool().emitAddress(array);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -77,8 +77,8 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this);
+    public void generate(NodeLIRGenerator gen) {
+        ((HotSpotNodeLIRGenerator) gen).visitDirectCompareAndSwap(this);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,17 +23,16 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an
  * object.
  */
-public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorExit, MemoryCheckpoint.Single {
+public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorExit, MemoryCheckpoint.Single {
 
     public EndLockScopeNode() {
         super(StampFactory.forVoid());
@@ -50,7 +49,7 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Sun Mar 30 16:08:33 2014 +0200
@@ -25,9 +25,9 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 
-public class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode {
+public class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode.DeoptBefore {
 
-    @Input private FrameState deoptimizationState;
+    @Input private FrameState stateBefore;
     private final boolean nullCheck;
     private final boolean doLoad;
 
@@ -55,17 +55,13 @@
     }
 
     @Override
-    public FrameState getDeoptimizationState() {
-        return deoptimizationState;
+    public FrameState stateBefore() {
+        return stateBefore;
     }
 
     @Override
-    public void setDeoptimizationState(FrameState state) {
-        updateUsages(deoptimizationState, state);
-        deoptimizationState = state;
-    }
-
-    public FrameState getState() {
-        return deoptimizationState;
+    public void setStateBefore(FrameState state) {
+        updateUsages(stateBefore, state);
+        stateBefore = state;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -45,9 +45,9 @@
     public static native long get(Object array);
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        AllocatableValue obj = gen.newVariable(gen.target().wordKind);
-        gen.emitMove(obj, gen.operand(object));
+    public void generate(NodeLIRGeneratorTool gen) {
+        AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(gen.getLIRGeneratorTool().target().wordKind);
+        gen.getLIRGeneratorTool().emitMove(obj, gen.operand(object));
         gen.setResult(this, obj);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -46,8 +46,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        ((HotSpotLIRGenerator) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc);
+    public void generate(NodeLIRGeneratorTool gen) {
+        ((HotSpotNodeLIRGenerator) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,22 +29,23 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
  * Node that is used to maintain a stack based counter of how many locks are currently held.
  */
-public final class MonitorCounterNode extends FloatingNode implements LIRGenLowerable {
+public final class MonitorCounterNode extends FloatingNode implements LIRGenResLowerable {
 
     private MonitorCounterNode() {
         super(null);
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) {
         assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
-        StackSlot counter = gen.frameMap().allocateStackSlots(1, new BitSet(0), null);
-        Value result = gen.emitAddress(counter);
+        StackSlot counter = res.getFrameMap().allocateStackSlots(1, new BitSet(0), null);
+        Value result = gen.getLIRGeneratorTool().emitAddress(counter);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Sun Mar 30 16:08:33 2014 +0200
@@ -47,12 +47,12 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGenerator gen) {
         assert lockDepth != -1;
-        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         StackSlot slot = hsGen.getLockSlot(lockDepth);
-        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(MonitorExitStubCall.MONITOREXIT);
-        gen.emitForeignCall(linkage, this, gen.operand(object), gen.emitAddress(slot));
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(MonitorExitStubCall.MONITOREXIT);
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(object), gen.getLIRGeneratorTool().emitAddress(slot));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Sun Mar 30 16:08:33 2014 +0200
@@ -61,9 +61,9 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(NEW_ARRAY);
-        Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length));
+    public void generate(NodeLIRGenerator gen) {
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY);
+        Variable result = gen.getLIRGenerator().emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,19 +24,17 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * A call to the {@link NewInstanceStub}.
  */
-public class NewInstanceStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
+public class NewInstanceStubCall extends DeoptimizingStubCall implements LIRLowerable {
 
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
@@ -59,9 +57,9 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(NEW_INSTANCE);
-        Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub));
+    public void generate(NodeLIRGeneratorTool gen) {
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_INSTANCE);
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(hub));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Sun Mar 30 16:08:33 2014 +0200
@@ -61,7 +61,7 @@
     }
 
     @Override
-    protected Value[] operands(LIRGeneratorTool gen) {
+    protected Value[] operands(NodeLIRGeneratorTool gen) {
         return new Value[]{gen.operand(hub), Constant.forInt(rank), gen.operand(dims)};
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -41,8 +41,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        ((HotSpotLIRGenerator) gen).emitPatchReturnAddress(address);
+    public void generate(NodeLIRGeneratorTool gen) {
+        ((HotSpotNodeLIRGenerator) gen).emitPatchReturnAddress(address);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -42,8 +42,8 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        ((HotSpotLIRGenerator) gen).emitPrefetchAllocate(address, distance);
+    public void generate(NodeLIRGenerator gen) {
+        ((HotSpotNodeLIRGenerator) gen).emitPrefetchAllocate(address, distance);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -57,7 +57,7 @@
         return foreignCalls.getKilledLocations(descriptor);
     }
 
-    protected Value[] operands(LIRGeneratorTool gen) {
+    protected Value[] operands(NodeLIRGeneratorTool gen) {
         Value[] operands = new Value[arguments.size()];
         for (int i = 0; i < operands.length; i++) {
             operands[i] = gen.operand(arguments.get(i));
@@ -66,11 +66,11 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         assert graph().start() instanceof StubStartNode;
-        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(descriptor);
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor);
         Value[] operands = operands(gen);
-        Value result = gen.emitForeignCall(linkage, null, operands);
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, operands);
         if (result != null) {
             gen.setResult(this, result);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
@@ -40,7 +41,7 @@
  * Performs a tail call to the specified target compiled method, with the parameter taken from the
  * supplied FrameState.
  */
-public class TailcallNode extends FixedWithNextNode implements LIRLowerable {
+public class TailcallNode extends FixedWithNextNode implements LIRGenResLowerable {
 
     @Input private FrameState frameState;
     @Input private ValueNode target;
@@ -57,22 +58,20 @@
         this.frameState = frameState;
     }
 
-    @Override
-    public void generate(LIRGeneratorTool generator) {
-        LIRGenerator gen = (LIRGenerator) generator;
+    public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) {
         HotSpotVMConfig config = runtime().getConfig();
         ResolvedJavaMethod method = frameState.method();
         boolean isStatic = Modifier.isStatic(method.getModifiers());
 
         JavaType[] signature = MetaUtil.signatureToTypes(method.getSignature(), isStatic ? null : method.getDeclaringClass());
-        CallingConvention cc = gen.frameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.target(), false);
+        CallingConvention cc = res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.getLIRGeneratorTool().target(), false);
         List<ValueNode> parameters = new ArrayList<>();
-        for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += FrameStateBuilder.stackSlots(frameState.localAt(slot).kind())) {
+        for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += HIRFrameStateBuilder.stackSlots(frameState.localAt(slot).getKind())) {
             parameters.add(frameState.localAt(slot));
         }
         Value[] args = gen.visitInvokeArguments(cc, parameters);
-        Value address = gen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
-        Value entry = gen.emitLoad(Kind.Long, address, null);
+        Value address = gen.getLIRGeneratorTool().emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
+        Value entry = gen.getLIRGeneratorTool().emitLoad(Kind.Long, address, null);
         HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
         hsgen.emitTailcall(args, entry);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,11 +22,13 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.hotspot.nodes.CStringNode.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
 
@@ -34,31 +36,39 @@
  * Causes the VM to exit with a description of the current Java location and an optional
  * {@linkplain Log#printf(String, long) formatted} error message specified.
  */
-public final class VMErrorNode extends DeoptimizingStubCall implements LIRGenLowerable {
+public final class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable {
 
     private final String format;
     @Input private ValueNode value;
     public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
 
-    private VMErrorNode(String format, ValueNode value) {
+    public VMErrorNode(String format, ValueNode value) {
         super(StampFactory.forVoid());
         this.format = format;
         this.value = value;
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        String whereString = "in compiled code for " + graph();
+    public void generate(NodeLIRGeneratorTool gen) {
+        String whereString;
+        if (stateBefore() != null) {
+            String nl = CodeUtil.NEW_LINE;
+            StringBuilder sb = new StringBuilder("in compiled code associated with frame state:");
+            FrameState fs = stateBefore();
+            while (fs != null) {
+                MetaUtil.appendLocation(sb.append(nl).append("\t"), fs.method(), fs.bci);
+                fs = fs.outerFrameState();
+            }
+            whereString = sb.toString();
+        } else {
+            ResolvedJavaMethod method = graph().method();
+            whereString = "in compiled code for " + (method == null ? graph().toString() : format("%H.%n(%p)", method));
+        }
+        Value whereArg = emitCString(gen, whereString);
+        Value formatArg = emitCString(gen, format);
 
-        // As these strings will end up embedded as oops in the code, they
-        // must be interned or else they will cause the nmethod to be unloaded
-        // (nmethods are a) weak GC roots and b) unloaded if any of their
-        // embedded oops become unreachable).
-        Constant whereArg = Constant.forObject(whereString.intern());
-        Constant formatArg = Constant.forObject(format.intern());
-
-        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(VMErrorNode.VM_ERROR);
-        gen.emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value));
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VMErrorNode.VM_ERROR);
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,11 +29,13 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
+import edu.umd.cs.findbugs.annotations.*;
+
 /**
  * Checks for illegal object constants in a graph processed for AOT compilation. The only legal
  * object constants are {@linkplain String#intern() interned} strings as they will be installed in
  * the Class Data Sharing (CDS) space.
- * 
+ *
  * @see LoadJavaMirrorWithKlassPhase
  */
 public class AheadOfTimeVerificationPhase extends VerifyPhase<PhaseContext> {
@@ -51,13 +53,14 @@
     }
 
     private static boolean isObject(ConstantNode node) {
-        return node.kind() == Kind.Object;
+        return node.getKind() == Kind.Object;
     }
 
     private static boolean isNullReference(ConstantNode node) {
         return isObject(node) && node.asConstant().asObject() == null;
     }
 
+    @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want")
     private static boolean isInternedString(ConstantNode node) {
         if (!isObject(node)) {
             return false;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -68,9 +68,9 @@
 
     protected static void addG1PreWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
         G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(object, value, location, doLoad, nullCheck));
-        preBarrier.setDeoptimizationState(node.getDeoptimizationState());
+        preBarrier.setStateBefore(node.stateBefore());
         node.setNullCheck(false);
-        node.setDeoptimizationState(null);
+        node.setStateBefore(null);
         graph.addBeforeFixed(node, preBarrier);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,7 +27,6 @@
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.Options.*;
 import static com.oracle.graal.nodes.PiArrayNode.*;
-import static com.oracle.graal.nodes.PiNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
@@ -139,7 +138,7 @@
         if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
             writeTlabTop(thread, newTop);
             emitPrefetchAllocate(newTop, false);
-            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, false);
+            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, false, true);
         } else {
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
@@ -197,7 +196,7 @@
             writeTlabTop(thread, newTop);
             emitPrefetchAllocate(newTop, true);
             newarray_loopInit.inc();
-            result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll);
+            result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true);
         } else {
             newarray_stub.inc();
             result = NewArrayStubCall.call(hub, length);
@@ -251,7 +250,7 @@
      * Computes the size of the memory chunk allocated for an array. This size accounts for the
      * array header size, boy size and any padding after the last element to satisfy object
      * alignment requirements.
-     * 
+     *
      * @param length the number of elements in the array
      * @param alignment the object alignment requirement
      * @param headerSize the size of the array header
@@ -277,7 +276,7 @@
     }
 
     /**
-     * Maximum number of long stores to emit when zeroing an object with a constant size Larger
+     * Maximum number of long stores to emit when zeroing an object with a constant size. Larger
      * objects have their bodies initialized in a loop.
      */
     private static final int MAX_UNROLLED_OBJECT_ZEROING_STORES = 8;
@@ -285,14 +284,14 @@
     /**
      * Zero uninitialized memory in a newly allocated object, unrolling as necessary and ensuring
      * that stores are aligned.
-     * 
+     *
      * @param size number of bytes to zero
      * @param memory beginning of object which is being zeroed
      * @param constantSize is @ size} known to be constant in the snippet
      * @param startOffset offset to begin zeroing. May not be word aligned.
      * @param manualUnroll maximally unroll zeroing
      */
-    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean noAsserts) {
+    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean noAsserts, boolean useSnippetCounters) {
         assert noAsserts || size % 8 == 0 : "unaligned object size";
         int offset = startOffset;
         if (offset % 8 != 0) {
@@ -305,7 +304,9 @@
             // This case handles arrays of constant length. Instead of having a snippet variant for
             // each length, generate a chain of stores of maximum length. Once it's inlined the
             // break statement will trim excess stores.
-            new_seqInit.inc();
+            if (useSnippetCounters) {
+                new_seqInit.inc();
+            }
             explodeLoop();
             for (int i = 0; i < MAX_UNROLLED_OBJECT_ZEROING_STORES; i++, offset += 8) {
                 if (offset == size) {
@@ -317,10 +318,14 @@
             // Use Word instead of int to avoid extension to long in generated code
             Word off = Word.signed(offset);
             if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
-                new_seqInit.inc();
+                if (useSnippetCounters) {
+                    new_seqInit.inc();
+                }
                 explodeLoop();
             } else {
-                new_loopInit.inc();
+                if (useSnippetCounters) {
+                    new_loopInit.inc();
+                }
             }
             for (; off.rawValue() < size; off = off.add(8)) {
                 memory.initializeLong(off, 0, INIT_LOCATION);
@@ -333,17 +338,17 @@
      * since they can't be compiled in stubs.
      */
     public static Object formatObjectForStub(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord) {
-        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, true);
+        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, true, false);
     }
 
     /**
      * Formats some allocated memory with an object header and zeroes out the rest.
      */
-    private static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean noAsserts) {
+    private static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean noAsserts, boolean useSnippetCounters) {
         Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
-            zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, noAsserts);
+            zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, noAsserts, useSnippetCounters);
         }
         return memory.toObject();
     }
@@ -351,7 +356,8 @@
     /**
      * Formats some allocated memory with an object header and zeroes out the rest.
      */
-    public static Object formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll) {
+    public static Object formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
+                    boolean useSnippetCounters) {
         memory.writeInt(arrayLengthOffset(), length, INIT_LOCATION);
         /*
          * store hub last as the concurrent garbage collectors assume length is valid if hub field
@@ -359,7 +365,7 @@
          */
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
-            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, true);
+            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, true, useSnippetCounters);
         }
         return memory.toObject();
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Sun Mar 30 16:08:33 2014 +0200
@@ -83,7 +83,7 @@
     /**
      * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to
      * -XX:-UseTLAB).
-     * 
+     *
      * @param hub the hub of the object to be allocated
      * @param length the length of the array
      * @param intArrayHub the hub for {@code int[].class}
@@ -110,7 +110,7 @@
                 if (logging()) {
                     printf("newArray: allocated new array at %p\n", memory.rawValue());
                 }
-                return verifyObject(formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true, false));
+                return verifyObject(formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true, false, false));
             }
         }
         if (logging()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Sun Mar 30 16:08:33 2014 +0200
@@ -97,7 +97,7 @@
     /**
      * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to
      * -XX:-UseTLAB).
-     * 
+     *
      * @param hub the hub of the object to be allocated
      * @param intArrayHub the hub for {@code int[].class}
      */
@@ -127,11 +127,11 @@
 
     /**
      * Attempts to refill the current thread's TLAB and retries the allocation.
-     * 
+     *
      * @param intArrayHub the hub for {@code int[].class}
      * @param sizeInBytes the size of the allocation
      * @param log specifies if logging is enabled
-     * 
+     *
      * @return the newly allocated, uninitialized chunk of memory, or {@link Word#zero()} if the
      *         operation was unsuccessful
      */
@@ -188,7 +188,7 @@
                 // an int
                 int tlabFreeSpaceInInts = (int) tlabFreeSpaceInBytes >>> 2;
                 int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts;
-                NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false, false);
+                NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false, false, false);
 
                 long allocated = thread.readLong(threadAllocatedBytesOffset(), TLAB_THREAD_ALLOCATED_BYTES_LOCATION);
                 allocated = allocated + top.subtract(readTlabStart(thread)).rawValue();
@@ -226,7 +226,7 @@
 
     /**
      * Attempts to allocate a chunk of memory from Eden space.
-     * 
+     *
      * @param sizeInBytes the size of the chunk to allocate
      * @param log specifies if logging is enabled
      * @return the allocated chunk or {@link Word#zero()} if allocation fails
--- a/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java	Sun Mar 30 16:08:33 2014 +0200
@@ -118,6 +118,20 @@
     public static final Register q14 = new Register(70, 14, "q14", CPU);
     public static final Register q15 = new Register(71, 15, "q15", CPU);
 
+    // non-allocatable registers used for deopt
+    public static final Register s32 = new Register(72, 32, "s32", CPU);
+    public static final Register s33 = new Register(73, 33, "s33", CPU);
+    public static final Register s34 = new Register(74, 34, "s34", CPU);
+    public static final Register s35 = new Register(75, 35, "s35", CPU);
+    public static final Register s36 = new Register(76, 36, "s36", CPU);
+    public static final Register s37 = new Register(77, 37, "s37", CPU);
+    public static final Register s38 = new Register(78, 38, "s38", CPU);
+    public static final Register s39 = new Register(79, 39, "s39", CPU);
+    public static final Register d16 = new Register(80, 16, "d16", CPU);
+    public static final Register d17 = new Register(81, 17, "d17", CPU);
+    public static final Register d18 = new Register(82, 18, "d18", CPU);
+    public static final Register d19 = new Register(83, 19, "d19", CPU);
+
     // @formatter:off
     public static final Register[] cRegisters = {
         c0, c1, c2, c3, c4, c5, c6, c7
--- a/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAILRegisterConfig.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAILRegisterConfig.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,7 +24,6 @@
 package com.oracle.graal.hsail;
 
 import com.oracle.graal.api.code.*;
-
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -168,6 +167,11 @@
     }
 
     @Override
+    public boolean areAllAllocatableRegistersCallerSaved() {
+        return false;
+    }
+
+    @Override
     public CalleeSaveLayout getCalleeSaveLayout() {
         return null;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,227 @@
+/*
+ * 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.meta.*;
+
+public abstract class AbstractFrameStateBuilder<T extends KindInterface> {
+
+    protected final ResolvedJavaMethod method;
+    protected int stackSize;
+
+    public AbstractFrameStateBuilder(ResolvedJavaMethod method) {
+        this.method = method;
+    }
+
+    protected AbstractFrameStateBuilder(AbstractFrameStateBuilder other) {
+        this.method = other.method;
+    }
+
+    /**
+     * Returns the size of the local variables.
+     *
+     * @return the size of the local variables
+     */
+    public abstract int localsSize();
+
+    /**
+     * 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 abstract T localAt(int 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 abstract T stackAt(int i);
+
+    /**
+     * 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 abstract T loadLocal(int i);
+
+    /**
+     * 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 abstract void storeLocal(int i, T x);
+
+    public abstract void storeStack(int i, T 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 abstract void push(Kind kind, T x);
+
+    /**
+     * Pushes a value onto the stack without checking the type.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public abstract void xpush(T x);
+
+    /**
+     * Pushes a value onto the stack and checks that it is an int.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public abstract void ipush(T x);
+
+    /**
+     * Pushes a value onto the stack and checks that it is a float.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public abstract void fpush(T x);
+
+    /**
+     * Pushes a value onto the stack and checks that it is an object.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public abstract void apush(T x);
+
+    /**
+     * Pushes a value onto the stack and checks that it is a long.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public abstract void lpush(T x);
+
+    /**
+     * Pushes a value onto the stack and checks that it is a double.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public abstract void dpush(T x);
+
+    public abstract void pushReturn(Kind kind, T 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 abstract T pop(Kind kind);
+
+    /**
+     * Pops a value off of the stack without checking the type.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public abstract T xpop();
+
+    /**
+     * Pops a value off of the stack and checks that it is an int.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public abstract T ipop();
+
+    /**
+     * Pops a value off of the stack and checks that it is a float.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public abstract T fpop();
+
+    /**
+     * Pops a value off of the stack and checks that it is an object.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public abstract T apop();
+
+    /**
+     * Pops a value off of the stack and checks that it is a long.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public abstract T lpop();
+
+    /**
+     * Pops a value off of the stack and checks that it is a double.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public abstract T dpop();
+
+    /**
+     * 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 abstract T[] popArguments(int slotSize, int argSize);
+
+    /**
+     * 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 abstract T peek(int argumentNumber);
+
+    public static int stackSlots(Kind kind) {
+        return isTwoSlot(kind) ? 2 : 1;
+    }
+
+    /**
+     * Clears all values on this stack.
+     */
+    public void clearStack() {
+        stackSize = 0;
+    }
+
+    protected static boolean isTwoSlot(Kind kind) {
+        assert kind != Kind.Void && kind != Kind.Illegal;
+        return kind == Kind.Long || kind == Kind.Double;
+    }
+
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 
 /**
  * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow graph
@@ -73,33 +74,40 @@
  */
 public final class BciBlockMapping {
 
-    public static class Block implements Cloneable {
+    public static class BciBlock extends AbstractBlockBase<BciBlock> implements Cloneable {
 
         public int startBci;
         public int endBci;
         public boolean isExceptionEntry;
         public boolean isLoopHeader;
         public int loopId;
-        public int blockID;
 
         public FixedWithNextNode firstInstruction;
-        public FrameStateBuilder entryState;
+        public HIRFrameStateBuilder entryState;
 
-        public ArrayList<Block> successors = new ArrayList<>(2);
+        // public ArrayList<BciBlock> successors = new ArrayList<>(2);
+        // public ArrayList<BciBlock> predecessors = new ArrayList<>(2); // only used in the
+        // baseline
+
         public long exits;
 
         private boolean visited;
         private boolean active;
         public long loops;
 
-        public HashMap<JsrScope, Block> jsrAlternatives;
+        public HashMap<JsrScope, BciBlock> jsrAlternatives;
         public JsrScope jsrScope = JsrScope.EMPTY_SCOPE;
-        public Block jsrSuccessor;
+        public BciBlock jsrSuccessor;
         public int jsrReturnBci;
-        public Block retSuccessor;
+        public BciBlock retSuccessor;
         public boolean endsWithRet = false;
 
-        public Block exceptionDispatchBlock() {
+        public BciBlock() {
+            this.successors = new ArrayList<>();
+            this.predecessors = new ArrayList<>();
+        }
+
+        public BciBlock exceptionDispatchBlock() {
             if (successors.size() > 0 && successors.get(successors.size() - 1) instanceof ExceptionDispatchBlock) {
                 return successors.get(successors.size() - 1);
             }
@@ -113,9 +121,9 @@
             return successors.size();
         }
 
-        public Block copy() {
+        public BciBlock copy() {
             try {
-                Block block = (Block) super.clone();
+                BciBlock block = (BciBlock) super.clone();
                 block.successors = new ArrayList<>(successors);
                 return block;
             } catch (CloneNotSupportedException e) {
@@ -125,7 +133,7 @@
 
         @Override
         public String toString() {
-            StringBuilder sb = new StringBuilder("B").append(blockID);
+            StringBuilder sb = new StringBuilder("B").append(getId());
             sb.append('[').append(startBci).append("->").append(endBci);
             if (isLoopHeader || isExceptionEntry) {
                 sb.append(' ');
@@ -139,9 +147,41 @@
             sb.append(']');
             return sb.toString();
         }
+
+        public Loop getLoop() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        public int getLoopDepth() {
+            // TODO Auto-generated method stub
+            return 0;
+        }
+
+        public boolean isLoopHeader() {
+            return isLoopHeader;
+        }
+
+        public boolean isLoopEnd() {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        public boolean isExceptionEntry() {
+            // TODO Auto-generated method stub
+            return false;
+        }
+
+        public BciBlock getSuccessor(int index) {
+            return successors.get(index);
+        }
+
+        public BciBlock getPredecessor(int index) {
+            return predecessors.get(index);
+        }
     }
 
-    public static class ExceptionDispatchBlock extends Block {
+    public static class ExceptionDispatchBlock extends BciBlock {
 
         private HashMap<ExceptionHandler, ExceptionDispatchBlock> exceptionDispatch = new HashMap<>();
 
@@ -152,15 +192,15 @@
     /**
      * The blocks found in this method, in reverse postorder.
      */
-    public final List<Block> blocks;
+    public final List<BciBlock> blocks;
     public final ResolvedJavaMethod method;
     public boolean hasJsrBytecodes;
-    public Block startBlock;
+    public BciBlock startBlock;
 
     private final BytecodeStream stream;
     private final ExceptionHandler[] exceptionHandlers;
-    private Block[] blockMap;
-    public Block[] loopHeaders;
+    private BciBlock[] blockMap;
+    public BciBlock[] loopHeaders;
 
     public LocalLiveness liveness;
 
@@ -173,9 +213,9 @@
         this.method = method;
         exceptionHandlers = method.getExceptionHandlers();
         stream = new BytecodeStream(method.getCode());
-        this.blockMap = new Block[method.getCodeSize()];
+        this.blockMap = new BciBlock[method.getCodeSize()];
         this.blocks = new ArrayList<>();
-        this.loopHeaders = new Block[64];
+        this.loopHeaders = new BciBlock[64];
     }
 
     /**
@@ -218,13 +258,13 @@
     }
 
     private boolean verify() {
-        for (Block block : blocks) {
-            assert blocks.get(block.blockID) == block;
+        for (BciBlock block : blocks) {
+            assert blocks.get(block.getId()) == block;
 
-            for (int i = 0; i < block.successors.size(); i++) {
-                Block sux = block.successors.get(i);
+            for (int i = 0; i < block.getSuccessorCount(); i++) {
+                BciBlock sux = block.getSuccessor(i);
                 if (sux instanceof ExceptionDispatchBlock) {
-                    assert i == block.successors.size() - 1 : "Only one exception handler allowed, and it must be last in successors list";
+                    assert i == block.getSuccessorCount() - 1 : "Only one exception handler allowed, and it must be last in successors list";
                 }
             }
         }
@@ -234,14 +274,14 @@
 
     private void initializeBlockIds() {
         for (int i = 0; i < blocks.size(); i++) {
-            blocks.get(i).blockID = i;
+            blocks.get(i).setId(i);
         }
     }
 
     private void makeExceptionEntries() {
         // start basic blocks at all exception handler blocks and mark them as exception entries
         for (ExceptionHandler h : this.exceptionHandlers) {
-            Block xhandler = makeBlock(h.getHandlerBCI());
+            BciBlock xhandler = makeBlock(h.getHandlerBCI());
             xhandler.isExceptionEntry = true;
         }
     }
@@ -250,13 +290,13 @@
         // iterate over the bytecodes top to bottom.
         // mark the entrypoints of basic blocks and build lists of successors for
         // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret)
-        Block current = null;
+        BciBlock current = null;
         stream.setBCI(0);
         while (stream.currentBC() != Bytecodes.END) {
             int bci = stream.currentBCI();
 
             if (current == null || blockMap[bci] != null) {
-                Block b = makeBlock(bci);
+                BciBlock b = makeBlock(bci);
                 if (current != null) {
                     addSuccessor(current.endBci, b);
                 }
@@ -327,7 +367,7 @@
                     if (target == 0) {
                         throw new JsrNotSupportedBailout("jsr target bci 0 not allowed");
                     }
-                    Block b1 = makeBlock(target);
+                    BciBlock b1 = makeBlock(target);
                     current.jsrSuccessor = b1;
                     current.jsrReturnBci = stream.nextBCI();
                     current = null;
@@ -382,10 +422,10 @@
         }
     }
 
-    private Block makeBlock(int startBci) {
-        Block oldBlock = blockMap[startBci];
+    private BciBlock makeBlock(int startBci) {
+        BciBlock oldBlock = blockMap[startBci];
         if (oldBlock == null) {
-            Block newBlock = new Block();
+            BciBlock newBlock = new BciBlock();
             newBlock.startBci = startBci;
             blockMap[startBci] = newBlock;
             return newBlock;
@@ -393,14 +433,14 @@
         } else if (oldBlock.startBci != startBci) {
             // Backward branch into the middle of an already processed block.
             // Add the correct fall-through successor.
-            Block newBlock = new Block();
+            BciBlock newBlock = new BciBlock();
             newBlock.startBci = startBci;
             newBlock.endBci = oldBlock.endBci;
-            newBlock.successors.addAll(oldBlock.successors);
+            newBlock.getSuccessors().addAll(oldBlock.getSuccessors());
 
             oldBlock.endBci = startBci - 1;
-            oldBlock.successors.clear();
-            oldBlock.successors.add(newBlock);
+            oldBlock.getSuccessors().clear();
+            oldBlock.getSuccessors().add(newBlock);
 
             for (int i = startBci; i <= newBlock.endBci; i++) {
                 blockMap[i] = newBlock;
@@ -424,30 +464,30 @@
         }
     }
 
-    private void addSuccessor(int predBci, Block sux) {
-        Block predecessor = blockMap[predBci];
+    private void addSuccessor(int predBci, BciBlock sux) {
+        BciBlock predecessor = blockMap[predBci];
         if (sux.isExceptionEntry) {
             throw new BailoutException("Exception handler can be reached by both normal and exceptional control flow");
         }
-        predecessor.successors.add(sux);
+        predecessor.getSuccessors().add(sux);
     }
 
-    private final ArrayList<Block> jsrVisited = new ArrayList<>();
+    private final ArrayList<BciBlock> jsrVisited = new ArrayList<>();
 
-    private void createJsrAlternatives(Block block) {
+    private void createJsrAlternatives(BciBlock block) {
         jsrVisited.add(block);
         JsrScope scope = block.jsrScope;
 
         if (block.endsWithRet) {
             block.retSuccessor = blockMap[scope.nextReturnAddress()];
-            block.successors.add(block.retSuccessor);
+            block.getSuccessors().add(block.retSuccessor);
             assert block.retSuccessor != block.jsrSuccessor;
         }
-        Debug.log("JSR alternatives block %s  sux %s  jsrSux %s  retSux %s  jsrScope %s", block, block.successors, block.jsrSuccessor, block.retSuccessor, block.jsrScope);
+        Debug.log("JSR alternatives block %s  sux %s  jsrSux %s  retSux %s  jsrScope %s", block, block.getSuccessors(), block.jsrSuccessor, block.retSuccessor, block.jsrScope);
 
         if (block.jsrSuccessor != null || !scope.isEmpty()) {
-            for (int i = 0; i < block.successors.size(); i++) {
-                Block successor = block.successors.get(i);
+            for (int i = 0; i < block.getSuccessorCount(); i++) {
+                BciBlock successor = block.getSuccessor(i);
                 JsrScope nextScope = scope;
                 if (successor == block.jsrSuccessor) {
                     nextScope = scope.push(block.jsrReturnBci);
@@ -459,7 +499,7 @@
                     throw new JsrNotSupportedBailout("unstructured control flow  (" + successor.jsrScope + " " + nextScope + ")");
                 }
                 if (!nextScope.isEmpty()) {
-                    Block clone;
+                    BciBlock clone;
                     if (successor.jsrAlternatives != null && successor.jsrAlternatives.containsKey(nextScope)) {
                         clone = successor.jsrAlternatives.get(nextScope);
                     } else {
@@ -470,7 +510,7 @@
                         clone.jsrScope = nextScope;
                         successor.jsrAlternatives.put(nextScope, clone);
                     }
-                    block.successors.set(i, clone);
+                    block.getSuccessors().set(i, clone);
                     if (successor == block.jsrSuccessor) {
                         block.jsrSuccessor = clone;
                     }
@@ -480,7 +520,7 @@
                 }
             }
         }
-        for (Block successor : block.successors) {
+        for (BciBlock successor : block.getSuccessors()) {
             if (!jsrVisited.contains(successor)) {
                 createJsrAlternatives(successor);
             }
@@ -509,9 +549,9 @@
                     curHandler.endBci = -1;
                     curHandler.deoptBci = bci;
                     curHandler.handler = h;
-                    curHandler.successors.add(blockMap[h.getHandlerBCI()]);
+                    curHandler.getSuccessors().add(blockMap[h.getHandlerBCI()]);
                     if (lastHandler != null) {
-                        curHandler.successors.add(lastHandler);
+                        curHandler.getSuccessors().add(lastHandler);
                     }
                     exceptionDispatch.put(h, curHandler);
                 }
@@ -526,7 +566,7 @@
     private void fixLoopBits() {
         do {
             loopChanges = false;
-            for (Block b : blocks) {
+            for (BciBlock b : blocks) {
                 b.visited = false;
             }
 
@@ -563,17 +603,17 @@
             String n = System.lineSeparator();
             StringBuilder sb = new StringBuilder(Debug.currentScope()).append("BlockMap ").append(name).append(" :");
             sb.append(n);
-            Iterable<Block> it;
+            Iterable<BciBlock> it;
             if (blocks.isEmpty()) {
                 it = new HashSet<>(Arrays.asList(blockMap));
             } else {
                 it = blocks;
             }
-            for (Block b : it) {
+            for (BciBlock b : it) {
                 if (b == null) {
                     continue;
                 }
-                sb.append("B").append(b.blockID).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")");
+                sb.append("B").append(b.getId()).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")");
                 if (b.isLoopHeader) {
                     sb.append(" LoopHeader");
                 }
@@ -581,8 +621,8 @@
                     sb.append(" ExceptionEntry");
                 }
                 sb.append(n).append("  Sux : ");
-                for (Block s : b.successors) {
-                    sb.append("B").append(s.blockID).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")");
+                for (BciBlock s : b.getSuccessors()) {
+                    sb.append("B").append(s.getId()).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")");
                     if (s.isExceptionEntry) {
                         sb.append("!");
                     }
@@ -594,7 +634,7 @@
                 while (l != 0) {
                     int lMask = 1 << pos;
                     if ((l & lMask) != 0) {
-                        sb.append("B").append(loopHeaders[pos].blockID).append(" ");
+                        sb.append("B").append(loopHeaders[pos].getId()).append(" ");
                         l &= ~lMask;
                     }
                     pos++;
@@ -605,14 +645,14 @@
                 while (l != 0) {
                     int lMask = 1 << pos;
                     if ((l & lMask) != 0) {
-                        sb.append("B").append(loopHeaders[pos].blockID).append(" ");
+                        sb.append("B").append(loopHeaders[pos].getId()).append(" ");
                         l &= ~lMask;
                     }
                     pos++;
                 }
                 sb.append(n);
             }
-            Debug.log(sb.toString());
+            Debug.log("%s", sb);
         }
     }
 
@@ -625,7 +665,7 @@
      * Mark the block as a loop header, using the next available loop number. Also checks for corner
      * cases that we don't want to compile.
      */
-    private void makeLoopHeader(Block block) {
+    private void makeLoopHeader(BciBlock block) {
         if (!block.isLoopHeader) {
             block.isLoopHeader = true;
 
@@ -655,11 +695,11 @@
     }
 
     /**
-     * Depth-first traversal of the control flow graph. The flag {@linkplain Block#visited} is used
-     * to visit every block only once. The flag {@linkplain Block#active} is used to detect cycles
-     * (backward edges).
+     * Depth-first traversal of the control flow graph. The flag {@linkplain BciBlock#visited} is
+     * used to visit every block only once. The flag {@linkplain BciBlock#active} is used to detect
+     * cycles (backward edges).
      */
-    private long computeBlockOrder(Block block) {
+    private long computeBlockOrder(BciBlock block) {
         if (block.visited) {
             if (block.active) {
                 // Reached block via backward branch.
@@ -677,7 +717,7 @@
         block.active = true;
 
         long loops = 0;
-        for (Block successor : block.successors) {
+        for (BciBlock successor : block.getSuccessors()) {
             // Recursively process successors.
             loops |= computeBlockOrder(successor);
         }
@@ -695,7 +735,7 @@
         return loops;
     }
 
-    private long fixLoopBits(Block block) {
+    private long fixLoopBits(BciBlock block) {
         if (block.visited) {
             // Return cached loop information for this block.
             if (block.isLoopHeader) {
@@ -707,11 +747,11 @@
 
         block.visited = true;
         long loops = block.loops;
-        for (Block successor : block.successors) {
+        for (BciBlock successor : block.getSuccessors()) {
             // Recursively process successors.
             loops |= fixLoopBits(successor);
         }
-        for (Block successor : block.successors) {
+        for (BciBlock successor : block.getSuccessors()) {
             successor.exits = loops & ~successor.loops;
         }
         if (block.loops != loops) {
@@ -734,7 +774,7 @@
     public abstract class LocalLiveness {
 
         private void computeLiveness() {
-            for (Block block : blocks) {
+            for (BciBlock block : blocks) {
                 computeLocalLiveness(block);
             }
 
@@ -744,22 +784,22 @@
                 Debug.log("Iteration %d", iteration);
                 changed = false;
                 for (int i = blocks.size() - 1; i >= 0; i--) {
-                    Block block = blocks.get(i);
-                    int blockID = block.blockID;
+                    BciBlock block = blocks.get(i);
+                    int blockID = block.getId();
                     // log statements in IFs because debugLiveX creates a new String
                     if (Debug.isLogEnabled()) {
-                        Debug.log("  start B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.blockID, block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
+                        Debug.logv("  start B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
                                         debugLiveGen(blockID), debugLiveKill(blockID));
                     }
 
                     boolean blockChanged = (iteration == 0);
-                    if (block.successors.size() > 0) {
+                    if (block.getSuccessorCount() > 0) {
                         int oldCardinality = liveOutCardinality(blockID);
-                        for (Block sux : block.successors) {
+                        for (BciBlock sux : block.getSuccessors()) {
                             if (Debug.isLogEnabled()) {
-                                Debug.log("    Successor B%d: %s", sux.blockID, debugLiveIn(sux.blockID));
+                                Debug.log("    Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId()));
                             }
-                            propagateLiveness(blockID, sux.blockID);
+                            propagateLiveness(blockID, sux.getId());
                         }
                         blockChanged |= (oldCardinality != liveOutCardinality(blockID));
                     }
@@ -767,7 +807,7 @@
                     if (blockChanged) {
                         updateLiveness(blockID);
                         if (Debug.isLogEnabled()) {
-                            Debug.log("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.blockID, block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
+                            Debug.logv("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
                                             debugLiveGen(blockID), debugLiveKill(blockID));
                         }
                     }
@@ -780,12 +820,12 @@
         /**
          * Returns whether the local is live at the beginning of the given block.
          */
-        public abstract boolean localIsLiveIn(Block block, int local);
+        public abstract boolean localIsLiveIn(BciBlock block, int local);
 
         /**
          * Returns whether the local is live at the end of the given block.
          */
-        public abstract boolean localIsLiveOut(Block block, int local);
+        public abstract boolean localIsLiveOut(BciBlock block, int local);
 
         /**
          * Returns a string representation of the liveIn values of the given block.
@@ -832,11 +872,11 @@
          */
         protected abstract void storeOne(int blockID, int local);
 
-        private void computeLocalLiveness(Block block) {
+        private void computeLocalLiveness(BciBlock block) {
             if (block.startBci < 0 || block.endBci < 0) {
                 return;
             }
-            int blockID = block.blockID;
+            int blockID = block.getId();
             stream.setBCI(block.startBci);
             while (stream.currentBCI() <= block.endBci) {
                 switch (stream.currentBC()) {
@@ -1043,14 +1083,14 @@
         }
 
         @Override
-        public boolean localIsLiveIn(Block block, int local) {
-            int blockID = block.blockID;
+        public boolean localIsLiveIn(BciBlock block, int local) {
+            int blockID = block.getId();
             return blockID >= Integer.MAX_VALUE ? false : (localsLiveIn[blockID] & (1L << local)) != 0L;
         }
 
         @Override
-        public boolean localIsLiveOut(Block block, int local) {
-            int blockID = block.blockID;
+        public boolean localIsLiveOut(BciBlock block, int local) {
+            int blockID = block.getId();
             return blockID >= Integer.MAX_VALUE ? false : (localsLiveOut[blockID] & (1L << local)) != 0L;
         }
     }
@@ -1128,13 +1168,13 @@
         }
 
         @Override
-        public boolean localIsLiveIn(Block block, int local) {
-            return block.blockID >= Integer.MAX_VALUE ? true : localsLiveIn[block.blockID].get(local);
+        public boolean localIsLiveIn(BciBlock block, int local) {
+            return block.getId() >= Integer.MAX_VALUE ? true : localsLiveIn[block.getId()].get(local);
         }
 
         @Override
-        public boolean localIsLiveOut(Block block, int local) {
-            return block.blockID >= Integer.MAX_VALUE ? true : localsLiveOut[block.blockID].get(local);
+        public boolean localIsLiveOut(BciBlock block, int local) {
+            return block.getId() >= Integer.MAX_VALUE ? true : localsLiveOut[block.getId()].get(local);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParseHelper.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,138 @@
+/*
+ * 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.bytecode.Bytecodes.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+
+public class BytecodeParseHelper<T extends KindInterface> {
+
+    private AbstractFrameStateBuilder<T> frameState;
+
+    public BytecodeParseHelper(AbstractFrameStateBuilder<T> frameState) {
+        this.frameState = frameState;
+    }
+
+    public void setCurrentFrameState(AbstractFrameStateBuilder<T> frameState) {
+        this.frameState = frameState;
+    }
+
+    public void loadLocal(int index, Kind kind) {
+        frameState.push(kind, frameState.loadLocal(index));
+    }
+
+    public void storeLocal(Kind kind, int index) {
+        T value;
+        if (kind == Kind.Object) {
+            value = frameState.xpop();
+            // astore and astore_<n> may be used to store a returnAddress (jsr)
+            assert value.getKind() == Kind.Object || value.getKind() == Kind.Int;
+        } else {
+            value = frameState.pop(kind);
+        }
+        frameState.storeLocal(index, value);
+    }
+
+    public void stackOp(int opcode) {
+        switch (opcode) {
+            case POP: {
+                frameState.xpop();
+                break;
+            }
+            case POP2: {
+                frameState.xpop();
+                frameState.xpop();
+                break;
+            }
+            case DUP: {
+                T w = frameState.xpop();
+                frameState.xpush(w);
+                frameState.xpush(w);
+                break;
+            }
+            case DUP_X1: {
+                T w1 = frameState.xpop();
+                T w2 = frameState.xpop();
+                frameState.xpush(w1);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                break;
+            }
+            case DUP_X2: {
+                T w1 = frameState.xpop();
+                T w2 = frameState.xpop();
+                T w3 = frameState.xpop();
+                frameState.xpush(w1);
+                frameState.xpush(w3);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                break;
+            }
+            case DUP2: {
+                T w1 = frameState.xpop();
+                T w2 = frameState.xpop();
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                break;
+            }
+            case DUP2_X1: {
+                T w1 = frameState.xpop();
+                T w2 = frameState.xpop();
+                T w3 = frameState.xpop();
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                frameState.xpush(w3);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                break;
+            }
+            case DUP2_X2: {
+                T w1 = frameState.xpop();
+                T w2 = frameState.xpop();
+                T w3 = frameState.xpop();
+                T w4 = frameState.xpop();
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                frameState.xpush(w4);
+                frameState.xpush(w3);
+                frameState.xpush(w2);
+                frameState.xpush(w1);
+                break;
+            }
+            case SWAP: {
+                T w1 = frameState.xpop();
+                T w2 = frameState.xpop();
+                frameState.xpush(w1);
+                frameState.xpush(w2);
+                break;
+            }
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Wed Mar 19 11:43:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,698 +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.java;
-
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-import static com.oracle.graal.nodes.ValueNodeUtil.*;
-import static java.lang.reflect.Modifier.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.Node.Verbosity;
-import com.oracle.graal.java.BciBlockMapping.Block;
-import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-
-public class FrameStateBuilder {
-
-    private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
-    private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
-
-    private final ResolvedJavaMethod method;
-    private final StructuredGraph graph;
-
-    private final ValueNode[] locals;
-    private final ValueNode[] stack;
-    private ValueNode[] lockedObjects;
-    private MonitorIdNode[] monitorIds;
-
-    private int stackSize;
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    private boolean rethrowException;
-
-    public FrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean eagerResolve) {
-        assert graph != null;
-        this.method = method;
-        this.graph = graph;
-        this.locals = new ValueNode[method.getMaxLocals()];
-        // we always need at least one stack slot (for exceptions)
-        this.stack = new ValueNode[Math.max(1, method.getMaxStackSize())];
-        this.lockedObjects = EMPTY_ARRAY;
-        this.monitorIds = EMPTY_MONITOR_ARRAY;
-
-        int javaIndex = 0;
-        int index = 0;
-        if (!isStatic(method.getModifiers())) {
-            // add the receiver
-            ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass())));
-            storeLocal(javaIndex, 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().getStackKind();
-            Stamp stamp;
-            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
-                stamp = StampFactory.declared((ResolvedJavaType) type);
-            } else {
-                stamp = StampFactory.forKind(kind);
-            }
-            ParameterNode param = graph.unique(new ParameterNode(index, stamp));
-            storeLocal(javaIndex, param);
-            javaIndex += stackSlots(kind);
-            index++;
-        }
-    }
-
-    private FrameStateBuilder(FrameStateBuilder other) {
-        method = other.method;
-        graph = other.graph;
-        locals = other.locals.clone();
-        stack = other.stack.clone();
-        lockedObjects = other.lockedObjects == EMPTY_ARRAY ? EMPTY_ARRAY : other.lockedObjects.clone();
-        monitorIds = other.monitorIds == EMPTY_MONITOR_ARRAY ? EMPTY_MONITOR_ARRAY : other.monitorIds.clone();
-        stackSize = other.stackSize;
-        rethrowException = other.rethrowException;
-
-        assert locals.length == method.getMaxLocals();
-        assert stack.length == Math.max(1, method.getMaxStackSize());
-        assert lockedObjects.length == monitorIds.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) {
-        return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), lockedObjects, monitorIds, rethrowException, false));
-    }
-
-    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.kind() != y.kind())) {
-                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(MergeNode block, FrameStateBuilder other) {
-        assert isCompatibleWith(other);
-
-        for (int i = 0; i < localsSize(); i++) {
-            storeLocal(i, merge(localAt(i), other.localAt(i), block));
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            storeStack(i, merge(stackAt(i), other.stackAt(i), block));
-        }
-        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, MergeNode block) {
-        if (currentValue == null || currentValue.isDeleted()) {
-            return null;
-
-        } else if (block.isPhiAtMerge(currentValue)) {
-            if (otherValue == null || otherValue.isDeleted() || currentValue.kind() != otherValue.kind()) {
-                propagateDelete((PhiNode) currentValue);
-                return null;
-            }
-            ((PhiNode) currentValue).addInput(otherValue);
-            return currentValue;
-
-        } else if (currentValue != otherValue) {
-            assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for all locals and stack slots";
-            if (otherValue == null || otherValue.isDeleted() || currentValue.kind() != otherValue.kind()) {
-                return null;
-            }
-
-            PhiNode phi = graph.addWithoutUnique(new PhiNode(currentValue.stamp().unrestricted(), block));
-            for (int i = 0; i < block.phiPredecessorCount(); i++) {
-                phi.addInput(currentValue);
-            }
-            phi.addInput(otherValue);
-            assert phi.valueCount() == block.phiPredecessorCount() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.phiPredecessorCount();
-            return phi;
-
-        } else {
-            return currentValue;
-        }
-    }
-
-    private void propagateDelete(FloatingNode node) {
-        assert node instanceof PhiNode || 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(PhiNode.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(PhiNode.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(LoopBeginNode loopBegin) {
-        for (int i = 0; i < localsSize(); 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, 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 PhiNode createLoopPhi(MergeNode block, ValueNode value) {
-        if (value == null) {
-            return null;
-        }
-        assert !block.isPhiAtMerge(value) : "phi function for this block already created";
-
-        PhiNode phi = graph.addWithoutUnique(new PhiNode(value.stamp().unrestricted(), block));
-        phi.addInput(value);
-        return phi;
-    }
-
-    public void cleanupDeletedPhis() {
-        for (int i = 0; i < localsSize(); i++) {
-            if (localAt(i) != null && localAt(i).isDeleted()) {
-                assert localAt(i) instanceof PhiNode || localAt(i) instanceof ProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i);
-                storeLocal(i, null);
-            }
-        }
-    }
-
-    public void clearNonLiveLocals(Block block, LocalLiveness liveness, boolean liveIn) {
-        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 final 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 final ValueNode stackAt(int i) {
-        return stack[i];
-    }
-
-    /**
-     * 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.kind() == 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);
-        }
-    }
-
-    public MonitorIdNode peekMonitorId() {
-        return monitorIds[monitorIds.length - 1];
-    }
-
-    /**
-     * @return the current lock depth
-     */
-    public int lockDepth() {
-        assert lockedObjects.length == monitorIds.length;
-        return lockedObjects.length;
-    }
-
-    /**
-     * 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 !x.isDeleted();
-        assert !isTwoSlot(x.kind()) || locals[i + 1] == null;
-        assert i == 0 || locals[i - 1] == null || !isTwoSlot(locals[i - 1].kind());
-        return x;
-    }
-
-    /**
-     * Stores a given local variable at the specified index. If the value occupies
-     * {@linkplain FrameStateBuilder#isTwoSlot(Kind) 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) {
-        assert x == null || x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal : "unexpected value: " + x;
-        locals[i] = x;
-        if (x != null && isTwoSlot(x.kind())) {
-            // if this is a double word, then kill i+1
-            locals[i + 1] = null;
-        }
-        if (x != null && i > 0) {
-            ValueNode p = locals[i - 1];
-            if (p != null && isTwoSlot(p.kind())) {
-                // if there was a double word at i - 1, then kill it
-                locals[i - 1] = null;
-            }
-        }
-    }
-
-    public void storeStack(int i, ValueNode x) {
-        assert x == null || x.isAlive() && (stack[i] == null || x.kind() == stack[i].kind()) : "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, ValueNode x) {
-        assert x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal;
-        xpush(assertKind(kind, x));
-        if (isTwoSlot(kind)) {
-            xpush(null);
-        }
-    }
-
-    /**
-     * 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 x == null || (x.isAlive() && x.kind() != Kind.Void && x.kind() != 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(ValueNode 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(ValueNode 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(ValueNode 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(ValueNode 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(ValueNode x) {
-        xpush(assertDouble(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) {
-        assert kind != Kind.Void;
-        if (isTwoSlot(kind)) {
-            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 ValueNode xpop() {
-        ValueNode result = stack[--stackSize];
-        assert result == null || !result.isDeleted();
-        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 ValueNode 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 ValueNode 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 ValueNode 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 ValueNode 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 ValueNode 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 ValueNode[] popArguments(int slotSize, int argSize) {
-        int base = stackSize - slotSize;
-        ValueNode[] r = new ValueNode[argSize];
-        int argIndex = 0;
-        int stackindex = 0;
-        while (stackindex < slotSize) {
-            ValueNode element = stack[base + stackindex];
-            assert element != null;
-            r[argIndex++] = element;
-            stackindex += stackSlots(element.kind());
-        }
-        stackSize = base;
-        return r;
-    }
-
-    /**
-     * 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 isTwoSlot(stackAt(idx).kind());
-            }
-            idx--;
-        }
-        return stackAt(idx);
-    }
-
-    /**
-     * Clears all values on this stack.
-     */
-    public void clearStack() {
-        stackSize = 0;
-    }
-
-    public static int stackSlots(Kind kind) {
-        return isTwoSlot(kind) ? 2 : 1;
-    }
-
-    public static boolean isTwoSlot(Kind kind) {
-        assert kind != Kind.Void && kind != Kind.Illegal;
-        return kind == Kind.Long || kind == Kind.Double;
-    }
-
-    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;
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -40,7 +40,7 @@
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.java.BciBlockMapping.Block;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 import com.oracle.graal.nodes.*;
@@ -117,8 +117,9 @@
 
         private BytecodeStream stream;           // the bytecode stream
 
-        protected FrameStateBuilder frameState;          // the current execution state
-        private Block currentBlock;
+        protected HIRFrameStateBuilder frameState;          // the current execution state
+        private BytecodeParseHelper<ValueNode> parseHelper;
+        private BciBlock currentBlock;
 
         private ValueNode methodSynchronizedObject;
         private ExceptionDispatchBlock unwindBlock;
@@ -139,7 +140,7 @@
          * the jump. When the block is seen the second time, a {@link MergeNode} is created to
          * correctly merge the now two different predecessor states.
          */
-        private static class BlockPlaceholderNode extends FixedWithNextNode {
+        protected static class BlockPlaceholderNode extends FixedWithNextNode {
 
             /*
              * Cannot be explicitly declared as a Node type since it is not an input; would cause
@@ -159,13 +160,13 @@
             }
         }
 
-        private Block[] loopHeaders;
+        private BciBlock[] loopHeaders;
         private LocalLiveness liveness;
 
         /**
          * Gets the current frame state being processed by this builder.
          */
-        protected FrameStateBuilder getCurrentFrameState() {
+        protected HIRFrameStateBuilder getCurrentFrameState() {
             return frameState;
         }
 
@@ -202,7 +203,8 @@
             unwindBlock = null;
             methodSynchronizedObject = null;
             this.currentGraph = graph;
-            this.frameState = new FrameStateBuilder(method, graph, graphBuilderConfig.eagerResolving());
+            this.frameState = new HIRFrameStateBuilder(method, graph, graphBuilderConfig.eagerResolving());
+            this.parseHelper = new BytecodeParseHelper<>(frameState);
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
                 build();
@@ -222,76 +224,86 @@
                 TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), "  "));
             }
 
-            Indent indent = Debug.logAndIndent("build graph for %s", method);
+            try (Indent indent = Debug.logAndIndent("build graph for %s", method)) {
 
-            // compute the block map, setup exception handlers and get the entrypoint(s)
-            BciBlockMapping blockMap = BciBlockMapping.create(method);
-            loopHeaders = blockMap.loopHeaders;
-            liveness = blockMap.liveness;
+                // compute the block map, setup exception handlers and get the entrypoint(s)
+                BciBlockMapping blockMap = BciBlockMapping.create(method);
+                loopHeaders = blockMap.loopHeaders;
+                liveness = blockMap.liveness;
 
-            lastInstr = currentGraph.start();
-            if (isSynchronized(method.getModifiers())) {
-                // add a monitor enter to the start block
-                currentGraph.start().setStateAfter(frameState.create(FrameState.BEFORE_BCI));
-                methodSynchronizedObject = synchronizedObject(frameState, method);
-                lastInstr = genMonitorEnter(methodSynchronizedObject);
-            }
-            frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
-            ((StateSplit) lastInstr).setStateAfter(frameState.create(0));
+                lastInstr = currentGraph.start();
+                if (isSynchronized(method.getModifiers())) {
+                    // add a monitor enter to the start block
+                    currentGraph.start().setStateAfter(frameState.create(FrameState.BEFORE_BCI));
+                    methodSynchronizedObject = synchronizedObject(frameState, method);
+                    lastInstr = genMonitorEnter(methodSynchronizedObject);
+                }
+                frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
+                ((StateSplit) lastInstr).setStateAfter(frameState.create(0));
+                finishPrepare(lastInstr);
 
-            if (graphBuilderConfig.eagerInfopointMode()) {
-                InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0)));
-                lastInstr.setNext(ipn);
-                lastInstr = ipn;
-            }
+                if (graphBuilderConfig.eagerInfopointMode()) {
+                    InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0)));
+                    lastInstr.setNext(ipn);
+                    lastInstr = ipn;
+                }
 
-            currentBlock = blockMap.startBlock;
-            blockMap.startBlock.entryState = frameState;
-            if (blockMap.startBlock.isLoopHeader) {
-                /*
-                 * TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it
-                 * expects currentBlock, etc. to be set up correctly. A better solution to this
-                 * problem of start blocks that are loop headers would be to create a dummy block in
-                 * BciBlockMapping.
-                 */
-                appendGoto(createTarget(blockMap.startBlock, frameState));
-            } else {
-                blockMap.startBlock.firstInstruction = lastInstr;
-            }
+                currentBlock = blockMap.startBlock;
+                blockMap.startBlock.entryState = frameState;
+                if (blockMap.startBlock.isLoopHeader) {
+                    /*
+                     * TODO(lstadler,gduboscq) createTarget might not be safe at this position,
+                     * since it expects currentBlock, etc. to be set up correctly. A better solution
+                     * to this problem of start blocks that are loop headers would be to create a
+                     * dummy block in BciBlockMapping.
+                     */
+                    appendGoto(createTarget(blockMap.startBlock, frameState));
+                } else {
+                    blockMap.startBlock.firstInstruction = lastInstr;
+                }
 
-            for (Block block : blockMap.blocks) {
-                processBlock(block);
-            }
-            processBlock(unwindBlock);
+                for (BciBlock block : blockMap.blocks) {
+                    processBlock(block);
+                }
+                processBlock(unwindBlock);
 
-            Debug.dump(currentGraph, "After bytecode parsing");
+                Debug.dump(currentGraph, "After bytecode parsing");
+
+                connectLoopEndToBegin();
 
-            connectLoopEndToBegin();
+                // remove Placeholders
+                for (BlockPlaceholderNode n = placeholders; n != null; n = n.nextPlaceholder()) {
+                    if (!n.isDeleted()) {
+                        currentGraph.removeFixed(n);
+                    }
+                }
+                placeholders = null;
 
-            // remove Placeholders
-            for (BlockPlaceholderNode n = placeholders; n != null; n = n.nextPlaceholder()) {
-                if (!n.isDeleted()) {
-                    currentGraph.removeFixed(n);
+                // remove dead FrameStates
+                for (Node n : currentGraph.getNodes(FrameState.class)) {
+                    if (n.usages().isEmpty() && n.predecessor() == null) {
+                        n.safeDelete();
+                    }
                 }
             }
-            placeholders = null;
-
-            // remove dead FrameStates
-            for (Node n : currentGraph.getNodes(FrameState.class)) {
-                if (n.usages().isEmpty() && n.predecessor() == null) {
-                    n.safeDelete();
-                }
-            }
-            indent.outdent();
         }
 
-        private Block unwindBlock(int bci) {
+        /**
+         * A hook for derived classes to modify the graph start instruction or append new
+         * instructions to it.
+         *
+         * @param startInstr The start instruction of the graph.
+         */
+        protected void finishPrepare(FixedWithNextNode startInstr) {
+        }
+
+        private BciBlock unwindBlock(int bci) {
             if (unwindBlock == null) {
                 unwindBlock = new ExceptionDispatchBlock();
                 unwindBlock.startBci = -1;
                 unwindBlock.endBci = -1;
                 unwindBlock.deoptBci = bci;
-                unwindBlock.blockID = Integer.MAX_VALUE;
+                unwindBlock.setId(Integer.MAX_VALUE);
             }
             return unwindBlock;
         }
@@ -304,6 +316,7 @@
             return stream.currentBCI();
         }
 
+        @SuppressWarnings("unused")
         private void loadLocal(int index, Kind kind) {
             frameState.push(kind, frameState.loadLocal(index));
         }
@@ -313,7 +326,7 @@
             if (kind == Kind.Object) {
                 value = frameState.xpop();
                 // astore and astore_<n> may be used to store a returnAddress (jsr)
-                assert value.kind() == Kind.Object || value.kind() == Kind.Int;
+                assert value.getKind() == Kind.Object || value.getKind() == Kind.Int;
             } else {
                 value = frameState.pop(kind);
             }
@@ -428,7 +441,7 @@
             assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci";
             Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, profilingInfo.getExceptionSeen(bci));
 
-            Block dispatchBlock = currentBlock.exceptionDispatchBlock();
+            BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock();
             /*
              * The exception dispatch block is always for the last bytecode of a block, so if we are
              * not at the endBci yet, there is no exception handler for this bci and we can unwind
@@ -438,7 +451,7 @@
                 dispatchBlock = unwindBlock(bci);
             }
 
-            FrameStateBuilder dispatchState = frameState.copy();
+            HIRFrameStateBuilder dispatchState = frameState.copy();
             dispatchState.clearStack();
 
             DispatchBeginNode dispatchBegin;
@@ -454,7 +467,7 @@
                 dispatchState.setRethrowException(true);
             }
             FixedNode target = createTarget(dispatchBlock, dispatchState);
-            dispatchBegin.setNext(target);
+            finishInstruction(dispatchBegin, dispatchState).setNext(target);
             return dispatchBegin;
         }
 
@@ -572,7 +585,6 @@
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
-
         }
 
         private void genArithmeticOp(Kind result, int opcode) {
@@ -730,15 +742,15 @@
         }
 
         private void genGoto() {
-            appendGoto(createTarget(currentBlock.successors.get(0), frameState));
+            appendGoto(createTarget(currentBlock.getSuccessor(0), frameState));
             assert currentBlock.numNormalSuccessors() == 1;
         }
 
         private void ifNode(ValueNode x, Condition cond, ValueNode y) {
             assert !x.isDeleted() && !y.isDeleted();
             assert currentBlock.numNormalSuccessors() == 2;
-            Block trueBlock = currentBlock.successors.get(0);
-            Block falseBlock = currentBlock.successors.get(1);
+            BciBlock trueBlock = currentBlock.getSuccessor(0);
+            BciBlock falseBlock = currentBlock.getSuccessor(1);
             if (trueBlock == falseBlock) {
                 appendGoto(createTarget(trueBlock, frameState));
                 return;
@@ -767,15 +779,15 @@
             ValueNode b = mirror ? x : y;
 
             CompareNode condition;
-            assert !a.kind().isNumericFloat();
+            assert !a.getKind().isNumericFloat();
             if (cond == Condition.EQ || cond == Condition.NE) {
-                if (a.kind() == Kind.Object) {
+                if (a.getKind() == Kind.Object) {
                     condition = new ObjectEqualsNode(a, b);
                 } else {
                     condition = new IntegerEqualsNode(a, b);
                 }
             } else {
-                assert a.kind() != Kind.Object && !cond.isUnsigned();
+                assert a.getKind() != Kind.Object && !cond.isUnsigned();
                 condition = new IntegerLessThanNode(a, b);
             }
             condition = currentGraph.unique(condition);
@@ -902,7 +914,7 @@
         /**
          * 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
          */
@@ -1113,7 +1125,7 @@
         private void genInvokeInterface(JavaMethod target) {
             if (target instanceof ResolvedJavaMethod) {
                 ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true));
-                genInvokeIndirect(InvokeKind.Interface, (ResolvedJavaMethod) target, args);
+                appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args);
             } else {
                 handleUnresolvedInvoke(target, InvokeKind.Interface);
             }
@@ -1148,7 +1160,7 @@
                 }
                 ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(hasReceiver), target.getSignature().getParameterCount(hasReceiver));
                 if (hasReceiver) {
-                    genInvokeIndirect(InvokeKind.Virtual, (ResolvedJavaMethod) target, args);
+                    appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args);
                 } else {
                     appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
                 }
@@ -1163,47 +1175,12 @@
                 assert target != null;
                 assert target.getSignature() != null;
                 ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true));
-                invokeDirect((ResolvedJavaMethod) target, args);
+                appendInvoke(InvokeKind.Special, (ResolvedJavaMethod) target, args);
             } else {
                 handleUnresolvedInvoke(target, InvokeKind.Special);
             }
         }
 
-        private void genInvokeIndirect(InvokeKind invokeKind, ResolvedJavaMethod target, ValueNode[] args) {
-            ValueNode receiver = args[0];
-            // attempt to devirtualize the call
-            ResolvedJavaType klass = target.getDeclaringClass();
-
-            // 0. check for trivial cases
-            if (target.canBeStaticallyBound()) {
-                // check for trivial cases (e.g. final methods, nonvirtual methods)
-                invokeDirect(target, args);
-                return;
-            }
-            // 1. check if the exact type of the receiver can be determined
-            ResolvedJavaType exact = klass.asExactType();
-            if (exact == null && receiver.stamp() instanceof ObjectStamp) {
-                ObjectStamp receiverStamp = (ObjectStamp) receiver.stamp();
-                if (receiverStamp.isExactType()) {
-                    exact = receiverStamp.type();
-                }
-            }
-            if (exact != null) {
-                // either the holder class is exact, or the receiver object has an exact type
-                ResolvedJavaMethod exactMethod = exact.resolveMethod(target);
-                if (exactMethod != null) {
-                    invokeDirect(exactMethod, args);
-                    return;
-                }
-            }
-            // devirtualization failed, produce an actual invokevirtual
-            appendInvoke(invokeKind, target, args);
-        }
-
-        private void invokeDirect(ResolvedJavaMethod target, ValueNode[] args) {
-            appendInvoke(InvokeKind.Special, target, args);
-        }
-
         private void appendInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
             Kind resultType = targetMethod.getSignature().getReturnKind();
             if (DeoptALot.getValue()) {
@@ -1235,7 +1212,7 @@
 
                 InvokeWithExceptionNode invoke = createInvokeWithException(callTarget, resultType);
 
-                Block nextBlock = currentBlock.successors.get(0);
+                BciBlock nextBlock = currentBlock.getSuccessor(0);
                 invoke.setNext(createTarget(nextBlock, frameState));
             }
         }
@@ -1254,7 +1231,7 @@
             DispatchBeginNode exceptionEdge = handleException(null, bci());
             InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
             frameState.pushReturn(resultType, invoke);
-            Block nextBlock = currentBlock.successors.get(0);
+            BciBlock nextBlock = currentBlock.getSuccessor(0);
             invoke.setStateAfter(frameState.create(nextBlock.startBci));
             return invoke;
         }
@@ -1292,7 +1269,7 @@
         }
 
         private void genJsr(int dest) {
-            Block successor = currentBlock.jsrSuccessor;
+            BciBlock successor = currentBlock.jsrSuccessor;
             assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci();
             JsrScope scope = currentBlock.jsrScope;
             if (!successor.jsrScope.pop().equals(scope)) {
@@ -1306,7 +1283,7 @@
         }
 
         private void genRet(int localIndex) {
-            Block successor = currentBlock.retSuccessor;
+            BciBlock successor = currentBlock.retSuccessor;
             ValueNode local = frameState.loadLocal(localIndex);
             JsrScope scope = currentBlock.jsrScope;
             int retAddress = scope.nextReturnAddress();
@@ -1344,7 +1321,7 @@
         /**
          * 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.
          */
@@ -1364,14 +1341,14 @@
             double[] keyProbabilities = switchProbability(nofCases + 1, bci);
 
             Map<Integer, SuccessorInfo> bciToBlockSuccessorIndex = new HashMap<>();
-            for (int i = 0; i < currentBlock.successors.size(); i++) {
-                assert !bciToBlockSuccessorIndex.containsKey(currentBlock.successors.get(i).startBci);
-                if (!bciToBlockSuccessorIndex.containsKey(currentBlock.successors.get(i).startBci)) {
-                    bciToBlockSuccessorIndex.put(currentBlock.successors.get(i).startBci, new SuccessorInfo(i));
+            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<Block> actualSuccessors = new ArrayList<>();
+            ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
             int[] keys = new int[nofCases];
             int[] keySuccessors = new int[nofCases + 1];
             int deoptSuccessorIndex = -1;
@@ -1392,7 +1369,7 @@
                     SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
                     if (info.actualIndex < 0) {
                         info.actualIndex = nextSuccessorIndex++;
-                        actualSuccessors.add(currentBlock.successors.get(info.blockIndex));
+                        actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
                     }
                     keySuccessors[i] = info.actualIndex;
                 }
@@ -1458,15 +1435,15 @@
         private static class Target {
 
             FixedNode fixed;
-            FrameStateBuilder state;
+            HIRFrameStateBuilder state;
 
-            public Target(FixedNode fixed, FrameStateBuilder state) {
+            public Target(FixedNode fixed, HIRFrameStateBuilder state) {
                 this.fixed = fixed;
                 this.state = state;
             }
         }
 
-        private Target checkLoopExit(FixedNode target, Block targetBlock, FrameStateBuilder state) {
+        private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) {
             if (currentBlock != null) {
                 long exits = currentBlock.loops & ~targetBlock.loops;
                 if (exits != 0) {
@@ -1474,7 +1451,7 @@
                     LoopExitNode lastLoopExit = null;
 
                     int pos = 0;
-                    ArrayList<Block> exitLoops = new ArrayList<>(Long.bitCount(exits));
+                    ArrayList<BciBlock> exitLoops = new ArrayList<>(Long.bitCount(exits));
                     do {
                         long lMask = 1L << pos;
                         if ((exits & lMask) != 0) {
@@ -1484,10 +1461,10 @@
                         pos++;
                     } while (exits != 0);
 
-                    Collections.sort(exitLoops, new Comparator<Block>() {
+                    Collections.sort(exitLoops, new Comparator<BciBlock>() {
 
                         @Override
-                        public int compare(Block o1, Block o2) {
+                        public int compare(BciBlock o1, BciBlock o2) {
                             return Long.bitCount(o2.loops) - Long.bitCount(o1.loops);
                         }
                     });
@@ -1496,8 +1473,8 @@
                     if (targetBlock instanceof ExceptionDispatchBlock) {
                         bci = ((ExceptionDispatchBlock) targetBlock).deoptBci;
                     }
-                    FrameStateBuilder newState = state.copy();
-                    for (Block loop : exitLoops) {
+                    HIRFrameStateBuilder newState = state.copy();
+                    for (BciBlock loop : exitLoops) {
                         LoopBeginNode loopBegin = (LoopBeginNode) loop.firstInstruction;
                         LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin));
                         if (lastLoopExit != null) {
@@ -1519,7 +1496,7 @@
             return new Target(target, state);
         }
 
-        private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) {
+        private FixedNode createTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) {
             assert probability >= 0 && probability <= 1.01 : probability;
             if (isNeverExecutedCode(probability)) {
                 return currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
@@ -1533,7 +1510,7 @@
             return probability == 0 && optimisticOpts.removeNeverExecutedCode() && entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI;
         }
 
-        private FixedNode createTarget(Block block, FrameStateBuilder state) {
+        private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) {
             assert block != null && state != null;
             assert !block.isExceptionEntry || state.stackSize() == 1;
 
@@ -1559,7 +1536,7 @@
             }
 
             if (block.firstInstruction instanceof LoopBeginNode) {
-                assert block.isLoopHeader && currentBlock.blockID >= block.blockID : "must be backward branch";
+                assert block.isLoopHeader && currentBlock.getId() >= block.getId() : "must be backward branch";
                 /*
                  * Backward loop edge. We need to create a special LoopEndNode and merge with the
                  * loop begin node created before.
@@ -1572,7 +1549,7 @@
                 Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
                 return result;
             }
-            assert currentBlock == null || currentBlock.blockID < block.blockID : "must not be backward branch";
+            assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
             assert block.firstInstruction.next() == null : "bytecodes already parsed for block";
 
             if (block.firstInstruction instanceof BlockPlaceholderNode) {
@@ -1613,7 +1590,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, Block block, FrameStateBuilder stateAfter) {
+        private AbstractBeginNode createBlockTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) {
             FixedNode target = createTarget(probability, block, stateAfter);
             AbstractBeginNode begin = AbstractBeginNode.begin(target);
 
@@ -1622,7 +1599,7 @@
             return begin;
         }
 
-        private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) {
+        private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) {
             if (isStatic(target.getModifiers())) {
                 return appendConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass));
             } else {
@@ -1630,37 +1607,38 @@
             }
         }
 
-        private void processBlock(Block block) {
+        private void processBlock(BciBlock block) {
             // Ignore blocks that have no predecessors by the time their bytecodes are parsed
             if (block == null || block.firstInstruction == null) {
                 Debug.log("Ignoring block %s", block);
                 return;
             }
-            Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, block.firstInstruction, block.isLoopHeader);
+            try (Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, block.firstInstruction, block.isLoopHeader)) {
 
-            lastInstr = block.firstInstruction;
-            frameState = block.entryState;
-            currentBlock = block;
+                lastInstr = block.firstInstruction;
+                frameState = block.entryState;
+                parseHelper.setCurrentFrameState(frameState);
+                currentBlock = block;
 
-            frameState.cleanupDeletedPhis();
-            if (lastInstr instanceof MergeNode) {
-                int bci = block.startBci;
-                if (block instanceof ExceptionDispatchBlock) {
-                    bci = ((ExceptionDispatchBlock) block).deoptBci;
+                frameState.cleanupDeletedPhis();
+                if (lastInstr instanceof MergeNode) {
+                    int bci = block.startBci;
+                    if (block instanceof ExceptionDispatchBlock) {
+                        bci = ((ExceptionDispatchBlock) block).deoptBci;
+                    }
+                    ((MergeNode) lastInstr).setStateAfter(frameState.create(bci));
                 }
-                ((MergeNode) lastInstr).setStateAfter(frameState.create(bci));
+
+                if (block == unwindBlock) {
+                    frameState.setRethrowException(false);
+                    createUnwind();
+                } else if (block instanceof ExceptionDispatchBlock) {
+                    createExceptionDispatch((ExceptionDispatchBlock) block);
+                } else {
+                    frameState.setRethrowException(false);
+                    iterateBytecodesForBlock(block);
+                }
             }
-
-            if (block == unwindBlock) {
-                frameState.setRethrowException(false);
-                createUnwind();
-            } else if (block instanceof ExceptionDispatchBlock) {
-                createExceptionDispatch((ExceptionDispatchBlock) block);
-            } else {
-                frameState.setRethrowException(false);
-                iterateBytecodesForBlock(block);
-            }
-            indent.outdent();
         }
 
         private void connectLoopEndToBegin() {
@@ -1696,7 +1674,7 @@
             if (Modifier.isSynchronized(method.getModifiers())) {
                 MonitorExitNode monitorExit = genMonitorExit(methodSynchronizedObject, returnValue);
                 if (returnValue != null) {
-                    frameState.push(returnValue.kind(), returnValue);
+                    frameState.push(returnValue.getKind(), returnValue);
                 }
                 monitorExit.setStateAfter(frameState.create(bci));
                 assert !frameState.rethrowException();
@@ -1706,8 +1684,8 @@
         private void createExceptionDispatch(ExceptionDispatchBlock block) {
             assert frameState.stackSize() == 1 : frameState;
             if (block.handler.isCatchAll()) {
-                assert block.successors.size() == 1;
-                appendGoto(createTarget(block.successors.get(0), frameState));
+                assert block.getSuccessorCount() == 1;
+                appendGoto(createTarget(block.getSuccessor(0), frameState));
                 return;
             }
 
@@ -1720,7 +1698,7 @@
                 ResolvedJavaType resolvedCatchType = (ResolvedJavaType) catchType;
                 for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
                     if (skippedType.isAssignableFrom(resolvedCatchType)) {
-                        Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1);
+                        BciBlock nextBlock = block.getSuccessorCount() == 1 ? unwindBlock(block.deoptBci) : block.getSuccessor(1);
                         ValueNode exception = frameState.stackAt(0);
                         FixedNode trueSuccessor = currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
                         FixedNode nextDispatch = createTarget(nextBlock, frameState);
@@ -1731,12 +1709,12 @@
             }
 
             if (initialized) {
-                Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1);
+                BciBlock nextBlock = block.getSuccessorCount() == 1 ? unwindBlock(block.deoptBci) : block.getSuccessor(1);
                 ValueNode exception = frameState.stackAt(0);
                 CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false));
                 frameState.apop();
                 frameState.push(Kind.Object, checkCast);
-                FixedNode catchSuccessor = createTarget(block.successors.get(0), frameState);
+                FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState);
                 frameState.apop();
                 frameState.push(Kind.Object, exception);
                 FixedNode nextDispatch = createTarget(nextBlock, frameState);
@@ -1757,7 +1735,7 @@
             return n instanceof ControlSplitNode || n instanceof ControlSinkNode;
         }
 
-        private void iterateBytecodesForBlock(Block block) {
+        private void iterateBytecodesForBlock(BciBlock block) {
             if (block.isLoopHeader) {
                 // Create the loop header block, which later will merge the backward branches of the
                 // loop.
@@ -1789,6 +1767,8 @@
             assert lastInstr.next() == null : "instructions already appended at block " + block;
             Debug.log("  frameState: %s", frameState);
 
+            lastInstr = finishInstruction(lastInstr, frameState);
+
             int endBCI = stream.endBCI();
 
             stream.setBCI(block.startBci);
@@ -1838,18 +1818,30 @@
                         }
                     }
                 }
+                lastInstr = finishInstruction(lastInstr, frameState);
                 if (bci < endBCI) {
                     if (bci > block.endBci) {
-                        assert !block.successors.get(0).isExceptionEntry;
+                        assert !block.getSuccessor(0).isExceptionEntry;
                         assert block.numNormalSuccessors() == 1;
                         // we fell through to the next block, add a goto and break
-                        appendGoto(createTarget(block.successors.get(0), frameState));
+                        appendGoto(createTarget(block.getSuccessor(0), frameState));
                         break;
                     }
                 }
             }
         }
 
+        /**
+         * A hook for derived classes to modify the last instruction or add other instructions.
+         *
+         * @param instr The last instruction (= fixed node) which was added.
+         * @param state The current frame state.
+         * @Returns Returns the (new) last instruction.
+         */
+        protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, HIRFrameStateBuilder state) {
+            return instr;
+        }
+
         private final int traceLevel = Options.TraceBytecodeParserLevel.getValue();
 
         private void traceState() {
@@ -1857,11 +1849,11 @@
                 Debug.log(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method));
                 for (int i = 0; i < frameState.localsSize(); ++i) {
                     ValueNode value = frameState.localAt(i);
-                    Debug.log(String.format("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind().getJavaName(), value));
+                    Debug.log(String.format("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value));
                 }
                 for (int i = 0; i < frameState.stackSize(); ++i) {
                     ValueNode value = frameState.stackAt(i);
-                    Debug.log(String.format("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind().getJavaName(), value));
+                    Debug.log(String.format("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value));
                 }
             }
         }
@@ -1893,31 +1885,31 @@
             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          : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Int); break;
+            case LLOAD          : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Long); break;
+            case FLOAD          : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Float); break;
+            case DLOAD          : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Double); break;
+            case ALOAD          : parseHelper.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 ILOAD_3        : parseHelper.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 LLOAD_3        : parseHelper.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 FLOAD_3        : parseHelper.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 DLOAD_3        : parseHelper.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 ALOAD_3        : parseHelper.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;
@@ -2098,7 +2090,7 @@
                 if (!currentBlock.jsrScope.isEmpty()) {
                     sb.append(' ').append(currentBlock.jsrScope);
                 }
-                Debug.log(sb.toString());
+                Debug.log("%s", sb);
             }
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,579 @@
+/*
+ * 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.java;
+
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+import static com.oracle.graal.nodes.ValueNodeUtil.*;
+import static java.lang.reflect.Modifier.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+
+public class HIRFrameStateBuilder extends AbstractFrameStateBuilder<ValueNode> {
+
+    private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
+
+    private final ValueNode[] locals;
+    private final ValueNode[] stack;
+    private ValueNode[] lockedObjects;
+    private MonitorIdNode[] monitorIds;
+    private final StructuredGraph graph;
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    private boolean rethrowException;
+
+    public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean eagerResolve) {
+        super(method);
+
+        assert graph != null;
+
+        this.locals = new ValueNode[method.getMaxLocals()];
+        // we always need at least one stack slot (for exceptions)
+        this.stack = new ValueNode[Math.max(1, method.getMaxStackSize())];
+        this.lockedObjects = EMPTY_ARRAY;
+        this.monitorIds = EMPTY_MONITOR_ARRAY;
+        this.graph = graph;
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!isStatic(method.getModifiers())) {
+            // add the receiver
+            ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass())));
+            storeLocal(javaIndex, 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().getStackKind();
+            Stamp stamp;
+            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
+                stamp = StampFactory.declared((ResolvedJavaType) type);
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            ParameterNode param = graph.unique(new ParameterNode(index, stamp));
+            storeLocal(javaIndex, param);
+            javaIndex += stackSlots(kind);
+            index++;
+        }
+    }
+
+    private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
+        super(other);
+        assert other.graph != null;
+        graph = other.graph;
+        locals = other.locals.clone();
+        stack = other.stack.clone();
+        lockedObjects = other.lockedObjects == EMPTY_ARRAY ? EMPTY_ARRAY : other.lockedObjects.clone();
+        monitorIds = other.monitorIds == EMPTY_MONITOR_ARRAY ? EMPTY_MONITOR_ARRAY : other.monitorIds.clone();
+        stackSize = other.stackSize;
+        rethrowException = other.rethrowException;
+
+        assert locals.length == method.getMaxLocals();
+        assert stack.length == Math.max(1, method.getMaxStackSize());
+        assert lockedObjects.length == monitorIds.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) {
+        return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), lockedObjects, monitorIds, rethrowException, false));
+    }
+
+    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(MergeNode block, HIRFrameStateBuilder other) {
+        assert isCompatibleWith(other);
+
+        for (int i = 0; i < localsSize(); i++) {
+            storeLocal(i, merge(localAt(i), other.localAt(i), block));
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            storeStack(i, merge(stackAt(i), other.stackAt(i), block));
+        }
+        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, MergeNode block) {
+        if (currentValue == null || currentValue.isDeleted()) {
+            return null;
+
+        } else if (block.isPhiAtMerge(currentValue)) {
+            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
+                propagateDelete((PhiNode) currentValue);
+                return null;
+            }
+            ((PhiNode) currentValue).addInput(otherValue);
+            return currentValue;
+
+        } else if (currentValue != otherValue) {
+            assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for all locals and stack slots";
+            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
+                return null;
+            }
+
+            PhiNode phi = graph.addWithoutUnique(new PhiNode(currentValue.stamp().unrestricted(), block));
+            for (int i = 0; i < block.phiPredecessorCount(); i++) {
+                phi.addInput(currentValue);
+            }
+            phi.addInput(otherValue);
+            assert phi.valueCount() == block.phiPredecessorCount() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.phiPredecessorCount();
+            return phi;
+
+        } else {
+            return currentValue;
+        }
+    }
+
+    private void propagateDelete(FloatingNode node) {
+        assert node instanceof PhiNode || 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(PhiNode.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(PhiNode.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(LoopBeginNode loopBegin) {
+        for (int i = 0; i < localsSize(); 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 PhiNode createLoopPhi(MergeNode block, ValueNode value) {
+        if (value == null) {
+            return null;
+        }
+        assert !block.isPhiAtMerge(value) : "phi function for this block already created";
+
+        PhiNode phi = graph.addWithoutUnique(new PhiNode(value.stamp().unrestricted(), block));
+        phi.addInput(value);
+        return phi;
+    }
+
+    public void cleanupDeletedPhis() {
+        for (int i = 0; i < localsSize(); i++) {
+            if (localAt(i) != null && localAt(i).isDeleted()) {
+                assert localAt(i) instanceof PhiNode || localAt(i) instanceof ProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i);
+                storeLocal(i, null);
+            }
+        }
+    }
+
+    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
+        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;
+    }
+
+    @Override
+    public int localsSize() {
+        return locals.length;
+    }
+
+    @Override
+    public ValueNode localAt(int i) {
+        return locals[i];
+    }
+
+    @Override
+    public ValueNode stackAt(int i) {
+        return stack[i];
+    }
+
+    /**
+     * 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);
+        }
+    }
+
+    public MonitorIdNode peekMonitorId() {
+        return monitorIds[monitorIds.length - 1];
+    }
+
+    /**
+     * @return the current lock depth
+     */
+    public int lockDepth() {
+        assert lockedObjects.length == monitorIds.length;
+        return lockedObjects.length;
+    }
+
+    @Override
+    public ValueNode loadLocal(int i) {
+        ValueNode x = locals[i];
+        assert !x.isDeleted();
+        assert !isTwoSlot(x.getKind()) || locals[i + 1] == null;
+        assert i == 0 || locals[i - 1] == null || !isTwoSlot(locals[i - 1].getKind());
+        return x;
+    }
+
+    @Override
+    public void storeLocal(int i, ValueNode x) {
+        assert x == null || x.isAlive() && x.getKind() != Kind.Void && x.getKind() != Kind.Illegal : "unexpected value: " + x;
+        locals[i] = x;
+        if (x != null && isTwoSlot(x.getKind())) {
+            // if this is a double word, then kill i+1
+            locals[i + 1] = null;
+        }
+        if (x != null && i > 0) {
+            ValueNode p = locals[i - 1];
+            if (p != null && isTwoSlot(p.getKind())) {
+                // if there was a double word at i - 1, then kill it
+                locals[i - 1] = null;
+            }
+        }
+    }
+
+    @Override
+    public void storeStack(int i, ValueNode x) {
+        assert x == null || x.isAlive() && (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;
+    }
+
+    @Override
+    public void push(Kind kind, ValueNode x) {
+        assert x.isAlive() && x.getKind() != Kind.Void && x.getKind() != Kind.Illegal;
+        xpush(assertKind(kind, x));
+        if (isTwoSlot(kind)) {
+            xpush(null);
+        }
+    }
+
+    @Override
+    public void xpush(ValueNode x) {
+        assert x == null || (x.isAlive() && x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        stack[stackSize++] = x;
+    }
+
+    @Override
+    public void ipush(ValueNode x) {
+        xpush(assertInt(x));
+    }
+
+    @Override
+    public void fpush(ValueNode x) {
+        xpush(assertFloat(x));
+    }
+
+    @Override
+    public void apush(ValueNode x) {
+        xpush(assertObject(x));
+    }
+
+    @Override
+    public void lpush(ValueNode x) {
+        xpush(assertLong(x));
+        xpush(null);
+    }
+
+    @Override
+    public void dpush(ValueNode x) {
+        xpush(assertDouble(x));
+        xpush(null);
+    }
+
+    @Override
+    public void pushReturn(Kind kind, ValueNode x) {
+        if (kind != Kind.Void) {
+            push(kind.getStackKind(), x);
+        }
+    }
+
+    @Override
+    public ValueNode pop(Kind kind) {
+        assert kind != Kind.Void;
+        if (isTwoSlot(kind)) {
+            xpop();
+        }
+        return assertKind(kind, xpop());
+    }
+
+    @Override
+    public ValueNode xpop() {
+        ValueNode result = stack[--stackSize];
+        assert result == null || !result.isDeleted();
+        return result;
+    }
+
+    @Override
+    public ValueNode ipop() {
+        return assertInt(xpop());
+    }
+
+    @Override
+    public ValueNode fpop() {
+        return assertFloat(xpop());
+    }
+
+    @Override
+    public ValueNode apop() {
+        return assertObject(xpop());
+    }
+
+    @Override
+    public ValueNode lpop() {
+        assertHigh(xpop());
+        return assertLong(xpop());
+    }
+
+    @Override
+    public ValueNode dpop() {
+        assertHigh(xpop());
+        return assertDouble(xpop());
+    }
+
+    @Override
+    public ValueNode[] popArguments(int slotSize, int argSize) {
+        int base = stackSize - slotSize;
+        ValueNode[] r = new ValueNode[argSize];
+        int argIndex = 0;
+        int stackindex = 0;
+        while (stackindex < slotSize) {
+            ValueNode element = stack[base + stackindex];
+            assert element != null;
+            r[argIndex++] = element;
+            stackindex += stackSlots(element.getKind());
+        }
+        stackSize = base;
+        return r;
+    }
+
+    @Override
+    public ValueNode peek(int argumentNumber) {
+        int idx = stackSize() - 1;
+        for (int i = 0; i < argumentNumber; i++) {
+            if (stackAt(idx) == null) {
+                idx--;
+                assert isTwoSlot(stackAt(idx).getKind());
+            }
+            idx--;
+        }
+        return stackAt(idx);
+    }
+
+    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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_getfield1.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ */
+package com.oracle.graal.jtt.except;
+
+import com.oracle.graal.jtt.*;
+
+import org.junit.*;
+
+public class BC_getfield1 extends JTTTest {
+
+    private int field = 13;
+
+    public static void test(BC_getfield1 arg) {
+        @SuppressWarnings("unused")
+        int i = arg.field;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", (Object) null);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        // tests that the null check isn't removed along with the read
+        runTest(EMPTY, true, true, "test", (Object) null);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", new BC_getfield1());
+    }
+
+}
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Sun Mar 30 16:08:33 2014 +0200
@@ -46,19 +46,18 @@
         return sum;
     }
 
-    // CheckStyle: stop system..print check
     private static void doPrint(int n) {
+        PrintStream out = System.out;
         for (int i = 0; i < n; i++) {
-            System.out.print('x');
+            out.print('x');
         }
     }
 
     public static void main(String[] args) throws Exception {
-        System.out.println(test(10000));
+        PrintStream out = System.out;
+        out.println(test(10000));
     }
 
-    // CheckStyle: resume system..print check
-
     @LongTest
     public void run0() throws Throwable {
         runTest("test", 10000);
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Sun Mar 30 16:08:33 2014 +0200
@@ -49,6 +49,7 @@
     I2F, I2D,
     L2F, L2D,
     MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L,
+    MOV_B2UI, MOV_B2UL, // Zero extending byte loads
 
     /*
      * Converts a float/double to an int/long. The result of the conversion does not comply with Java semantics
@@ -102,6 +103,32 @@
     }
 
     /**
+     * Unary operation with separate memory source and destination operand.
+     */
+    public static class Unary2MemoryOp extends AMD64LIRInstruction {
+
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({COMPOSITE}) protected AMD64AddressValue x;
+        @State protected LIRFrameState state;
+
+        public Unary2MemoryOp(AMD64Arithmetic opcode, AllocatableValue result, AMD64AddressValue x, LIRFrameState state) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emit(crb, masm, opcode, result, x, null);
+        }
+    }
+
+    /**
      * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand may be a stack slot.
      */
@@ -135,6 +162,45 @@
 
     /**
      * Binary operation with two operands. The first source operand is combined with the
+     * destination. The second source operand may be a stack slot.
+     */
+    public static class BinaryMemory extends AMD64LIRInstruction {
+
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        protected final Kind kind;
+        @Alive({COMPOSITE}) protected AMD64AddressValue location;
+        @State protected LIRFrameState state;
+
+        public BinaryMemory(AMD64Arithmetic opcode, Kind kind, AllocatableValue result, AllocatableValue x, AMD64AddressValue location, LIRFrameState state) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.location = location;
+            this.kind = kind;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emit(crb, masm, opcode, result, location, null);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert differentRegisters(result, location) || sameRegister(x, location);
+            // verifyKind(opcode, result, x, location);
+        }
+    }
+
+    /**
+     * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand must be a register.
      */
     public static class BinaryRegReg extends AMD64LIRInstruction {
@@ -688,7 +754,8 @@
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
-        } else {
+        } else if (isStackSlot(src)) {
+
             switch (opcode) {
                 case IADD:
                     masm.addl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
@@ -819,6 +886,143 @@
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
+        } else {
+            switch (opcode) {
+                case IADD:
+                    masm.addl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case ISUB:
+                    masm.subl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IAND:
+                    masm.andl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IMUL:
+                    masm.imull(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IOR:
+                    masm.orl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IXOR:
+                    masm.xorl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case LADD:
+                    masm.addq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LSUB:
+                    masm.subq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LMUL:
+                    masm.imulq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LAND:
+                    masm.andq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LOR:
+                    masm.orq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LXOR:
+                    masm.xorq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case FADD:
+                    masm.addss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case FSUB:
+                    masm.subss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case FMUL:
+                    masm.mulss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case FDIV:
+                    masm.divss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case DADD:
+                    masm.addsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case DSUB:
+                    masm.subsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case DMUL:
+                    masm.mulsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case DDIV:
+                    masm.divsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case SQRT:
+                    masm.sqrtsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case B2I:
+                    masm.movsbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case S2I:
+                    masm.movswl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case B2L:
+                    masm.movsbq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case S2L:
+                    masm.movswq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case I2L:
+                    masm.movslq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case F2D:
+                    masm.cvtss2sd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case D2F:
+                    masm.cvtsd2ss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case I2F:
+                    masm.cvtsi2ssl(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case I2D:
+                    masm.cvtsi2sdl(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case L2F:
+                    masm.cvtsi2ssq(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case L2D:
+                    masm.cvtsi2sdq(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case F2I:
+                    masm.cvttss2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case D2I:
+                    masm.cvttsd2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case F2L:
+                    masm.cvttss2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case D2L:
+                    masm.cvttsd2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_I2F:
+                    masm.movss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_L2D:
+                    masm.movsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_F2I:
+                    masm.movl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_D2L:
+                    masm.movq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_B2UI:
+                    masm.movzbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_B2UL:
+                    masm.movzbl(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
 
         if (info != null) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Sun Mar 30 16:08:33 2014 +0200
@@ -31,7 +31,6 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
-// @formatter:off
 public enum AMD64Compare {
     ICMP, LCMP, ACMP, FCMP, DCMP;
 
@@ -54,57 +53,152 @@
         @Override
         protected void verify() {
             super.verify();
-            assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int)
-                || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long)
-                || (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object)
-                || (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float)
-                || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
+            assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) ||
+                            (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) ||
+                            (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
+        }
+    }
+
+    public static class CompareMemoryOp extends AMD64LIRInstruction {
+        @Opcode private final AMD64Compare opcode;
+        @Use({REG, COMPOSITE}) protected Value x;
+        @Use({CONST, COMPOSITE}) protected Value y;
+        @State protected LIRFrameState state;
+
+        /**
+         * Compare memory, constant or register, memory.
+         */
+        public CompareMemoryOp(AMD64Compare opcode, Value x, Value y, LIRFrameState state) {
+            assert (x instanceof AMD64AddressValue && y instanceof Constant) || (x instanceof Variable && y instanceof AMD64AddressValue);
+            this.opcode = opcode;
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emit(crb, masm, opcode, x, y);
+        }
+
+        @Override
+        protected void verify() {
+            super.verify();
+            assert (x instanceof AMD64AddressValue && y instanceof Constant) || (x instanceof Variable && y instanceof AMD64AddressValue);
         }
     }
 
     public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Compare opcode, Value x, Value y) {
-        if (isRegister(y)) {
+        if (isRegister(x) && isRegister(y)) {
             switch (opcode) {
-                case ICMP: masm.cmpl(asIntReg(x), asIntReg(y)); break;
-                case LCMP: masm.cmpq(asLongReg(x), asLongReg(y)); break;
-                case ACMP: masm.cmpptr(asObjectReg(x), asObjectReg(y)); break;
-                case FCMP: masm.ucomiss(asFloatReg(x), asFloatReg(y)); break;
-                case DCMP: masm.ucomisd(asDoubleReg(x), asDoubleReg(y)); break;
-                default:   throw GraalInternalError.shouldNotReachHere();
+                case ICMP:
+                    masm.cmpl(asIntReg(x), asIntReg(y));
+                    break;
+                case LCMP:
+                    masm.cmpq(asLongReg(x), asLongReg(y));
+                    break;
+                case ACMP:
+                    masm.cmpptr(asObjectReg(x), asObjectReg(y));
+                    break;
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), asFloatReg(y));
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), asDoubleReg(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        } else if (isConstant(y)) {
+        } else if (isRegister(x) && isConstant(y)) {
             boolean isZero = ((Constant) y).isDefaultForKind();
             switch (opcode) {
-                case ICMP: if (isZero) {
-                    masm.testl(asIntReg(x), asIntReg(x));
-                } else {
-                    masm.cmpl(asIntReg(x), crb.asIntConst(y));
-                }
-                break;
-                case LCMP: if (isZero) {
-                    masm.testq(asLongReg(x), asLongReg(x));
-                } else {
-                    masm.cmpq(asLongReg(x), crb.asIntConst(y));
-                }
-                break;
+                case ICMP:
+                    if (isZero) {
+                        masm.testl(asIntReg(x), asIntReg(x));
+                    } else {
+                        masm.cmpl(asIntReg(x), crb.asIntConst(y));
+                    }
+                    break;
+                case LCMP:
+                    if (isZero) {
+                        masm.testq(asLongReg(x), asLongReg(x));
+                    } else {
+                        masm.cmpq(asLongReg(x), crb.asIntConst(y));
+                    }
+                    break;
                 case ACMP:
                     if (isZero) {
-                        masm.testq(asObjectReg(x), asObjectReg(x)); break;
+                        masm.testq(asObjectReg(x), asObjectReg(x));
+                        break;
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons");
                     }
-                case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y)); break;
-                case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y)); break;
-                default:   throw GraalInternalError.shouldNotReachHere();
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y));
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        } else {
+        } else if (isRegister(x) && isStackSlot(y)) {
+            switch (opcode) {
+                case ICMP:
+                    masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y));
+                    break;
+                case LCMP:
+                    masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y));
+                    break;
+                case ACMP:
+                    masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y));
+                    break;
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y));
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else if (isRegister(x) && y instanceof AMD64AddressValue) {
             switch (opcode) {
-                case ICMP: masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y)); break;
-                case LCMP: masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y)); break;
-                case ACMP: masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y)); break;
-                case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y)); break;
-                case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y)); break;
-                default:  throw GraalInternalError.shouldNotReachHere();
+                case ICMP:
+                    masm.cmpl(asIntReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case LCMP:
+                    masm.cmpq(asLongReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case ACMP:
+                    masm.cmpptr(asObjectReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else if (x instanceof AMD64AddressValue && isConstant(y)) {
+            switch (opcode) {
+                case ICMP:
+                    masm.cmpl(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y));
+                    break;
+                case LCMP:
+                    if (crb.asLongConst(y) == (int) crb.asLongConst(y)) {
+                        masm.cmpq(((AMD64AddressValue) x).toAddress(), (int) crb.asLongConst(y));
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere();
+                    }
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
         }
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,6 +29,7 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CompilationResult.RawData;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
@@ -171,6 +172,38 @@
         }
     }
 
+    public static class ZeroExtendLoadOp extends MemOp {
+
+        @Def({REG}) protected AllocatableValue result;
+
+        public ZeroExtendLoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) {
+            super(kind, address, state);
+            this.result = result;
+        }
+
+        @Override
+        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            switch (kind) {
+                case Boolean:
+                case Byte:
+                    masm.movzbl(asRegister(result), address.toAddress());
+                    break;
+                case Char:
+                case Short:
+                    masm.movzwl(asRegister(result), address.toAddress());
+                    break;
+                case Int:
+                    masm.movl(asRegister(result), address.toAddress());
+                    break;
+                case Long:
+                    masm.movq(asRegister(result), address.toAddress());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
     public static class StoreOp extends MemOp {
 
         @Use({REG}) protected AllocatableValue input;
@@ -277,6 +310,23 @@
         }
     }
 
+    public static class LeaDataOp extends AMD64LIRInstruction {
+
+        @Def({REG}) protected AllocatableValue result;
+        private final byte[] data;
+
+        public LeaDataOp(AllocatableValue result, byte[] data) {
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            RawData rawData = new RawData(data, 16);
+            masm.leaq(asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(rawData));
+        }
+    }
+
     public static class StackLeaOp extends AMD64LIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64TestMemoryOp extends AMD64LIRInstruction {
+
+    @Use({COMPOSITE}) protected AMD64AddressValue x;
+    @Use({REG, CONST}) protected Value y;
+    @State protected LIRFrameState state;
+
+    public AMD64TestMemoryOp(AMD64AddressValue x, Value y, LIRFrameState state) {
+        this.x = x;
+        this.y = y;
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        emit(crb, masm, x, y);
+    }
+
+    @Override
+    protected void verify() {
+        super.verify();
+        // Can't check the kind of an address so just check the other input
+        assert (x.getKind() == Kind.Int || x.getKind() == Kind.Long) : x + " " + y;
+    }
+
+    public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value x, Value y) {
+        if (isRegister(y)) {
+            switch (y.getKind()) {
+                case Int:
+                    masm.testl(asIntReg(y), ((AMD64AddressValue) x).toAddress());
+                    break;
+                case Long:
+                    masm.testq(asLongReg(y), ((AMD64AddressValue) x).toAddress());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else if (isConstant(y)) {
+            switch (y.getKind()) {
+                case Int:
+                    masm.testl(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y));
+                    break;
+                case Long:
+                    masm.testq(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Sun Mar 30 16:08:33 2014 +0200
@@ -34,6 +34,11 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.calc.*;
 
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hsail.HSAIL;
+
 /**
  * Implementation of control flow instructions.
  */
@@ -96,11 +101,11 @@
                 protected void conditionalJump(int index, Condition condition, Label target) {
                     switch (key.getKind()) {
                         case Int:
+                        case Long:
                             // Generate cascading compare and branches for each case.
                             masm.emitCompare(key, keyConstants[index], HSAILCompare.conditionToString(condition), false, false);
                             masm.cbr(masm.nameOf(target));
                             break;
-                        case Long:
                         case Object:
                         default:
                             throw new GraalInternalError("switch only supported for int");
@@ -126,6 +131,100 @@
         }
     }
 
+    /***
+     * The ALIVE annotation is so we can get a scratch32 register that does not clobber
+     * actionAndReason.
+     */
+    public static class DeoptimizeOp extends ReturnOp {
+
+        @Alive({REG, CONST}) protected Value actionAndReason;
+        @State protected LIRFrameState frameState;
+        protected MetaAccessProvider metaAccessProvider;
+        protected String emitName;
+        protected int codeBufferPos = -1;
+        protected int dregOopMap = 0;
+
+        public DeoptimizeOp(Value actionAndReason, LIRFrameState frameState, String emitName, MetaAccessProvider metaAccessProvider) {
+            super(Value.ILLEGAL);   // return with no ret value
+            this.actionAndReason = actionAndReason;
+            this.frameState = frameState;
+            this.emitName = emitName;
+            this.metaAccessProvider = metaAccessProvider;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+            String reasonString;
+            if (isConstant(actionAndReason)) {
+                DeoptimizationReason reason = metaAccessProvider.decodeDeoptReason((Constant) actionAndReason);
+                reasonString = reason.toString();
+            } else {
+                reasonString = "Variable Reason";
+            }
+
+            masm.emitComment("// " + emitName + ", Deoptimization for " + reasonString);
+
+            if (frameState == null) {
+                masm.emitComment("// frameState == null");
+                // and emit the return
+                super.emitCode(crb, masm);
+                return;
+            }
+            // get a unique codeBuffer position
+            // when we save our state, we will save this as well (it can be used as a key to get the
+            // debugInfo)
+            codeBufferPos = masm.position();
+
+            // get the bitmap of $d regs that contain references
+            ReferenceMap referenceMap = frameState.debugInfo().getReferenceMap();
+            for (int dreg = HSAIL.d0.number; dreg <= HSAIL.d15.number; dreg++) {
+                if (referenceMap.getRegister(dreg) == Kind.Object) {
+                    dregOopMap |= 1 << (dreg - HSAIL.d0.number);
+                }
+            }
+
+            // here we will by convention use some never-allocated registers to pass to the epilogue
+            // deopt code
+            // todo: define these in HSAIL.java
+            // we need to pass the actionAndReason and the codeBufferPos
+
+            AllocatableValue actionAndReasonReg = HSAIL.s32.asValue(Kind.Int);
+            AllocatableValue codeBufferOffsetReg = HSAIL.s33.asValue(Kind.Int);
+            AllocatableValue dregOopMapReg = HSAIL.s39.asValue(Kind.Int);
+            masm.emitMov(actionAndReasonReg, actionAndReason);
+            masm.emitMov(codeBufferOffsetReg, Constant.forInt(codeBufferPos));
+            masm.emitMov(dregOopMapReg, Constant.forInt(dregOopMap));
+            masm.emitJumpToLabelName(masm.getDeoptLabelName());
+
+            // now record the debuginfo
+            crb.recordInfopoint(codeBufferPos, frameState, InfopointReason.IMPLICIT_EXCEPTION);
+        }
+
+        public LIRFrameState getFrameState() {
+            return frameState;
+        }
+
+        public int getCodeBufferPos() {
+            return codeBufferPos;
+        }
+    }
+
+    public static class UnwindOp extends ReturnOp {
+
+        protected String commentMessage;
+
+        public UnwindOp(String commentMessage) {
+            super(Value.ILLEGAL);   // return with no ret value
+            this.commentMessage = commentMessage;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+            masm.emitComment("// " + commentMessage);
+            super.emitCode(crb, masm);
+        }
+    }
+
     public static class ForeignCallNoArgOp extends HSAILLIRInstruction {
 
         @Def({REG}) protected Value out;
@@ -224,7 +323,7 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
             HSAILCompare.emit(crb, masm, condition, left, right, right, false);
-            cmove(crb, masm, result, false, trueValue, falseValue);
+            cmove(masm, result, trueValue, falseValue);
         }
     }
 
@@ -240,12 +339,11 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
             HSAILCompare.emit(crb, masm, condition, left, right, right, unorderedIsTrue);
-            cmove(crb, masm, result, false, trueValue, falseValue);
+            cmove(masm, result, trueValue, falseValue);
         }
     }
 
-    @SuppressWarnings("unused")
-    private static void cmove(CompilationResultBuilder crb, HSAILAssembler masm, Value result, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
+    private static void cmove(HSAILAssembler masm, Value result, Value trueValue, Value falseValue) {
         // Check that we don't overwrite an input operand before it is used.
         assert (result.getKind() == trueValue.getKind() && result.getKind() == falseValue.getKind());
         int width;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,13 +23,32 @@
 package com.oracle.graal.lir.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Add;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Ldf;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsb;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsh;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Lduh;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Membar;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Rdpc;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Stb;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Sth;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Stw;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Stx;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cas;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Casx;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Clr;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setuw;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Sun Mar 30 16:08:33 2014 +0200
@@ -37,9 +37,8 @@
     /**
      * Performs control flow optimizations on the given LIR graph.
      */
-    public static void optimize(LIR lir) {
-        List<Block> blocks = lir.codeEmittingOrder();
-        ControlFlowOptimizer.deleteEmptyBlocks(lir, blocks);
+    public static <T extends AbstractBlock<T>> void optimize(LIR lir, List<T> codeEmittingOrder) {
+        ControlFlowOptimizer.deleteEmptyBlocks(lir, codeEmittingOrder);
     }
 
     private ControlFlowOptimizer() {
@@ -54,41 +53,41 @@
      * @param block the block checked for deletion
      * @return whether the block can be deleted
      */
-    private static boolean canDeleteBlock(LIR lir, Block block) {
-        if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getFirstSuccessor() == block) {
+    private static boolean canDeleteBlock(LIR lir, AbstractBlock<?> block) {
+        if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getSuccessors().iterator().next() == block) {
             return false;
         }
 
-        List<LIRInstruction> instructions = lir.lir(block);
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
 
         assert instructions.size() >= 2 : "block must have label and branch";
         assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
         assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch";
-        assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.lir(block.getFirstSuccessor()).get(0)).getLabel() : "branch target must be the successor";
+        assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.getLIRforBlock(block.getSuccessors().iterator().next()).get(0)).getLabel() : "branch target must be the successor";
 
         // Block must have exactly one successor.
         return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry();
     }
 
-    private static void alignBlock(LIR lir, Block block) {
+    private static void alignBlock(LIR lir, AbstractBlock<?> block) {
         if (!block.isAligned()) {
             block.setAlign(true);
-            List<LIRInstruction> instructions = lir.lir(block);
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
             assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
             StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0);
             instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true));
         }
     }
 
-    private static void deleteEmptyBlocks(LIR lir, List<Block> blocks) {
+    private static <T extends AbstractBlock<T>> void deleteEmptyBlocks(LIR lir, List<T> blocks) {
         assert verifyBlocks(lir, blocks);
-        Iterator<Block> iterator = blocks.iterator();
+        Iterator<T> iterator = blocks.iterator();
         while (iterator.hasNext()) {
-            Block block = iterator.next();
+            T block = iterator.next();
             if (canDeleteBlock(lir, block)) {
                 // adjust successor and predecessor lists
-                Block other = block.getFirstSuccessor();
-                for (Block pred : block.getPredecessors()) {
+                T other = block.getSuccessors().iterator().next();
+                for (AbstractBlock<T> pred : block.getPredecessors()) {
                     Collections.replaceAll(pred.getSuccessors(), block, other);
                 }
                 for (int i = 0; i < other.getPredecessorCount(); i++) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Sun Mar 30 16:08:33 2014 +0200
@@ -53,10 +53,10 @@
     public static void optimize(LIR ir) {
         EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(ir);
 
-        List<Block> blockList = ir.linearScanOrder();
+        List<? extends AbstractBlock<?>> blockList = ir.linearScanOrder();
         // ignore the first block in the list (index 0 is not processed)
         for (int i = blockList.size() - 1; i >= 1; i--) {
-            Block block = blockList.get(i);
+            AbstractBlock<?> block = blockList.get(i);
 
             if (block.getPredecessorCount() > 1) {
                 optimizer.optimizeMovesAtBlockEnd(block);
@@ -103,8 +103,8 @@
      * Moves the longest {@linkplain #same common} subsequence at the end all predecessors of
      * {@code block} to the start of {@code block}.
      */
-    private void optimizeMovesAtBlockEnd(Block block) {
-        for (Block pred : block.getPredecessors()) {
+    private void optimizeMovesAtBlockEnd(AbstractBlock<?> block) {
+        for (AbstractBlock<?> pred : block.getPredecessors()) {
             if (pred == block) {
                 // currently we can't handle this correctly.
                 return;
@@ -118,10 +118,10 @@
         assert numPreds > 1 : "do not call otherwise";
 
         // setup a list with the LIR instructions of all predecessors
-        for (Block pred : block.getPredecessors()) {
+        for (AbstractBlock<?> pred : block.getPredecessors()) {
             assert pred != null;
-            assert ir.lir(pred) != null;
-            List<LIRInstruction> predInstructions = ir.lir(pred);
+            assert ir.getLIRforBlock(pred) != null;
+            List<LIRInstruction> predInstructions = ir.getLIRforBlock(pred);
 
             if (pred.getSuccessorCount() != 1) {
                 // this can happen with switch-statements where multiple edges are between
@@ -129,7 +129,7 @@
                 return;
             }
 
-            assert pred.getFirstSuccessor() == block : "invalid control flow";
+            assert pred.getSuccessors().iterator().next() == block : "invalid control flow";
             assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
 
             if (predInstructions.get(predInstructions.size() - 1).hasState()) {
@@ -158,7 +158,7 @@
             }
 
             // insert the instruction at the beginning of the current block
-            ir.lir(block).add(1, op);
+            ir.getLIRforBlock(block).add(1, op);
 
             // delete the instruction at the end of all predecessors
             for (int i = 0; i < numPreds; i++) {
@@ -173,12 +173,12 @@
      * {@code block} to the end of {@code block} just prior to the branch instruction ending
      * {@code block}.
      */
-    private void optimizeMovesAtBlockBegin(Block block) {
+    private void optimizeMovesAtBlockBegin(AbstractBlock<?> block) {
 
         edgeInstructionSeqences.clear();
         int numSux = block.getSuccessorCount();
 
-        List<LIRInstruction> instructions = ir.lir(block);
+        List<LIRInstruction> instructions = ir.getLIRforBlock(block);
 
         assert numSux == 2 : "method should not be called otherwise";
 
@@ -203,8 +203,8 @@
         int insertIdx = instructions.size() - 1;
 
         // setup a list with the lir-instructions of all successors
-        for (Block sux : block.getSuccessors()) {
-            List<LIRInstruction> suxInstructions = ir.lir(sux);
+        for (AbstractBlock<?> sux : block.getSuccessors()) {
+            List<LIRInstruction> suxInstructions = ir.getLIRforBlock(sux);
 
             assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
 
@@ -213,7 +213,7 @@
                 // the same blocks.
                 return;
             }
-            assert sux.getFirstPredecessor() == block : "invalid control flow";
+            assert sux.getPredecessors().iterator().next() == block : "invalid control flow";
 
             // ignore the label at the beginning of the block
             List<LIRInstruction> seq = suxInstructions.subList(1, suxInstructions.size());
@@ -238,7 +238,7 @@
             }
 
             // insert instruction at end of current block
-            ir.lir(block).add(insertIdx, op);
+            ir.getLIRforBlock(block).add(insertIdx, op);
             insertIdx++;
 
             // delete the instructions at the beginning of all successors
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Sun Mar 30 16:08:33 2014 +0200
@@ -35,17 +35,17 @@
  */
 public class LIR {
 
-    private final ControlFlowGraph cfg;
+    private final AbstractControlFlowGraph<?> cfg;
 
     /**
      * The linear-scan ordered list of blocks.
      */
-    private final List<Block> linearScanOrder;
+    private final List<? extends AbstractBlock<?>> linearScanOrder;
 
     /**
      * The order in which the code is emitted.
      */
-    private final List<Block> codeEmittingOrder;
+    private final List<? extends AbstractBlock<?>> codeEmittingOrder;
 
     private int firstVariableNumber;
 
@@ -65,14 +65,14 @@
     /**
      * Creates a new LIR instance for the specified compilation.
      */
-    public LIR(ControlFlowGraph cfg, List<Block> linearScanOrder, List<Block> codeEmittingOrder) {
+    public LIR(AbstractControlFlowGraph<?> cfg, List<? extends AbstractBlock<?>> linearScanOrder, List<? extends AbstractBlock<?>> codeEmittingOrder) {
         this.cfg = cfg;
         this.codeEmittingOrder = codeEmittingOrder;
         this.linearScanOrder = linearScanOrder;
         this.lirInstructions = new BlockMap<>(cfg);
     }
 
-    public ControlFlowGraph getControlFlowGraph() {
+    public AbstractControlFlowGraph<?> getControlFlowGraph() {
         return cfg;
     }
 
@@ -80,8 +80,8 @@
      * Determines if any instruction in the LIR has debug info associated with it.
      */
     public boolean hasDebugInfo() {
-        for (Block b : linearScanOrder()) {
-            for (LIRInstruction op : lir(b)) {
+        for (AbstractBlock<?> b : linearScanOrder()) {
+            for (LIRInstruction op : getLIRforBlock(b)) {
                 if (op.hasState()) {
                     return true;
                 }
@@ -94,12 +94,12 @@
         return spillMoveFactory;
     }
 
-    public List<LIRInstruction> lir(AbstractBlock<?> block) {
+    public List<LIRInstruction> getLIRforBlock(AbstractBlock<?> block) {
         return lirInstructions.get(block);
     }
 
-    public void setLir(Block block, List<LIRInstruction> list) {
-        assert lir(block) == null : "lir instruction list should only be initialized once";
+    public void setLIRforBlock(AbstractBlock<?> block, List<LIRInstruction> list) {
+        assert getLIRforBlock(block) == null : "lir instruction list should only be initialized once";
         lirInstructions.put(block, list);
     }
 
@@ -108,11 +108,11 @@
      * 
      * @return the blocks in linear scan order
      */
-    public List<Block> linearScanOrder() {
+    public List<? extends AbstractBlock<?>> linearScanOrder() {
         return linearScanOrder;
     }
 
-    public List<Block> codeEmittingOrder() {
+    public List<? extends AbstractBlock<?>> codeEmittingOrder() {
         return codeEmittingOrder;
     }
 
@@ -169,8 +169,8 @@
      */
     public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 3;
 
-    public static boolean verifyBlock(LIR lir, Block block) {
-        List<LIRInstruction> ops = lir.lir(block);
+    public static boolean verifyBlock(LIR lir, AbstractBlock<?> block) {
+        List<LIRInstruction> ops = lir.getLIRforBlock(block);
         if (ops.size() == 0) {
             return false;
         }
@@ -193,12 +193,12 @@
         return true;
     }
 
-    public static boolean verifyBlocks(LIR lir, List<Block> blocks) {
-        for (Block block : blocks) {
-            for (Block sux : block.getSuccessors()) {
+    public static boolean verifyBlocks(LIR lir, List<? extends AbstractBlock<?>> blocks) {
+        for (AbstractBlock<?> block : blocks) {
+            for (AbstractBlock<?> sux : block.getSuccessors()) {
                 assert blocks.contains(sux) : "missing successor from: " + block + "to: " + sux;
             }
-            for (Block pred : block.getPredecessors()) {
+            for (AbstractBlock<?> pred : block.getPredecessors()) {
                 assert blocks.contains(pred) : "missing predecessor from: " + block + "to: " + pred;
             }
             if (!verifyBlock(lir, block)) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Sun Mar 30 16:08:33 2014 +0200
@@ -46,11 +46,11 @@
     private final BitSet[] blockLiveOut;
     private final Object[] variableDefinitions;
 
-    private BitSet liveOutFor(Block block) {
+    private BitSet liveOutFor(AbstractBlock<?> block) {
         return blockLiveOut[block.getId()];
     }
 
-    private void setLiveOutFor(Block block, BitSet liveOut) {
+    private void setLiveOutFor(AbstractBlock<?> block, BitSet liveOut) {
         blockLiveOut[block.getId()] = liveOut;
     }
 
@@ -98,7 +98,7 @@
     private BitSet curVariablesLive;
     private Value[] curRegistersLive;
 
-    private Block curBlock;
+    private AbstractBlock<?> curBlock;
     private Object curInstruction;
     private BitSet curRegistersDefined;
 
@@ -120,7 +120,7 @@
 
         int maxRegisterNum = maxRegisterNum();
         curRegistersDefined = new BitSet();
-        for (Block block : lir.linearScanOrder()) {
+        for (AbstractBlock<?> block : lir.linearScanOrder()) {
             curBlock = block;
             curVariablesLive = new BitSet();
             curRegistersLive = new Value[maxRegisterNum];
@@ -129,14 +129,14 @@
                 curVariablesLive.or(liveOutFor(block.getDominator()));
             }
 
-            assert lir.lir(block).get(0) instanceof StandardOp.LabelOp : "block must start with label";
+            assert lir.getLIRforBlock(block).get(0) instanceof StandardOp.LabelOp : "block must start with label";
 
             if (block.getSuccessorCount() > 0) {
-                LIRInstruction last = lir.lir(block).get(lir.lir(block).size() - 1);
+                LIRInstruction last = lir.getLIRforBlock(block).get(lir.getLIRforBlock(block).size() - 1);
                 assert last instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
             }
 
-            for (LIRInstruction op : lir.lir(block)) {
+            for (LIRInstruction op : lir.getLIRforBlock(block)) {
                 curInstruction = op;
 
                 op.forEachInput(useProc);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Sun Mar 30 16:08:33 2014 +0200
@@ -73,7 +73,7 @@
     }
 
     public Label label() {
-        return ((StandardOp.LabelOp) lir.lir(getTargetBlock()).get(0)).getLabel();
+        return ((StandardOp.LabelOp) lir.getLIRforBlock(getTargetBlock()).get(0)).getLabel();
     }
 
     @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Sun Mar 30 16:08:33 2014 +0200
@@ -31,16 +31,16 @@
 public final class NullCheckOptimizer {
 
     public static void optimize(LIR ir, int implicitNullCheckLimit) {
-        List<Block> blocks = ir.codeEmittingOrder();
+        List<? extends AbstractBlock<?>> blocks = ir.codeEmittingOrder();
         NullCheckOptimizer.foldNullChecks(ir, blocks, implicitNullCheckLimit);
     }
 
     private NullCheckOptimizer() {
     }
 
-    private static void foldNullChecks(LIR ir, List<Block> blocks, int implicitNullCheckLimit) {
-        for (Block block : blocks) {
-            List<LIRInstruction> list = ir.lir(block);
+    private static void foldNullChecks(LIR ir, List<? extends AbstractBlock<?>> blocks, int implicitNullCheckLimit) {
+        for (AbstractBlock<?> block : blocks) {
+            List<LIRInstruction> list = ir.getLIRforBlock(block);
 
             if (!list.isEmpty()) {
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Sun Mar 30 16:08:33 2014 +0200
@@ -50,7 +50,7 @@
      * instruction. Note that because instructions can have multiple outputs it is not possible to
      * use the instruction id for value numbering. In addition, the result of merging at block
      * entries (= phi values) get unique value numbers.
-     * 
+     *
      * The value numbers also contain information if it is an object kind value or not: if the
      * number is negative it is an object kind value.
      */
@@ -79,7 +79,7 @@
         int entryValueNum;
     }
 
-    Map<Block, BlockData> blockData = new HashMap<>();
+    Map<AbstractBlock<?>, BlockData> blockData = new HashMap<>();
 
     Register[] callerSaveRegs;
 
@@ -134,7 +134,7 @@
 
     private void initBlockData(LIR lir) {
 
-        List<Block> blocks = lir.linearScanOrder();
+        List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
         numRegs = 0;
 
         int maxStackLocations = COMPLEXITY_LIMIT / blocks.size();
@@ -143,8 +143,8 @@
          * Search for relevant locations which can be optimized. These are register or stack slots
          * which occur as destinations of move instructions.
          */
-        for (Block block : blocks) {
-            List<LIRInstruction> instructions = lir.lir(block);
+        for (AbstractBlock<?> block : blocks) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
             for (LIRInstruction op : instructions) {
                 if (isEligibleMove(op)) {
                     Value dest = ((MoveOp) op).getResult();
@@ -168,7 +168,7 @@
          */
         int numLocations = numRegs + stackIndices.size();
         Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
-        for (Block block : blocks) {
+        for (AbstractBlock<?> block : blocks) {
             BlockData data = new BlockData(numLocations);
             blockData.put(block, data);
         }
@@ -176,100 +176,101 @@
 
     /**
      * Calculates the entry and exit states for all basic blocks.
-     * 
+     *
      * @return Returns true on success and false if the the control flow is too complex.
      */
     private boolean solveDataFlow(LIR lir) {
 
-        Indent indent = Debug.logAndIndent("solve data flow");
+        try (Indent indent = Debug.logAndIndent("solve data flow")) {
 
-        List<Block> blocks = lir.linearScanOrder();
+            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
 
-        int numIter = 0;
+            int numIter = 0;
 
-        /*
-         * Iterate until there are no more changes.
-         */
-        int currentValueNum = 1;
-        boolean firstRound = true;
-        boolean changed;
-        do {
-            changed = false;
-            Indent indent2 = indent.logAndIndent("new iteration");
+            /*
+             * Iterate until there are no more changes.
+             */
+            int currentValueNum = 1;
+            boolean firstRound = true;
+            boolean changed;
+            do {
+                changed = false;
+                try (Indent indent2 = Debug.logAndIndent("new iteration")) {
+
+                    for (AbstractBlock<?> block : blocks) {
 
-            for (Block block : blocks) {
+                        BlockData data = blockData.get(block);
+                        /*
+                         * Initialize the number for global value numbering for this block. It is
+                         * essential that the starting number for a block is consistent at all
+                         * iterations and also in eliminateMoves().
+                         */
+                        if (firstRound) {
+                            data.entryValueNum = currentValueNum;
+                        }
+                        int valueNum = data.entryValueNum;
+                        assert valueNum > 0;
+                        boolean newState = false;
 
-                BlockData data = blockData.get(block);
-                /*
-                 * Initialize the number for global value numbering for this block. It is essential
-                 * that the starting number for a block is consistent at all iterations and also in
-                 * eliminateMoves().
-                 */
-                if (firstRound) {
-                    data.entryValueNum = currentValueNum;
-                }
-                int valueNum = data.entryValueNum;
-                assert valueNum > 0;
-                boolean newState = false;
+                        if (block == blocks.get(0) || block.isExceptionEntry()) {
+                            /*
+                             * The entry block has undefined values. And also exception handler
+                             * blocks: the LinearScan can insert moves at the end of an exception
+                             * handler predecessor block (after the invoke, which throws the
+                             * exception), and in reality such moves are not in the control flow in
+                             * case of an exception. So we assume a save default for exception
+                             * handler blocks.
+                             */
+                            Debug.log("kill all values at entry of block %d", block.getId());
+                            clearValues(data.entryState, valueNum);
+                        } else {
+                            /*
+                             * Merge the states of predecessor blocks
+                             */
+                            for (AbstractBlock<?> predecessor : block.getPredecessors()) {
+                                BlockData predData = blockData.get(predecessor);
+                                newState |= mergeState(data.entryState, predData.exitState, valueNum);
+                            }
+                        }
+                        // Advance by the value numbers which are "consumed" by
+                        // clearValues and mergeState
+                        valueNum += data.entryState.length;
 
-                if (block == blocks.get(0) || block.isExceptionEntry()) {
+                        if (newState || firstRound) {
+                            try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) {
+
+                                /*
+                                 * Derive the exit state from the entry state by iterating through
+                                 * all instructions of the block.
+                                 */
+                                int[] iterState = data.exitState;
+                                copyState(iterState, data.entryState);
+                                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+                                for (LIRInstruction op : instructions) {
+                                    valueNum = updateState(iterState, op, valueNum);
+                                }
+                                changed = true;
+                            }
+                        }
+                        if (firstRound) {
+                            currentValueNum = valueNum;
+                        }
+                    }
+                    firstRound = false;
+                }
+                numIter++;
+
+                if (numIter > 5) {
                     /*
-                     * The entry block has undefined values. And also exception handler blocks: the
-                     * LinearScan can insert moves at the end of an exception handler predecessor
-                     * block (after the invoke, which throws the exception), and in reality such
-                     * moves are not in the control flow in case of an exception. So we assume a
-                     * save default for exception handler blocks.
-                     */
-                    indent2.log("kill all values at entry of block %d", block.getId());
-                    clearValues(data.entryState, valueNum);
-                } else {
-                    /*
-                     * Merge the states of predecessor blocks
+                     * This is _very_ seldom.
                      */
-                    for (Block predecessor : block.getPredecessors()) {
-                        BlockData predData = blockData.get(predecessor);
-                        newState |= mergeState(data.entryState, predData.exitState, valueNum);
-                    }
+                    return false;
                 }
-                // Advance by the value numbers which are "consumed" by clearValues and mergeState
-                valueNum += data.entryState.length;
-
-                if (newState || firstRound) {
-
-                    Indent indent3 = indent2.logAndIndent("update block %d", block.getId());
-
-                    /*
-                     * Derive the exit state from the entry state by iterating through all
-                     * instructions of the block.
-                     */
-                    int[] iterState = data.exitState;
-                    copyState(iterState, data.entryState);
-                    List<LIRInstruction> instructions = lir.lir(block);
 
-                    for (LIRInstruction op : instructions) {
-                        valueNum = updateState(iterState, op, valueNum);
-                    }
-                    changed = true;
-                    indent3.outdent();
-                }
-                if (firstRound) {
-                    currentValueNum = valueNum;
-                }
-            }
-            firstRound = false;
-            indent2.outdent();
-            numIter++;
+            } while (changed);
 
-            if (numIter > 5) {
-                /*
-                 * This is _very_ seldom.
-                 */
-                return false;
-            }
-
-        } while (changed);
-
-        indent.outdent();
+        }
 
         return true;
     }
@@ -279,47 +280,48 @@
      */
     private void eliminateMoves(LIR lir) {
 
-        Indent indent = Debug.logAndIndent("eliminate moves");
+        try (Indent indent = Debug.logAndIndent("eliminate moves")) {
+
+            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
 
-        List<Block> blocks = lir.linearScanOrder();
+            for (AbstractBlock<?> block : blocks) {
 
-        for (Block block : blocks) {
+                try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) {
 
-            Indent indent2 = indent.logAndIndent("eliminate moves in block %d", block.getId());
+                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                    BlockData data = blockData.get(block);
+                    boolean hasDead = false;
 
-            List<LIRInstruction> instructions = lir.lir(block);
-            BlockData data = blockData.get(block);
-            boolean hasDead = false;
+                    // Reuse the entry state for iteration, we don't need it later.
+                    int[] iterState = data.entryState;
 
-            // Reuse the entry state for iteration, we don't need it later.
-            int[] iterState = data.entryState;
+                    // Add the values which are "consumed" by clearValues and
+                    // mergeState in solveDataFlow
+                    int valueNum = data.entryValueNum + data.entryState.length;
 
-            // Add the values which are "consumed" by clearValues and mergeState in solveDataFlow
-            int valueNum = data.entryValueNum + data.entryState.length;
-
-            int numInsts = instructions.size();
-            for (int idx = 0; idx < numInsts; idx++) {
-                LIRInstruction op = instructions.get(idx);
-                if (isEligibleMove(op)) {
-                    MoveOp moveOp = (MoveOp) op;
-                    int sourceIdx = getStateIdx(moveOp.getInput());
-                    int destIdx = getStateIdx(moveOp.getResult());
-                    if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
-                        assert iterState[sourceIdx] != INIT_VALUE;
-                        indent2.log("delete move %s", op);
-                        instructions.set(idx, null);
-                        hasDead = true;
+                    int numInsts = instructions.size();
+                    for (int idx = 0; idx < numInsts; idx++) {
+                        LIRInstruction op = instructions.get(idx);
+                        if (isEligibleMove(op)) {
+                            MoveOp moveOp = (MoveOp) op;
+                            int sourceIdx = getStateIdx(moveOp.getInput());
+                            int destIdx = getStateIdx(moveOp.getResult());
+                            if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
+                                assert iterState[sourceIdx] != INIT_VALUE;
+                                Debug.log("delete move %s", op);
+                                instructions.set(idx, null);
+                                hasDead = true;
+                            }
+                        }
+                        // It doesn't harm if updateState is also called for a deleted move
+                        valueNum = updateState(iterState, op, valueNum);
+                    }
+                    if (hasDead) {
+                        instructions.removeAll(Collections.singleton(null));
                     }
                 }
-                // It doesn't harm if updateState is also called for a deleted move
-                valueNum = updateState(iterState, op, valueNum);
             }
-            if (hasDead) {
-                instructions.removeAll(Collections.singleton(null));
-            }
-            indent2.outdent();
         }
-        indent.outdent();
     }
 
     /**
@@ -338,7 +340,7 @@
                 if (sourceIdx >= 0 && destIdx >= 0) {
                     assert isObjectValue(state[sourceIdx]) || (moveOp.getInput().getKind() != Kind.Object) : "move op moves object but input is not defined as object";
                     state[destIdx] = state[sourceIdx];
-                    indent.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
+                    Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
                     return initValueNum;
                 }
             }
@@ -346,7 +348,7 @@
             int valueNum = initValueNum;
 
             if (op.destroysCallerSavedRegisters()) {
-                indent.log("kill all caller save regs");
+                Debug.log("kill all caller save regs");
 
                 for (Register reg : callerSaveRegs) {
                     if (reg.number < numRegs) {
@@ -375,7 +377,7 @@
                          * Assign a unique number to the output or temp location.
                          */
                         state[stateIdx] = encodeValueNum(opValueNum++, operand.getKind() == Kind.Object);
-                        indent.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
+                        Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
                     }
                     return operand;
                 }
@@ -395,12 +397,11 @@
                 /*
                  * All instructions with framestates (mostly method calls), may do garbage
                  * collection. GC will rewrite all object references which are live at this point.
-                 * So we can't rely on their values.
-                 * 
-                 * It would be sufficient to just kill all values which are referenced in the state
-                 * (or all values which are not), but for simplicity we kill all values.
+                 * So we can't rely on their values. It would be sufficient to just kill all values
+                 * which are referenced in the state (or all values which are not), but for
+                 * simplicity we kill all values.
                  */
-                indent.log("kill all object values");
+                Debug.log("kill all object values");
                 clearValuesOfKindObject(state, valueNum);
                 valueNum += state.length;
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Sun Mar 30 16:08:33 2014 +0200
@@ -182,20 +182,20 @@
         /**
          * The block in which this instruction is located.
          */
-        final Block block;
+        final AbstractBlock<?> block;
 
         /**
          * The block index of this instruction.
          */
         final int index;
 
-        public NoOp(Block block, int index) {
+        public NoOp(AbstractBlock<?> block, int index) {
             this.block = block;
             this.index = index;
         }
 
         public void replace(LIR lir, LIRInstruction replacement) {
-            lir.lir(block).set(index, replacement);
+            lir.getLIRforBlock(block).set(index, replacement);
         }
 
         @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -301,7 +301,7 @@
      */
     public boolean isSuccessorEdge(LabelRef edge) {
         assert lir != null;
-        List<Block> order = lir.codeEmittingOrder();
+        List<? extends AbstractBlock<?>> order = lir.codeEmittingOrder();
         assert order.get(currentBlockIndex) == edge.getSourceBlock();
         return currentBlockIndex < order.size() - 1 && order.get(currentBlockIndex + 1) == edge.getTargetBlock();
     }
@@ -315,7 +315,7 @@
         this.lir = lir;
         this.currentBlockIndex = 0;
         frameContext.enter(this);
-        for (Block b : lir.codeEmittingOrder()) {
+        for (AbstractBlock<?> b : lir.codeEmittingOrder()) {
             emitBlock(b);
             currentBlockIndex++;
         }
@@ -323,12 +323,12 @@
         this.currentBlockIndex = 0;
     }
 
-    private void emitBlock(Block block) {
+    private void emitBlock(AbstractBlock<?> block) {
         if (Debug.isDumpEnabled()) {
             blockComment(String.format("block B%d %s", block.getId(), block.getLoop()));
         }
 
-        for (LIRInstruction op : lir.lir(block)) {
+        for (LIRInstruction op : lir.getLIRforBlock(block)) {
             if (Debug.isDumpEnabled()) {
                 blockComment(String.format("%d %s", op.id(), op));
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Sun Mar 30 16:08:33 2014 +0200
@@ -63,7 +63,7 @@
     }
 
     private void findDerived(Collection<BasicInductionVariable> bivs) {
-        Queue<InductionVariable> scanQueue = new LinkedList<InductionVariable>(bivs);
+        Queue<InductionVariable> scanQueue = new LinkedList<>(bivs);
         while (!scanQueue.isEmpty()) {
             InductionVariable baseIv = scanQueue.remove();
             ValueNode baseIvNode = baseIv.valueNode();
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Sun Mar 30 16:08:33 2014 +0200
@@ -141,7 +141,7 @@
             BinaryNode result = BinaryNode.reassociate(binary, invariant);
             if (result != binary) {
                 if (Debug.isLogEnabled()) {
-                    Debug.log(MetaUtil.format("%H::%n", Debug.contextLookup(ResolvedJavaMethod.class)) + " : Reassociated %s into %s", binary, result);
+                    Debug.log("%s : Reassociated %s into %s", MetaUtil.format("%H::%n", graph.method()), binary, result);
                 }
                 graph.replaceFloating(binary, result);
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -84,6 +84,6 @@
             }
         }
         sb.append("]");
-        Debug.log(sb.toString());
+        Debug.log("%s", sb);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -128,7 +128,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         // nop
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,13 +30,11 @@
  * This node represents an unconditional explicit request for immediate deoptimization.
  * 
  * After this node, execution will continue using a fallback execution engine (such as an
- * interpreter) at the position described by the {@link #getDeoptimizationState() deoptimization
- * state}.
- * 
+ * interpreter) at the position described by the {@link #stateBefore() deoptimization state}.
  */
-public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode {
+public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode.DeoptBefore {
 
-    @Input private FrameState deoptState;
+    @Input private FrameState stateBefore;
 
     public AbstractDeoptimizeNode() {
         super(StampFactory.forVoid());
@@ -48,18 +46,14 @@
     }
 
     @Override
-    public FrameState getDeoptimizationState() {
-        return deoptState;
+    public FrameState stateBefore() {
+        return stateBefore;
     }
 
     @Override
-    public void setDeoptimizationState(FrameState f) {
-        updateUsages(deoptState, f);
-        deoptState = f;
-    }
-
-    public FrameState getState() {
-        return deoptState;
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
     }
 
     public abstract ValueNode getActionAndReason(MetaAccessProvider metaAccess);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -35,7 +35,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.visitEndNode(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -86,7 +86,7 @@
         FixedNode next = next();
         setNext(null);
         DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason));
-        deopt.setDeoptimizationState(getDeoptimizationState());
+        deopt.setStateBefore(stateBefore());
         IfNode ifNode;
         AbstractBeginNode noDeoptSuccessor;
         if (negated) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Sun Mar 30 16:08:33 2014 +0200
@@ -41,10 +41,6 @@
         stateAfter = x;
     }
 
-    public FrameState getState() {
-        return stateAfter();
-    }
-
     public boolean hasSideEffect() {
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -54,7 +54,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.visitBreakpointNode(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -54,7 +54,7 @@
     public abstract String targetName();
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         // nop
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -120,12 +120,12 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         assert ConstantNodeRecordsUsages : "LIR generator should generate constants per-usage";
-        if (gen.canInlineConstant(value) || onlyUsedInVirtualState()) {
+        if (gen.getLIRGeneratorTool().canInlineConstant(value) || onlyUsedInVirtualState()) {
             gen.setResult(this, value);
         } else {
-            gen.setResult(this, gen.emitMove(value));
+            gen.setResult(this, gen.getLIRGeneratorTool().emitMove(value));
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -62,8 +62,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.emitDeoptimize(gen.getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, this);
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, this);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,26 +24,22 @@
 
 import com.oracle.graal.nodes.type.*;
 
-public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode {
+public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode.DeoptBefore {
 
-    @Input(notDataflow = true) private FrameState deoptState;
+    @Input(notDataflow = true) private FrameState stateBefore;
 
     public DeoptimizingFixedWithNextNode(Stamp stamp) {
         super(stamp);
     }
 
     @Override
-    public FrameState getDeoptimizationState() {
-        return deoptState;
+    public FrameState stateBefore() {
+        return stateBefore;
     }
 
     @Override
-    public void setDeoptimizationState(FrameState f) {
-        updateUsages(deoptState, f);
-        deoptState = f;
-    }
-
-    public FrameState getState() {
-        return deoptState;
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -35,14 +35,46 @@
     boolean canDeoptimize();
 
     /**
-     * Gets the deoptimization information associated with this node if any.
+     * Interface for nodes that need a {@link FrameState} for deoptimizing to a point before their
+     * execution.
      */
-    FrameState getDeoptimizationState();
+    public interface DeoptBefore extends DeoptimizingNode {
+
+        /**
+         * Sets the {@link FrameState} describing the program state before the execution of this
+         * node.
+         */
+        void setStateBefore(FrameState state);
+
+        FrameState stateBefore();
+    }
+
+    /**
+     * Interface for nodes that need a {@link FrameState} for deoptimizing to a point after their
+     * execution.
+     */
+    public interface DeoptAfter extends DeoptimizingNode, StateSplit {
+    }
 
     /**
-     * Sets the deoptimization information associated with this node.
-     * 
-     * @param state the {@link FrameState} which represents the deoptimization information
+     * Interface for nodes that need a special {@link FrameState} for deoptimizing during their
+     * execution (e.g. {@link Invoke}).
      */
-    void setDeoptimizationState(FrameState state);
+    public interface DeoptDuring extends DeoptimizingNode, StateSplit {
+
+        FrameState stateDuring();
+
+        /**
+         * Sets the {@link FrameState} describing the program state during the execution of this
+         * node.
+         */
+        void setStateDuring(FrameState state);
+
+        /**
+         * Compute the {@link FrameState} describing the program state during the execution of this
+         * node from an input {@link FrameState} describing the program state after finishing the
+         * execution of this node.
+         */
+        void computeStateDuring(FrameState stateAfter);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -54,8 +54,8 @@
         return getSpeculation();
     }
 
-    public void generate(LIRGeneratorTool generator) {
-        generator.emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), this);
+    public void generate(NodeLIRGeneratorTool generator) {
+        generator.getLIRGeneratorTool().emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), this);
     }
 
     @Override
@@ -66,7 +66,7 @@
             DeoptimizeNode newDeopt = graph().add(
                             new DeoptimizeNode(tool.getMetaAccess().decodeDeoptAction(constant), tool.getMetaAccess().decodeDeoptReason(constant), tool.getMetaAccess().decodeDebugId(constant),
                                             speculationConstant));
-            newDeopt.setDeoptimizationState(getDeoptimizationState());
+            newDeopt.setStateBefore(stateBefore());
             return newDeopt;
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -38,7 +38,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         throw new GraalInternalError("OnStackReplacementNode should not survive");
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -52,7 +52,7 @@
                 }
 
                 DeoptimizeNode deopt = graph().add(new DeoptimizeNode(getAction(), getReason()));
-                deopt.setDeoptimizationState(getDeoptimizationState());
+                deopt.setStateBefore(stateBefore());
                 setNext(deopt);
             }
             this.replaceAtUsages(null);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Sun Mar 30 16:08:33 2014 +0200
@@ -254,12 +254,12 @@
                 copy.remove(copy.size() - 1);
             }
             ValueNode lastSlot = copy.get(copy.size() - 1);
-            assert lastSlot.kind().getStackKind() == popKind.getStackKind();
+            assert lastSlot.getKind().getStackKind() == popKind.getStackKind();
             copy.remove(copy.size() - 1);
         }
         for (ValueNode node : pushedValues) {
             copy.add(node);
-            if (node.kind() == Kind.Long || node.kind() == Kind.Double) {
+            if (node.getKind() == Kind.Long || node.getKind() == Kind.Double) {
                 copy.add(null);
             }
         }
@@ -404,7 +404,7 @@
         assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks");
         for (ValueNode value : values) {
             assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
-            assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != Kind.Void), "unexpected value: %s", value);
+            assertTrue(value == null || value instanceof VirtualObjectNode || (value.getKind() != Kind.Void), "unexpected value: %s", value);
         }
         return super.verify();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -53,8 +53,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
-        if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) {
+    public void generate(NodeLIRGeneratorTool generator) {
+        if (object.getKind() != Kind.Void && object.getKind() != Kind.Illegal) {
             generator.setResult(this, generator.operand(object));
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -99,7 +99,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (stamp() == StampFactory.illegal(object.kind())) {
+        if (stamp() == StampFactory.illegal(object.getKind())) {
             // The guard always fails
             return graph().add(new DeoptimizeNode(action, reason));
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -42,7 +43,7 @@
  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
  * of a comparison.
  */
-public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Successor private AbstractBeginNode trueSuccessor;
     @Successor private AbstractBeginNode falseSuccessor;
@@ -126,11 +127,16 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.emitIf(this);
     }
 
     @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        return gen.emitIfMemory(this, access);
+    }
+
+    @Override
     public boolean verify() {
         assertTrue(condition() != null, "missing condition");
         assertTrue(trueSuccessor() != null, "missing trueSuccessor");
@@ -356,10 +362,10 @@
                         boolean inverted = trueEnd == merge.forwardEndAt(1);
                         ValueNode trueValue = singlePhi.valueAt(inverted ? 1 : 0);
                         ValueNode falseValue = singlePhi.valueAt(inverted ? 0 : 1);
-                        if (trueValue.kind() != falseValue.kind()) {
+                        if (trueValue.getKind() != falseValue.getKind()) {
                             return false;
                         }
-                        if (trueValue.kind() != Kind.Int && trueValue.kind() != Kind.Long) {
+                        if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
                             return false;
                         }
                         ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
@@ -379,10 +385,10 @@
             ValueNode falseValue = falseEnd.result();
             ConditionalNode conditional = null;
             if (trueValue != null) {
-                if (trueValue.kind() != falseValue.kind()) {
+                if (trueValue.getKind() != falseValue.getKind()) {
                     return false;
                 }
-                if (trueValue.kind() != Kind.Int && trueValue.kind() != Kind.Long) {
+                if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
                     return false;
                 }
                 conditional = canonicalizeConditionalCascade(trueValue, falseValue);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -41,7 +41,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         generator.visitInfopointNode(this);
     }
 
@@ -51,7 +51,7 @@
 
     @Override
     public boolean verify() {
-        return getState() != null && super.verify();
+        return state != null && super.verify();
     }
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
-public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode, GuardedNode {
+public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, GuardedNode {
 
     FixedNode next();
 
@@ -38,10 +38,6 @@
 
     FixedNode asNode();
 
-    FrameState stateDuring();
-
-    FrameState stateAfter();
-
     Node predecessor();
 
     void intrinsify(Node node);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -38,7 +38,7 @@
 public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private CallTargetNode callTarget;
-    @Input private FrameState deoptState;
+    @Input private FrameState stateDuring;
     @Input private GuardingNode guard;
     private final int bci;
     private boolean polymorphic;
@@ -113,7 +113,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.emitInvoke(this);
     }
 
@@ -133,19 +133,8 @@
     }
 
     @Override
-    public FrameState stateDuring() {
-        FrameState stateAfter = stateAfter();
-        if (stateAfter == null) {
-            return null;
-        }
-        FrameState stateDuring = stateAfter.duplicateModified(bci(), stateAfter.rethrowException(), kind());
-        stateDuring.setDuringCall(true);
-        return stateDuring;
-    }
-
-    @Override
     public void intrinsify(Node node) {
-        assert !(node instanceof ValueNode) || (((ValueNode) node).kind() == Kind.Void) == (kind() == Kind.Void);
+        assert !(node instanceof ValueNode) || (((ValueNode) node).getKind() == Kind.Void) == (getKind() == Kind.Void);
         CallTargetNode call = callTarget;
         FrameState stateAfter = stateAfter();
         if (node instanceof StateSplit) {
@@ -174,18 +163,21 @@
     }
 
     @Override
-    public FrameState getDeoptimizationState() {
-        if (deoptState == null) {
-            FrameState stateDuring = stateDuring();
-            updateUsages(deoptState, stateDuring);
-            deoptState = stateDuring;
-        }
-        return deoptState;
+    public FrameState stateDuring() {
+        return stateDuring;
     }
 
     @Override
-    public void setDeoptimizationState(FrameState f) {
-        throw new IllegalStateException("Cannot set deoptimization state " + f + " for invoke " + this);
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    @Override
+    public void computeStateDuring(FrameState stateAfter) {
+        FrameState newStateDuring = stateAfter.duplicateModified(bci(), stateAfter.rethrowException(), getKind());
+        newStateDuring.setDuringCall(true);
+        setStateDuring(newStateDuring);
     }
 
     @Override
@@ -198,14 +190,4 @@
         updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
         this.guard = guard;
     }
-
-    @Override
-    public FrameState getState() {
-        if (deoptState != null) {
-            assert stateAfter() == null;
-            return deoptState;
-        } else {
-            return super.getState();
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,7 +39,7 @@
     @Successor private AbstractBeginNode next;
     @Successor private DispatchBeginNode exceptionEdge;
     @Input private CallTargetNode callTarget;
-    @Input private FrameState deoptState;
+    @Input private FrameState stateDuring;
     @Input private FrameState stateAfter;
     @Input private GuardingNode guard;
     private final int bci;
@@ -133,7 +133,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.emitInvoke(this);
     }
 
@@ -155,13 +155,6 @@
         return LocationIdentity.ANY_LOCATION;
     }
 
-    public FrameState stateDuring() {
-        FrameState tempStateAfter = stateAfter();
-        FrameState stateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), kind());
-        stateDuring.setDuringCall(true);
-        return stateDuring;
-    }
-
     @Override
     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
         Map<Object, Object> debugProperties = super.getDebugProperties(map);
@@ -177,7 +170,7 @@
 
     @Override
     public void intrinsify(Node node) {
-        assert !(node instanceof ValueNode) || (((ValueNode) node).kind() == Kind.Void) == (kind() == Kind.Void);
+        assert !(node instanceof ValueNode) || (((ValueNode) node).getKind() == Kind.Void) == (getKind() == Kind.Void);
         CallTargetNode call = callTarget;
         FrameState state = stateAfter();
         killExceptionEdge();
@@ -186,7 +179,7 @@
             stateSplit.setStateAfter(state);
         }
         if (node == null) {
-            assert kind() == Kind.Void && usages().isEmpty();
+            assert getKind() == Kind.Void && usages().isEmpty();
             graph().removeSplit(this, next());
         } else if (node instanceof ControlSinkNode) {
             this.replaceAtPredecessor(node);
@@ -219,18 +212,21 @@
     }
 
     @Override
-    public FrameState getDeoptimizationState() {
-        if (deoptState == null) {
-            FrameState stateDuring = stateDuring();
-            updateUsages(deoptState, stateDuring);
-            deoptState = stateDuring;
-        }
-        return deoptState;
+    public FrameState stateDuring() {
+        return stateDuring;
     }
 
     @Override
-    public void setDeoptimizationState(FrameState f) {
-        throw new IllegalStateException();
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
+    }
+
+    @Override
+    public void computeStateDuring(FrameState tempStateAfter) {
+        FrameState newStateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), getKind());
+        newStateDuring.setDuringCall(true);
+        setStateDuring(newStateDuring);
     }
 
     @Override
@@ -244,16 +240,6 @@
         this.guard = guard;
     }
 
-    @Override
-    public FrameState getState() {
-        if (deoptState != null) {
-            assert stateAfter() == null;
-            return deoptState;
-        } else {
-            return stateAfter();
-        }
-    }
-
     public MemoryCheckpoint asMemoryCheckpoint() {
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -68,7 +68,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         // nothing to do
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -98,7 +98,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         // Nothing to emit, since this is node is used for structural purposes only.
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.visitLoopEnd(this);
         super.generate(gen);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -42,7 +42,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -41,7 +41,7 @@
     @Input(notDataflow = true) private final NodeInputList<AbstractEndNode> ends = new NodeInputList<>(this);
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.visitMerge(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -62,8 +62,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
-        if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) {
+    public void generate(NodeLIRGeneratorTool generator) {
+        if (object.getKind() != Kind.Void && object.getKind() != Kind.Illegal) {
             generator.setResult(this, generator.operand(object));
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -57,7 +57,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.visitReturn(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -35,7 +35,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.visitSafepointNode(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,7 +39,7 @@
 
     public UnwindNode(ValueNode exception) {
         super(StampFactory.forVoid());
-        assert exception == null || exception.kind() == Kind.Object;
+        assert exception == null || exception.getKind() == Kind.Object;
         this.exception = exception;
     }
 
@@ -49,7 +49,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.emitUnwind(gen.operand(exception()));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.getLIRGeneratorTool().emitUnwind(gen.operand(exception()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -31,7 +31,7 @@
  * This class represents a value within the graph, including local variables, phis, and all other
  * instructions.
  */
-public abstract class ValueNode extends ScheduledNode implements StampProvider {
+public abstract class ValueNode extends ScheduledNode implements StampProvider, KindInterface {
 
     /**
      * The kind of this value. This is {@link Kind#Void} for instructions that produce no value.
@@ -79,7 +79,7 @@
         return false;
     }
 
-    public final Kind kind() {
+    public final Kind getKind() {
         return stamp().getStackKind();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Sun Mar 30 16:08:33 2014 +0200
@@ -32,7 +32,7 @@
 public class ValueNodeUtil {
 
     public static ValueNode assertKind(Kind kind, ValueNode x) {
-        assert x != null && x.kind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind());
+        assert x != null && x.getKind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
         return x;
     }
 
@@ -45,27 +45,27 @@
     }
 
     public static ValueNode assertLong(ValueNode x) {
-        assert x != null && (x.kind() == Kind.Long);
+        assert x != null && (x.getKind() == Kind.Long);
         return x;
     }
 
     public static ValueNode assertInt(ValueNode x) {
-        assert x != null && (x.kind() == Kind.Int);
+        assert x != null && (x.getKind() == Kind.Int);
         return x;
     }
 
     public static ValueNode assertFloat(ValueNode x) {
-        assert x != null && (x.kind() == Kind.Float);
+        assert x != null && (x.getKind() == Kind.Float);
         return x;
     }
 
     public static ValueNode assertObject(ValueNode x) {
-        assert x != null && (x.kind() == Kind.Object);
+        assert x != null && (x.getKind() == Kind.Object);
         return x;
     }
 
     public static ValueNode assertDouble(ValueNode x) {
-        assert x != null && (x.kind() == Kind.Double);
+        assert x != null && (x.getKind() == Kind.Double);
         return x;
     }
 
@@ -87,14 +87,14 @@
     /**
      * Converts a given instruction to a value string. The representation of an node as a value is
      * formed by concatenating the {@linkplain com.oracle.graal.api.meta.Kind#getTypeChar character}
-     * denoting its {@linkplain ValueNode#kind kind} and its id. For example, {@code "i13"}.
+     * denoting its {@linkplain ValueNode#getKind kind} and its id. For example, {@code "i13"}.
      * 
      * @param value the instruction to convert to a value string. If {@code value == null}, then "-"
      *            is returned.
      * @return the instruction representation as a string
      */
     public static String valueString(ValueNode value) {
-        return (value == null) ? "-" : ("" + value.kind().getTypeChar() + value.toString(Verbosity.Id));
+        return (value == null) ? "-" : ("" + value.getKind().getTypeChar() + value.toString(Verbosity.Id));
     }
 
     public static ValueNode asNode(MemoryNode node) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -80,7 +81,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitAnd(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitAnd(gen.operand(x()), gen.operand(y())));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitAndMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,7 +29,7 @@
 /**
  * The {@code LogicNode} class definition.
  */
-public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     /**
      * Constructs a new logic operation node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /* TODO (thomaswue/gdub) For high-level optimization purpose the compare node should be a boolean *value* (it is currently only a helper node)
@@ -34,7 +35,7 @@
  * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
  * into variants that do not materialize the value (CompareIf, CompareGuard...)
  */
-public abstract class CompareNode extends LogicNode implements Canonicalizable, LIRLowerable {
+public abstract class CompareNode extends LogicNode implements Canonicalizable, LIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
@@ -54,7 +55,7 @@
      * @param y the instruction that produces the second input to this instruction
      */
     public CompareNode(ValueNode x, ValueNode y) {
-        assert x != null && y != null && x.kind() == y.kind();
+        assert x != null && y != null && x.getKind() == y.getKind();
         this.x = x;
         this.y = y;
     }
@@ -74,7 +75,7 @@
     public abstract boolean unorderedIsTrue();
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
     }
 
     private LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
@@ -169,27 +170,37 @@
     }
 
     public static CompareNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
-        assert x.kind() == y.kind();
+        assert x.getKind() == y.getKind();
         assert condition.isCanonical() : "condition is not canonical: " + condition;
-        assert !x.kind().isNumericFloat();
+        assert !x.getKind().isNumericFloat();
 
         CompareNode comparison;
         if (condition == Condition.EQ) {
-            if (x.kind() == Kind.Object) {
+            if (x.getKind() == Kind.Object) {
                 comparison = new ObjectEqualsNode(x, y);
             } else {
-                assert x.kind().isNumericInteger();
+                assert x.getKind().isNumericInteger();
                 comparison = new IntegerEqualsNode(x, y);
             }
         } else if (condition == Condition.LT) {
-            assert x.kind().isNumericInteger();
+            assert x.getKind().isNumericInteger();
             comparison = new IntegerLessThanNode(x, y);
         } else {
             assert condition == Condition.BT;
-            assert x.kind().isNumericInteger();
+            assert x.getKind().isNumericInteger();
             comparison = new IntegerBelowThanNode(x, y);
         }
 
         return graph.unique(comparison);
     }
+
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        return false;
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
+        return super.verify();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -109,7 +109,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         generator.emitConditional(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -64,7 +65,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value op1 = gen.operand(x());
         Value op2 = gen.operand(y());
         if (!y().isConstant() && !livesLonger(this, y(), gen)) {
@@ -72,15 +73,24 @@
             op1 = op2;
             op2 = op;
         }
-        gen.setResult(this, gen.emitAdd(op1, op2));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitAdd(op1, op2));
     }
 
-    public static boolean livesLonger(ValueNode after, ValueNode value, ArithmeticLIRGenerator gen) {
+    public static boolean livesLonger(ValueNode after, ValueNode value, NodeLIRGeneratorTool gen) {
         for (Node usage : value.usages()) {
-            if (usage != after && usage instanceof ValueNode && gen.operand(((ValueNode) usage)) != null) {
+            if (usage != after && usage instanceof ValueNode && gen.hasOperand(((ValueNode) usage))) {
                 return true;
             }
         }
         return false;
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitAddMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     private final boolean isStrictFP;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -33,7 +34,7 @@
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
+public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     public enum FloatConvert {
         F2I, D2I, F2L, D2L, I2F, L2F, D2F, I2D, L2D, F2D;
@@ -191,7 +192,21 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitFloatConvert(op, gen.operand(getInput())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitFloatConvert(op, gen.operand(getInput())));
+    }
+
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Kind kind = access.nullCheckLocation().getValueKind();
+        if (kind != kind.getStackKind()) {
+            // Doesn't work for subword operations
+            return false;
+        }
+
+        Value result = gen.emitFloatConvertMemory(getOp(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -56,7 +57,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()), null));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), null));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitDivMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -59,7 +60,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value op1 = gen.operand(x());
         Value op2 = gen.operand(y());
         if (!y().isConstant() && !FloatAddNode.livesLonger(this, y(), gen)) {
@@ -67,6 +68,15 @@
             op1 = op2;
             op2 = op;
         }
-        gen.setResult(this, gen.emitMul(op1, op2));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitMul(op1, op2));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitMulMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -56,7 +57,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()), null));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), null));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitRemMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -75,7 +76,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitSub(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitSub(gen.operand(x()), gen.operand(y())));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitSubMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -78,9 +79,6 @@
             if (reassociated != this) {
                 return reassociated;
             }
-            if (c < 0) {
-                return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph()));
-            }
         }
         if (x() instanceof NegateNode) {
             return IntegerArithmeticNode.sub(graph(), y(), ((NegateNode) x()).x());
@@ -91,7 +89,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value op1 = gen.operand(x());
         assert op1 != null : x() + ", this=" + this;
         Value op2 = gen.operand(y());
@@ -100,6 +98,15 @@
             op1 = op2;
             op2 = op;
         }
-        gen.setResult(this, gen.emitAdd(op1, op2));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitAdd(op1, op2));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitAddMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
         super(stamp, x, y);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,8 +39,8 @@
      */
     public IntegerBelowThanNode(ValueNode x, ValueNode y) {
         super(x, y);
-        assert !x.kind().isNumericFloat() && x.kind() != Kind.Object;
-        assert !y.kind().isNumericFloat() && y.kind() != Kind.Object;
+        assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
+        assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -31,7 +31,7 @@
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable {
 
     private final int resultBits;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -106,8 +106,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()), this));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,8 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
 public final class IntegerEqualsNode extends CompareNode {
@@ -38,8 +40,8 @@
      */
     public IntegerEqualsNode(ValueNode x, ValueNode y) {
         super(x, y);
-        assert !x.kind().isNumericFloat() && x.kind() != Kind.Object;
-        assert !y.kind().isNumericFloat() && y.kind() != Kind.Object;
+        assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
+        assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
 
     @Override
@@ -58,7 +60,7 @@
             ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x();
             ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y();
 
-            if (normalizeNode.x().kind() == Kind.Double || normalizeNode.x().kind() == Kind.Float) {
+            if (normalizeNode.x().getKind() == Kind.Double || normalizeNode.x().getKind() == Kind.Float) {
                 return graph().unique(new FloatEqualsNode(a, b));
             } else {
                 return graph().unique(new IntegerEqualsNode(a, b));
@@ -69,17 +71,67 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
+        if (GraphUtil.unproxify(x()) == GraphUtil.unproxify(y())) {
             return LogicConstantNode.tautology(graph());
         } else if (x().stamp().alwaysDistinct(y().stamp())) {
             return LogicConstantNode.contradiction(graph());
         }
 
-        if (x() instanceof AndNode && y().isConstant() && y().asConstant().asLong() == 0) {
-            return graph().unique(new IntegerTestNode(((AndNode) x()).x(), ((AndNode) x()).y()));
-        } else if (y() instanceof AndNode && x().isConstant() && x().asConstant().asLong() == 0) {
-            return graph().unique(new IntegerTestNode(((AndNode) y()).x(), ((AndNode) y()).y()));
+        ValueNode result = canonicalizeSymmetric(x(), y());
+        if (result != null) {
+            return result;
         }
+
+        result = canonicalizeSymmetric(y(), x());
+        if (result != null) {
+            return result;
+        }
+
         return super.canonical(tool);
     }
+
+    private ValueNode canonicalizeSymmetric(ValueNode x, ValueNode y) {
+        if (y.isConstant() && y.asConstant().asLong() == 0) {
+            if (x instanceof AndNode) {
+                return graph().unique(new IntegerTestNode(((AndNode) x).x(), ((AndNode) x).y()));
+            } else if (x instanceof LeftShiftNode) {
+                LeftShiftNode shift = (LeftShiftNode) x;
+                if (shift.y().isConstant()) {
+                    int mask = shift.getShiftAmountMask();
+                    int amount = shift.y().asConstant().asInt() & mask;
+                    if (shift.x().getKind() == Kind.Int) {
+                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 >>> amount, graph())));
+                    } else {
+                        assert shift.x().getKind() == Kind.Long;
+                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L >>> amount, graph())));
+                    }
+                }
+            } else if (x instanceof RightShiftNode) {
+                RightShiftNode shift = (RightShiftNode) x;
+                if (shift.y().isConstant() && ((IntegerStamp) shift.x().stamp()).isPositive()) {
+                    int mask = shift.getShiftAmountMask();
+                    int amount = shift.y().asConstant().asInt() & mask;
+                    if (shift.x().getKind() == Kind.Int) {
+                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
+                    } else {
+                        assert shift.x().getKind() == Kind.Long;
+                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                    }
+                }
+            } else if (x instanceof UnsignedRightShiftNode) {
+                UnsignedRightShiftNode shift = (UnsignedRightShiftNode) x;
+                if (shift.y().isConstant()) {
+                    int mask = shift.getShiftAmountMask();
+                    int amount = shift.y().asConstant().asInt() & mask;
+                    if (shift.x().getKind() == Kind.Int) {
+                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
+                    } else {
+                        assert shift.x().getKind() == Kind.Long;
+                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                    }
+                }
+            }
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,8 +39,8 @@
      */
     public IntegerLessThanNode(ValueNode x, ValueNode y) {
         super(x, y);
-        assert !x.kind().isNumericFloat() && x.kind() != Kind.Object;
-        assert !y.kind().isNumericFloat() && y.kind() != Kind.Object;
+        assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
+        assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
 
     @Override
@@ -60,7 +60,7 @@
             ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x();
             ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y();
 
-            if (normalizeNode.x().kind() == Kind.Double || normalizeNode.x().kind() == Kind.Float) {
+            if (normalizeNode.x().getKind() == Kind.Double || normalizeNode.x().getKind() == Kind.Float) {
                 return graph().unique(new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess));
             } else {
                 return graph().unique(new IntegerLessThanNode(a, b));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -74,7 +75,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value op1 = gen.operand(x());
         Value op2 = gen.operand(y());
         if (!y().isConstant() && !FloatAddNode.livesLonger(this, y(), gen)) {
@@ -82,6 +83,15 @@
             op1 = op2;
             op2 = op;
         }
-        gen.setResult(this, gen.emitMul(op1, op2));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitMul(op1, op2));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitMulMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -61,8 +61,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()), this));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -97,7 +98,9 @@
             if (reassociated != this) {
                 return reassociated;
             }
-            if (c < 0) {
+            if (c < 0 || ((IntegerStamp) StampFactory.forKind(y().getKind())).contains(-c)) {
+                // Adding a negative is more friendly to the backend since adds are
+                // commutative, so prefer add when it fits.
                 return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph()));
             }
         } else if (x().isConstant()) {
@@ -114,7 +117,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitSub(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitSub(gen.operand(x()), gen.operand(y())));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitSubMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -33,7 +34,7 @@
  * expression "(x &amp; y) == 0", meaning that it will return true if (and only if) no bit is set in
  * both x and y.
  */
-public class IntegerTestNode extends LogicNode implements Canonicalizable, LIRLowerable {
+public class IntegerTestNode extends LogicNode implements Canonicalizable, LIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
@@ -59,7 +60,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
     }
 
     @Override
@@ -76,4 +77,9 @@
         }
         return this;
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -50,7 +50,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         // Nothing to do.
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -44,10 +44,10 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Int) {
+        if (getKind() == Kind.Int) {
             return Constant.forInt(inputs[0].asInt() << inputs[1].asInt());
         } else {
-            assert kind() == Kind.Long;
+            assert getKind() == Kind.Long;
             return Constant.forLong(inputs[0].asLong() << inputs[1].asLong());
         }
     }
@@ -59,13 +59,7 @@
         } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
-            int mask;
-            if (kind() == Kind.Int) {
-                mask = 0x1f;
-            } else {
-                assert kind() == Kind.Long;
-                mask = 0x3f;
-            }
+            int mask = getShiftAmountMask();
             amount &= mask;
             if (amount == 0) {
                 return x();
@@ -77,14 +71,14 @@
                     if (other instanceof LeftShiftNode) {
                         int total = amount + otherAmount;
                         if (total != (total & mask)) {
-                            return ConstantNode.forIntegerKind(kind(), 0, graph());
+                            return ConstantNode.forIntegerKind(getKind(), 0, graph());
                         }
                         return graph().unique(new LeftShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
                     } else if ((other instanceof RightShiftNode || other instanceof UnsignedRightShiftNode) && otherAmount == amount) {
-                        if (kind() == Kind.Long) {
+                        if (getKind() == Kind.Long) {
                             return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L << amount, graph())));
                         } else {
-                            assert kind() == Kind.Int;
+                            assert getKind() == Kind.Int;
                             return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 << amount, graph())));
                         }
                     }
@@ -98,7 +92,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitShl(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitShl(gen.operand(x()), gen.operand(y())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -109,7 +110,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitNarrow(gen.operand(getInput()), getResultBits()));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitNarrow(gen.operand(getInput()), getResultBits()));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitNarrowMemory(getResultBits(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -88,7 +88,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitNegate(gen.operand(x())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitNegate(gen.operand(x())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -73,7 +73,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitNot(gen.operand(x())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitNot(gen.operand(x())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -40,8 +40,8 @@
      */
     public ObjectEqualsNode(ValueNode x, ValueNode y) {
         super(x, y);
-        assert x.kind() == Kind.Object;
-        assert y.kind() == Kind.Object;
+        assert x.getKind() == Kind.Object;
+        assert y.getKind() == Kind.Object;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -72,7 +73,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitOr(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitOr(gen.operand(x()), gen.operand(y())));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitOrMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -34,7 +35,7 @@
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
+public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Input private ValueNode value;
 
@@ -101,9 +102,18 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        PlatformKind kind = gen.getPlatformKind(stamp());
-        gen.setResult(this, gen.emitReinterpret(kind, gen.operand(value())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        PlatformKind kind = gen.getLIRGeneratorTool().getPlatformKind(stamp());
+        gen.setResult(this, gen.getLIRGeneratorTool().emitReinterpret(kind, gen.operand(value())));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitReinterpretMemory(stamp(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,10 +39,10 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Int) {
+        if (getKind() == Kind.Int) {
             return Constant.forInt(inputs[0].asInt() >> inputs[1].asInt());
         } else {
-            assert kind() == Kind.Long;
+            assert getKind() == Kind.Long;
             return Constant.forLong(inputs[0].asLong() >> inputs[1].asLong());
         }
     }
@@ -57,13 +57,7 @@
         } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
-            int mask;
-            if (kind() == Kind.Int) {
-                mask = 0x1f;
-            } else {
-                assert kind() == Kind.Long;
-                mask = 0x3f;
-            }
+            int mask = getShiftAmountMask();
             amount &= mask;
             if (amount == 0) {
                 return x();
@@ -79,10 +73,10 @@
                             IntegerStamp istamp = (IntegerStamp) other.x().stamp();
 
                             if (istamp.isPositive()) {
-                                return ConstantNode.forIntegerKind(kind(), 0, graph());
+                                return ConstantNode.forIntegerKind(getKind(), 0, graph());
                             }
                             if (istamp.isStrictlyNegative()) {
-                                return ConstantNode.forIntegerKind(kind(), -1L, graph());
+                                return ConstantNode.forIntegerKind(getKind(), -1L, graph());
                             }
 
                             /*
@@ -104,7 +98,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitShr(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitShr(gen.operand(x()), gen.operand(y())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -40,4 +41,15 @@
     public ShiftNode(Stamp stamp, ValueNode x, ValueNode s) {
         super(stamp, x, s);
     }
+
+    public int getShiftAmountMask() {
+        int mask;
+        if (getKind() == Kind.Int) {
+            mask = 0x1f;
+        } else {
+            assert getKind() == Kind.Long;
+            mask = 0x3f;
+        }
+        return mask;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -104,7 +105,17 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitSignExtend(gen.operand(getInput()), getInputBits(), getResultBits()));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitSignExtend(gen.operand(getInput()), getInputBits(), getResultBits()));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        assert !access.nullCheckLocation().getValueKind().isUnsigned() : "can't sign extend unsigned value";
+        Value result = gen.emitSignExtendMemory(access, access.nullCheckLocation().getValueKind().getBitCount(), getResultBits());
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -71,8 +71,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitUDiv(gen.operand(x()), gen.operand(y()), this));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(x()), gen.operand(y()), this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -70,8 +70,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitURem(gen.operand(x()), gen.operand(y()), this));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(x()), gen.operand(y()), this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -44,10 +44,10 @@
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        if (kind() == Kind.Int) {
+        if (getKind() == Kind.Int) {
             return Constant.forInt(inputs[0].asInt() >>> inputs[1].asInt());
         } else {
-            assert kind() == Kind.Long;
+            assert getKind() == Kind.Long;
             return Constant.forLong(inputs[0].asLong() >>> inputs[1].asLong());
         }
     }
@@ -59,13 +59,7 @@
         } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
-            int mask;
-            if (kind() == Kind.Int) {
-                mask = 0x1f;
-            } else {
-                assert kind() == Kind.Long;
-                mask = 0x3f;
-            }
+            int mask = getShiftAmountMask();
             amount &= mask;
             if (amount == 0) {
                 return x();
@@ -77,14 +71,14 @@
                     if (other instanceof UnsignedRightShiftNode) {
                         int total = amount + otherAmount;
                         if (total != (total & mask)) {
-                            return ConstantNode.forIntegerKind(kind(), 0, graph());
+                            return ConstantNode.forIntegerKind(getKind(), 0, graph());
                         }
                         return graph().unique(new UnsignedRightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph())));
                     } else if (other instanceof LeftShiftNode && otherAmount == amount) {
-                        if (kind() == Kind.Long) {
+                        if (getKind() == Kind.Long) {
                             return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L >>> amount, graph())));
                         } else {
-                            assert kind() == Kind.Int;
+                            assert getKind() == Kind.Int;
                             return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 >>> amount, graph())));
                         }
                     }
@@ -98,7 +92,7 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitUShr(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitUShr(gen.operand(x()), gen.operand(y())));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -71,7 +72,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitXor(gen.operand(x()), gen.operand(y())));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitXor(gen.operand(x()), gen.operand(y())));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitXorMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -84,7 +85,16 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitZeroExtend(gen.operand(getInput()), getInputBits(), getResultBits()));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitZeroExtend(gen.operand(getInput()), getInputBits(), getResultBits()));
+    }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,14 +22,12 @@
  */
 package com.oracle.graal.nodes.cfg;
 
-import com.oracle.graal.nodes.*;
+import java.util.*;
 
 public interface AbstractBlock<T extends AbstractBlock<?>> {
 
     int getId();
 
-    AbstractBeginNode getBeginNode();
-
     Loop getLoop();
 
     int getLoopDepth();
@@ -40,11 +38,11 @@
 
     boolean isExceptionEntry();
 
-    Iterable<T> getPredecessors();
+    List<T> getPredecessors();
 
     int getPredecessorCount();
 
-    Iterable<T> getSuccessors();
+    List<T> getSuccessors();
 
     int getSuccessorCount();
 
@@ -55,4 +53,6 @@
     boolean isAligned();
 
     void setAlign(boolean align);
+
+    T getDominator();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlockBase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.cfg;
+
+import java.util.*;
+
+public abstract class AbstractBlockBase<T extends AbstractBlock<T>> implements AbstractBlock<T> {
+
+    protected int id;
+
+    protected List<T> predecessors;
+    protected List<T> successors;
+
+    protected T dominator;
+
+    private boolean align;
+    private int linearScanNumber;
+
+    protected AbstractBlockBase() {
+        this.id = ControlFlowGraph.BLOCK_ID_INITIAL;
+        this.linearScanNumber = -1;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public List<T> getPredecessors() {
+        return predecessors;
+    }
+
+    public List<T> getSuccessors() {
+        return successors;
+    }
+
+    public T getDominator() {
+        return dominator;
+    }
+
+    @Override
+    public String toString() {
+        return "B" + id;
+    }
+
+    public int getPredecessorCount() {
+        return getPredecessors().size();
+    }
+
+    public int getSuccessorCount() {
+        return getSuccessors().size();
+    }
+
+    public int getLinearScanNumber() {
+        return linearScanNumber;
+    }
+
+    public void setLinearScanNumber(int linearScanNumber) {
+        this.linearScanNumber = linearScanNumber;
+    }
+
+    public boolean isAligned() {
+        return align;
+    }
+
+    public void setAlign(boolean align) {
+        this.align = align;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractControlFlowGraph.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.cfg;
+
+public interface AbstractControlFlowGraph<T extends AbstractBlock<T>> {
+
+    T[] getBlocks();
+
+    Loop[] getLoops();
+
+    T getStartBlock();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,34 +27,18 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 
-public final class Block implements AbstractBlock<Block> {
+public final class Block extends AbstractBlockBase<Block> {
 
     protected final AbstractBeginNode beginNode;
 
-    protected int id;
-
     protected FixedNode endNode;
     protected Loop loop;
 
-    protected List<Block> predecessors;
-    protected List<Block> successors;
-
-    protected Block dominator;
     protected List<Block> dominated;
     protected Block postdominator;
 
-    private boolean align;
-    private int linearScanNumber;
-
     protected Block(AbstractBeginNode node) {
         this.beginNode = node;
-
-        this.id = ControlFlowGraph.BLOCK_ID_INITIAL;
-        this.linearScanNumber = -1;
-    }
-
-    public int getId() {
-        return id;
     }
 
     public AbstractBeginNode getBeginNode() {
@@ -89,22 +73,10 @@
         return predecessors.get(0);
     }
 
-    public List<Block> getPredecessors() {
-        return predecessors;
-    }
-
     public Block getFirstSuccessor() {
         return successors.get(0);
     }
 
-    public List<Block> getSuccessors() {
-        return successors;
-    }
-
-    public Block getDominator() {
-        return dominator;
-    }
-
     public Block getEarliestPostDominated() {
         Block b = this;
         while (true) {
@@ -187,14 +159,6 @@
         return "B" + id;
     }
 
-    public int getPredecessorCount() {
-        return getPredecessors().size();
-    }
-
-    public int getSuccessorCount() {
-        return getSuccessors().size();
-    }
-
     public boolean dominates(Block block) {
         return block.isDominatedBy(this);
     }
@@ -209,19 +173,4 @@
         return dominator.isDominatedBy(block);
     }
 
-    public int getLinearScanNumber() {
-        return linearScanNumber;
-    }
-
-    public void setLinearScanNumber(int linearScanNumber) {
-        this.linearScanNumber = linearScanNumber;
-    }
-
-    public boolean isAligned() {
-        return align;
-    }
-
-    public void setAlign(boolean align) {
-        this.align = align;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlockMap.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlockMap.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,7 +27,7 @@
     private final T[] data;
 
     @SuppressWarnings("unchecked")
-    public BlockMap(ControlFlowGraph cfg) {
+    public BlockMap(AbstractControlFlowGraph<?> cfg) {
         data = (T[]) new Object[cfg.getBlocks().length];
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlocksToDoubles.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,73 @@
+/*
+ * 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.cfg;
+
+import java.util.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+
+public class BlocksToDoubles {
+
+    private final IdentityHashMap<AbstractBlock<?>, Double> nodeProbabilities;
+
+    public BlocksToDoubles(int numberOfNodes) {
+        this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes);
+    }
+
+    public void put(AbstractBlock<?> n, double value) {
+        assert value >= 0.0 : value;
+        nodeProbabilities.put(n, value);
+    }
+
+    public boolean contains(AbstractBlock<?> n) {
+        return nodeProbabilities.containsKey(n);
+    }
+
+    public double get(AbstractBlock<?> n) {
+        Double value = nodeProbabilities.get(n);
+        assert value != null;
+        return value;
+    }
+
+    public static BlocksToDoubles createFromNodeProbability(NodesToDoubles nodeProbabilities, ControlFlowGraph cfg) {
+        BlocksToDoubles blockProbabilities = new BlocksToDoubles(cfg.getBlocks().length);
+        for (Block block : cfg.getBlocks()) {
+            blockProbabilities.put(block, nodeProbabilities.get(block.getBeginNode()));
+        }
+        assert verify(nodeProbabilities, cfg, blockProbabilities) : "Probabilities differ for nodes in the same block.";
+        return blockProbabilities;
+    }
+
+    private static boolean verify(NodesToDoubles nodeProbabilities, ControlFlowGraph cfg, BlocksToDoubles blockProbabilities) {
+        for (Block b : cfg.getBlocks()) {
+            double p = blockProbabilities.get(b);
+            for (FixedNode n : b.getNodes()) {
+                if (nodeProbabilities.get(n) != p) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Sun Mar 30 16:08:33 2014 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
-public class ControlFlowGraph {
+public class ControlFlowGraph implements AbstractControlFlowGraph<Block> {
 
     public final StructuredGraph graph;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -107,7 +107,7 @@
     }
 
     @Override
-    public Value generateAddress(LIRGeneratorTool gen, Value base) {
+    public Value generateAddress(NodeLIRGeneratorTool gen, Value base) {
         Value xAddr = getX().generateAddress(gen, base);
         return getY().generateAddress(gen, xAddr);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -48,7 +48,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value addr = getLocation().generateAddress(gen, gen.operand(getObject()));
         gen.setResult(this, addr);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -65,7 +65,7 @@
     }
 
     @Override
-    public Value generateAddress(LIRGeneratorTool gen, Value base) {
-        return gen.emitAddress(base, getDisplacement(), Value.ILLEGAL, 0);
+    public Value generateAddress(NodeLIRGeneratorTool gen, Value base) {
+        return gen.getLIRGeneratorTool().emitAddress(base, getDisplacement(), Value.ILLEGAL, 0);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -43,6 +43,11 @@
         return object;
     }
 
+    protected void setObject(ValueNode x) {
+        updateUsages(object, x);
+        object = x;
+    }
+
     public LocationNode location() {
         return (LocationNode) location;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -49,7 +49,7 @@
     public static native <T> T getObject(Object object);
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         generator.setResult(this, generator.operand(object));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -60,13 +60,16 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value address = location().generateAddress(gen, gen.operand(object()));
-        gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(location().getValueKind(), address, this));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
+        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
+            return graph().unique(new FloatingReadNode(((PiNode) object()).getOriginalValue(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType(), isCompressible()));
+        }
         return ReadNode.canonicalizeRead(this, location(), object(), tool, isCompressible());
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -35,11 +35,11 @@
  * Node for a {@linkplain ForeignCallDescriptor foreign} call.
  */
 @NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}")
-public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint.Multi {
+public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode.DeoptDuring, MemoryCheckpoint.Multi {
 
     @Input private final NodeInputList<ValueNode> arguments;
     private final ForeignCallsProvider foreignCalls;
-    @Input private FrameState deoptState;
+    @Input private FrameState stateDuring;
 
     private final ForeignCallDescriptor descriptor;
 
@@ -82,7 +82,7 @@
         return foreignCalls.getKilledLocations(descriptor);
     }
 
-    protected Value[] operands(LIRGeneratorTool gen) {
+    protected Value[] operands(NodeLIRGeneratorTool gen) {
         Value[] operands = new Value[arguments.size()];
         for (int i = 0; i < operands.length; i++) {
             operands[i] = gen.operand(arguments.get(i));
@@ -91,42 +91,35 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(descriptor);
+    public void generate(NodeLIRGeneratorTool gen) {
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor);
         Value[] operands = operands(gen);
-        Value result = gen.emitForeignCall(linkage, this, operands);
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, operands);
         if (result != null) {
             gen.setResult(this, result);
         }
     }
 
     @Override
-    public FrameState getDeoptimizationState() {
-        if (deoptState != null) {
-            return deoptState;
-        } else if (stateAfter() != null && canDeoptimize()) {
-            FrameState stateDuring = stateAfter();
-            if ((stateDuring.stackSize() > 0 && stateDuring.stackAt(stateDuring.stackSize() - 1) == this) || (stateDuring.stackSize() > 1 && stateDuring.stackAt(stateDuring.stackSize() - 2) == this)) {
-                stateDuring = stateDuring.duplicateModified(stateDuring.bci, stateDuring.rethrowException(), this.kind());
-            }
-            setDeoptimizationState(stateDuring);
-            return stateDuring;
-        }
-        return null;
+    public FrameState stateDuring() {
+        return stateDuring;
     }
 
     @Override
-    public void setDeoptimizationState(FrameState f) {
-        updateUsages(deoptState, f);
-        assert deoptState == null && canDeoptimize() : "shouldn't assign deoptState to " + this;
-        deoptState = f;
+    public void setStateDuring(FrameState stateDuring) {
+        updateUsages(this.stateDuring, stateDuring);
+        this.stateDuring = stateDuring;
     }
 
     @Override
-    public void setStateAfter(FrameState x) {
-        if (hasSideEffect()) {
-            super.setStateAfter(x);
+    public void computeStateDuring(FrameState stateAfter) {
+        FrameState newStateDuring;
+        if ((stateAfter.stackSize() > 0 && stateAfter.stackAt(stateAfter.stackSize() - 1) == this) || (stateAfter.stackSize() > 1 && stateAfter.stackAt(stateAfter.stackSize() - 2) == this)) {
+            newStateDuring = stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), this.getKind());
+        } else {
+            newStateDuring = stateAfter;
         }
+        setStateDuring(newStateDuring);
     }
 
     @Override
@@ -141,14 +134,4 @@
     public boolean canDeoptimize() {
         return foreignCalls.canDeoptimize(descriptor);
     }
-
-    @Override
-    public FrameState getState() {
-        if (deoptState != null) {
-            assert stateAfter() == null;
-            return deoptState;
-        } else {
-            return super.getState();
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -96,7 +96,7 @@
     }
 
     @Override
-    public Value generateAddress(LIRGeneratorTool gen, Value base) {
-        return gen.emitAddress(base, displacement, gen.operand(getIndex()), getIndexScaling());
+    public Value generateAddress(NodeLIRGeneratorTool gen, Value base) {
+        return gen.getLIRGeneratorTool().emitAddress(base, displacement, gen.operand(getIndex()), getIndexScaling());
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.emitSwitch(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -56,9 +56,9 @@
     public abstract LocationIdentity getLocationIdentity();
 
     @Override
-    public final void generate(LIRGeneratorTool generator) {
+    public final void generate(NodeLIRGeneratorTool generator) {
         // nothing to do...
     }
 
-    public abstract Value generateAddress(LIRGeneratorTool gen, Value base);
+    public abstract Value generateAddress(NodeLIRGeneratorTool gen, Value base);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -56,8 +56,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
-        generator.emitMembar(barriers);
+    public void generate(NodeLIRGeneratorTool generator) {
+        generator.getLIRGeneratorTool().emitMembar(barriers);
     }
 
     public MemoryCheckpoint asMemoryCheckpoint() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -40,7 +40,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         generator.emitNullCheck(object, this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -53,13 +53,16 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value address = location().generateAddress(gen, gen.operand(object()));
-        gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(location().getValueKind(), address, this));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
+        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
+            return graph().add(new ReadNode(((PiNode) object()).getOriginalValue(), location(), stamp(), getGuard(), getBarrierType(), isCompressible()));
+        }
         return canonicalizeRead(this, location(), object(), tool, isCompressible());
     }
 
@@ -71,8 +74,14 @@
     public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool, boolean compressible) {
         MetaAccessProvider metaAccess = tool.getMetaAccess();
         if (read.usages().isEmpty()) {
-            // Read without usages can be safely removed.
-            return null;
+            GuardingNode guard = ((Access) read).getGuard();
+            if (guard != null && !(guard instanceof FixedNode)) {
+                // The guard is necessary even if the read goes away.
+                return read.graph().add(new ValueAnchorNode((ValueNode) guard));
+            } else {
+                // Read without usages or guard can be safely removed.
+                return null;
+            }
         }
         if (tool.canonicalizeReads()) {
             if (metaAccess != null && object != null && object.isConstant()) {
@@ -80,7 +89,7 @@
                                 location instanceof ConstantLocationNode) {
                     long displacement = ((ConstantLocationNode) location).getDisplacement();
                     Kind kind = location.getValueKind();
-                    if (object.kind() == Kind.Object) {
+                    if (object.getKind() == Kind.Object) {
                         Object base = object.asConstant().asObject();
                         if (base != null) {
                             Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, base, displacement, compressible);
@@ -88,7 +97,7 @@
                                 return ConstantNode.forConstant(constant, metaAccess, read.graph());
                             }
                         }
-                    } else if (object.kind().isNumericInteger()) {
+                    } else if (object.getKind().isNumericInteger()) {
                         long base = object.asConstant().asLong();
                         if (base != 0L) {
                             Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, null, base + displacement, compressible);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -100,7 +100,7 @@
     }
 
     @Override
-    public Value generateAddress(LIRGeneratorTool gen, Value base) {
+    public Value generateAddress(NodeLIRGeneratorTool gen, Value base) {
         throw new GraalInternalError("locationIdentity must be a constant so that this node can be canonicalized: " + locationIdentity);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -47,7 +47,7 @@
      */
     public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
         super(StampFactory.forVoid());
-        assert value.kind() == Kind.Int || value.kind() == Kind.Long || value.kind() == Kind.Object : value.kind() + " key not supported by SwitchNode";
+        assert value.getKind() == Kind.Int || value.getKind() == Kind.Long || value.getKind() == Kind.Object : value.getKind() + " key not supported by SwitchNode";
         assert keySuccessors.length == keyProbabilities.length;
         this.successors = new NodeSuccessorList<>(this, successors);
         this.value = value;
@@ -67,7 +67,7 @@
     }
 
     protected boolean assertValues() {
-        Kind kind = value.kind();
+        Kind kind = value.getKind();
         for (int i = 0; i < keyCount(); i++) {
             Constant key = keyAt(i);
             assert key.getKind() == kind;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -60,7 +60,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        assert kind() == Kind.Object && object.kind() == Kind.Object;
+        assert getKind() == Kind.Object && object.getKind() == Kind.Object;
 
         ObjectStamp my = (ObjectStamp) stamp();
         ObjectStamp other = (ObjectStamp) object.stamp();
@@ -94,8 +94,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
-        assert kind() == Kind.Object && object.kind() == Kind.Object;
+    public void generate(NodeLIRGeneratorTool generator) {
+        assert getKind() == Kind.Object && object.getKind() == Kind.Object;
         /*
          * The LIR only cares about the kind of an operand, not the actual type of an object. So we
          * do not have to introduce a new operand.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -65,7 +65,7 @@
                 int entryIndex = state.getVirtualObject().entryIndexForOffset(offset);
                 if (entryIndex != -1) {
                     ValueNode entry = state.getEntry(entryIndex);
-                    if (entry.kind() == kind() || state.getVirtualObject().entryKind(entryIndex) == accessKind()) {
+                    if (entry.getKind() == getKind() || state.getVirtualObject().entryKind(entryIndex) == accessKind()) {
                         tool.replaceWith(entry);
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -79,7 +79,7 @@
                 if (entryIndex != -1) {
                     Kind entryKind = state.getVirtualObject().entryKind(entryIndex);
                     ValueNode entry = state.getEntry(entryIndex);
-                    if (entry.kind() == value.kind() || entryKind == accessKind()) {
+                    if (entry.getKind() == value.getKind() || entryKind == accessKind()) {
                         tool.setVirtualEntry(state, entryIndex, value(), true);
                         tool.delete();
                     } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,16 +22,17 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
  */
-public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Virtualizable, GuardingNode {
+public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, GuardingNode {
 
     @Input private ValueNode anchored;
 
@@ -41,7 +42,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         // Nothing to emit, since this node is used for structural purposes only.
     }
 
@@ -50,19 +51,40 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (anchored != null && !anchored.isConstant() && !(anchored instanceof FixedNode)) {
-            // Found entry that needs this anchor.
-            return this;
+    public void simplify(SimplifierTool tool) {
+        while (next() instanceof ValueAnchorNode) {
+            ValueAnchorNode nextAnchor = (ValueAnchorNode) next();
+            if (nextAnchor.anchored == anchored || nextAnchor.anchored == null) {
+                // two anchors for the same anchored -> coalesce
+                // nothing anchored on the next anchor -> coalesce
+                nextAnchor.replaceAtUsages(this);
+                GraphUtil.removeFixedWithUnusedInputs(nextAnchor);
+            } else {
+                break;
+            }
+        }
+        if (usages().isEmpty() && next() instanceof FixedAccessNode) {
+            FixedAccessNode next = (FixedAccessNode) next();
+            if (next.getGuard() == anchored) {
+                GraphUtil.removeFixedWithUnusedInputs(this);
+                return;
+            } else if (next.getGuard() == null && anchored instanceof GuardNode && ((GuardNode) anchored).condition() instanceof IsNullNode) {
+                // coalesce null check guards into subsequent read/write
+                next.setGuard((GuardingNode) anchored);
+                tool.addToWorkList(next());
+                return;
+            }
         }
 
-        if (usages().isNotEmpty()) {
-            // A not uses this anchor => anchor is necessary.
-            return this;
+        if (anchored != null && (anchored.isConstant() || anchored instanceof FixedNode)) {
+            // anchoring fixed nodes and constants is useless
+            removeAnchoredNode();
         }
 
-        // Anchor is not necessary any more => remove.
-        return null;
+        if (anchored == null && usages().isEmpty()) {
+            // anchor is not necessary any more => remove.
+            GraphUtil.removeFixedWithUnusedInputs(this);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.LocationNode.Location;
 import com.oracle.graal.nodes.spi.*;
@@ -33,7 +34,7 @@
 /**
  * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}.
  */
-public final class WriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Virtualizable {
+public final class WriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Simplifiable, Virtualizable {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
@@ -45,16 +46,6 @@
         return stateAfter;
     }
 
-    @Override
-    public FrameState getState() {
-        if (stateAfter != null) {
-            assert super.getState() == null;
-            return stateAfter;
-        } else {
-            return super.getState();
-        }
-    }
-
     public void setStateAfter(FrameState x) {
         assert x == null || x.isAlive() : "frame state must be in a graph";
         updateUsages(stateAfter, x);
@@ -89,17 +80,24 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value address = location().generateAddress(gen, gen.operand(object()));
         // It's possible a constant was forced for other usages so inspect the value directly and
         // use a constant if it can be directly stored.
         Value v;
-        if (value().isConstant() && gen.canStoreConstant(value().asConstant(), isCompressible())) {
+        if (value().isConstant() && gen.getLIRGeneratorTool().canStoreConstant(value().asConstant(), isCompressible())) {
             v = value().asConstant();
         } else {
             v = gen.operand(value());
         }
-        gen.emitStore(location().getValueKind(), address, v, this);
+        gen.getLIRGeneratorTool().emitStore(location().getValueKind(), address, v, this);
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
+            setObject(((PiNode) object()).getOriginalValue());
+        }
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -73,7 +73,7 @@
                 return;
             }
         }
-        for (Node usage : usages().snapshot()) {
+        for (Node usage : usages().distinct().snapshot()) {
             List<Node> snapshot = usage.inputs().snapshot();
             graph().removeFixed((FixedWithNextNode) usage);
             for (Node input : snapshot) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,9 +33,9 @@
  * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and
  * throws a {@link BailoutException} instead during graph building.
  */
-public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode {
+public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode.DeoptBefore, DeoptimizingNode.DeoptAfter {
 
-    @Input private FrameState deoptState;
+    @Input private FrameState stateBefore;
     @Input private ValueNode object;
     @Input private MonitorIdNode monitorId;
 
@@ -44,21 +44,14 @@
         return true;
     }
 
-    @Override
-    public FrameState getDeoptimizationState() {
-        return deoptState;
+    public FrameState stateBefore() {
+        return stateBefore;
     }
 
     @Override
-    public void setDeoptimizationState(FrameState f) {
-        updateUsages(deoptState, f);
-        deoptState = f;
-    }
-
-    @Override
-    public FrameState getState() {
-        assert deoptState == null || stateAfter() == null;
-        return deoptState == null ? stateAfter() : deoptState;
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
     }
 
     public ValueNode object() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -46,7 +46,7 @@
     public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) {
         this.mirror = mirror;
         this.object = object;
-        assert mirror.kind() == Kind.Object : mirror.kind();
+        assert mirror.getKind() == Kind.Object : mirror.getKind();
         assert ObjectStamp.isExactType(mirror);
         assert ObjectStamp.typeOrNull(mirror).getName().equals("Ljava/lang/Class;");
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -61,7 +61,7 @@
 
     public LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType, boolean compressible) {
         super(object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType, compressible);
-        assert expectedValue.kind() == newValue.kind();
+        assert expectedValue.getKind() == newValue.getKind();
         this.expectedValue = expectedValue;
         this.newValue = newValue;
     }
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.visitCompareAndSwap(this, location().generateAddress(gen, gen.operand(object())));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -126,15 +126,28 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (!isStatic()) {
+        if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
+            // attempt to devirtualize the call
+
+            // check for trivial cases (e.g. final methods, nonvirtual methods)
+            if (targetMethod.canBeStaticallyBound()) {
+                invokeKind = InvokeKind.Special;
+                return this;
+            }
+
+            // check if the exact type of the receiver can be determined
             ValueNode receiver = receiver();
-            if (receiver != null && ObjectStamp.isExactType(receiver) && ObjectStamp.typeOrNull(receiver) != null) {
-                if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
-                    ResolvedJavaMethod method = ObjectStamp.typeOrNull(receiver).resolveMethod(targetMethod);
-                    if (method != null) {
-                        invokeKind = InvokeKind.Special;
-                        targetMethod = method;
-                    }
+            ResolvedJavaType exact = targetMethod.getDeclaringClass().asExactType();
+            if (exact == null && ObjectStamp.isExactType(receiver)) {
+                exact = ObjectStamp.typeOrNull(receiver);
+            }
+            if (exact != null) {
+                // either the holder class is exact, or the receiver object has an exact type
+                ResolvedJavaMethod exactMethod = exact.resolveMethod(targetMethod);
+                if (exactMethod != null) {
+                    invokeKind = InvokeKind.Special;
+                    targetMethod = exactMethod;
+                    return this;
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -49,7 +49,7 @@
         this.lockDepth = lockDepth;
     }
 
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         // nothing to do
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -34,7 +34,7 @@
  * This node is used to perform the finalizer registration at the end of the java.lang.Object
  * constructor.
  */
-public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode {
+public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
 
     public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
 
@@ -51,9 +51,9 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(REGISTER_FINALIZER);
-        gen.emitForeignCall(linkage, this, gen.operand(object()));
+    public void generate(NodeLIRGeneratorTool gen) {
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(REGISTER_FINALIZER);
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(object()));
     }
 
     @Override
@@ -96,17 +96,6 @@
         return true;
     }
 
-    @Override
-    public FrameState getDeoptimizationState() {
-        return deoptState;
-    }
-
-    @Override
-    public void setDeoptimizationState(FrameState f) {
-        updateUsages(deoptState, f);
-        deoptState = f;
-    }
-
     @SuppressWarnings("unused")
     @NodeIntrinsic
     public static void register(Object thisObj) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,7 +29,7 @@
 import com.oracle.graal.graph.GraalInternalError;
 import com.oracle.graal.graph.NodeInputList;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.LIRGeneratorTool;
+import com.oracle.graal.nodes.spi.NodeLIRGeneratorTool;
 import com.oracle.graal.nodes.spi.Lowerable;
 import com.oracle.graal.nodes.spi.LoweringTool;
 
@@ -78,7 +78,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         throw GraalInternalError.shouldNotReachHere("should have replaced itself");
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -61,7 +61,7 @@
 
     @Override
     public boolean isSorted() {
-        Kind kind = value().kind();
+        Kind kind = value().getKind();
         if (kind.isNumericInteger()) {
             Constant lastKey = null;
             for (int i = 0; i < keyCount(); i++) {
@@ -92,7 +92,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         gen.emitSwitch(this);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -28,15 +28,12 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * This interface can be used to generate LIR for arithmetic operations (@see
- * ArithmeticLIRLowerable).
+ * This interface can be used to generate LIR for arithmetic operations.
  */
 public interface ArithmeticLIRGenerator {
-
-    Value operand(ValueNode object);
-
-    Value setResult(ValueNode x, Value operand);
-
+    /**
+     * TODO remove reference to {@link Stamp}.
+     */
     PlatformKind getPlatformKind(Stamp stamp);
 
     Value emitNegate(Value input);
@@ -47,12 +44,24 @@
 
     Value emitMul(Value a, Value b);
 
+    /**
+     * TODO remove {@link DeoptimizeNode}.
+     */
     Value emitDiv(Value a, Value b, DeoptimizingNode deopting);
 
+    /**
+     * TODO remove {@link DeoptimizeNode}.
+     */
     Value emitRem(Value a, Value b, DeoptimizingNode deopting);
 
+    /**
+     * TODO remove {@link DeoptimizeNode}.
+     */
     Value emitUDiv(Value a, Value b, DeoptimizingNode deopting);
 
+    /**
+     * TODO remove {@link DeoptimizeNode}.
+     */
     Value emitURem(Value a, Value b, DeoptimizingNode deopting);
 
     Value emitNot(Value input);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,5 +26,5 @@
 
 public interface ArithmeticLIRLowerable extends ArithmeticOperation {
 
-    void generate(ArithmeticLIRGenerator gen);
+    void generate(NodeLIRGeneratorTool gen);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Sun Mar 30 16:08:33 2014 +0200
@@ -25,9 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
 
 public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
 
@@ -39,6 +37,14 @@
 
     ForeignCallsProvider getForeignCalls();
 
+    Value emitLoad(Kind kind, Value address, Access access);
+
+    void emitStore(Kind kind, Value address, Value input, Access access);
+
+    void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting);
+
+    Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args);
+
     /**
      * Checks whether the supplied constant can be used without loading it into a register for most
      * operations, i.e., for commonly used arithmetic, logical, and comparison operations.
@@ -59,47 +65,20 @@
 
     void emitMove(AllocatableValue dst, Value src);
 
+    /**
+     * Emits an op that loads the address of some raw data.
+     * 
+     * @param dst the variable into which the address is loaded
+     * @param data the data to be installed with the generated code
+     */
+    void emitData(AllocatableValue dst, byte[] data);
+
     Value emitAddress(Value base, long displacement, Value index, int scale);
 
     Value emitAddress(StackSlot slot);
 
-    Value emitLoad(Kind kind, Value address, Access access);
-
-    void emitStore(Kind kind, Value address, Value input, Access access);
-
     void emitMembar(int barriers);
 
-    void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting);
-
-    void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
-
-    Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args);
-
-    void emitIf(IfNode i);
-
-    void emitConditional(ConditionalNode i);
-
-    void emitSwitch(SwitchNode i);
-
-    void emitInvoke(Invoke i);
-
-    // Handling of block-end nodes still needs to be unified in the LIRGenerator.
-    void visitMerge(MergeNode i);
-
-    void visitEndNode(AbstractEndNode i);
-
-    void visitLoopEnd(LoopEndNode i);
-
-    void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address);
-
-    // These methods define the contract a runtime specific backend must provide.
-
-    void visitReturn(ReturnNode i);
-
-    void visitSafepointNode(SafepointNode i);
-
-    void visitBreakpointNode(BreakpointNode i);
-
     void emitUnwind(Value operand);
 
     /**
@@ -108,5 +87,7 @@
      */
     void beforeRegisterAllocation();
 
-    void visitInfopointNode(InfopointNode i);
+    void emitIncomingValues(Value[] params);
+
+    void emitReturn(Value input);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRLowerable.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRLowerable.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,5 +24,5 @@
 
 public interface LIRLowerable {
 
-    void generate(LIRGeneratorTool generator);
+    void generate(NodeLIRGeneratorTool generator);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Marks nodes which may be lowered in combination with a memory operation.
+ */
+public interface MemoryArithmeticLIRLowerable {
+
+    /**
+     * Attempt to generate a memory form of a node operation. On platforms that support it this will
+     * be called when the merging is safe.
+     * 
+     * @param gen
+     * @param access the memory input which can potentially merge into this operation.
+     * @return null if it's not possible to emit a memory form of this operation. A non-null value
+     *         will be set as the operand of this node.
+     */
+    boolean generate(MemoryArithmeticLIRLowerer gen, Access access);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * This interface can be used to generate LIR for arithmetic operations where one of the operations
+ * is load (@see ArithmeticLIRLowerable).
+ */
+public interface MemoryArithmeticLIRLowerer {
+
+    Value setResult(ValueNode x, Value operand);
+
+    Value emitAddMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitMulMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitSubMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitDivMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitRemMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitXorMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitOrMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitAndMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitReinterpretMemory(Stamp stamp, Access access);
+
+    Value emitSignExtendMemory(Access access, int fromBits, int toBits);
+
+    Value emitNarrowMemory(int resultBits, Access access);
+
+    Value emitZeroExtendMemory(int inputBits, int resultBits, Access access);
+
+    Value emitFloatConvertMemory(FloatConvert op, Access access);
+
+    boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred);
+
+    boolean emitIfMemory(IfNode ifNode, Access access);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRGeneratorTool.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+
+public interface NodeLIRGeneratorTool extends NodeMappableLIRGenerator {
+
+    void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
+
+    void emitIf(IfNode i);
+
+    void emitConditional(ConditionalNode i);
+
+    void emitSwitch(SwitchNode i);
+
+    void emitInvoke(Invoke i);
+
+    // Handling of block-end nodes still needs to be unified in the LIRGenerator.
+    void visitMerge(MergeNode i);
+
+    void visitEndNode(AbstractEndNode i);
+
+    void visitLoopEnd(LoopEndNode i);
+
+    void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address);
+
+    // These methods define the contract a runtime specific backend must provide.
+
+    void visitReturn(ReturnNode i);
+
+    void visitSafepointNode(SafepointNode i);
+
+    void visitBreakpointNode(BreakpointNode i);
+
+    void visitInfopointNode(InfopointNode i);
+
+    LIRGeneratorTool getLIRGeneratorTool();
+
+    void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, double probability);
+
+    Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments);
+
+    MemoryArithmeticLIRLowerer getMemoryLowerer();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.nodes.spi;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+public interface NodeMappableLIRGenerator {
+
+    Value operand(ValueNode object);
+
+    boolean hasOperand(ValueNode object);
+
+    Value setResult(ValueNode x, Value operand);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,25 +24,11 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import static com.oracle.graal.nodes.StructuredGraph.GuardsStage.*;
 
 /**
  * Interface for nodes which have {@link FrameState} nodes as input.
- * <p>
- * Some node can implement more than one interface which requires a {@link FrameState} input (e.g.
- * {@link DeoptimizingNode} and {@link StateSplit}). Since this interface can only report one
- * FrameState, such nodes must ensure they only maintain a link to at most one FrameState at all
- * times. Usually this is not a problem because FrameStates are associated only with StateSplit
- * nodes before the {@link #AFTER_FSA} stage and only with DeoptimizingNodes after.
- * 
  */
 public interface NodeWithState {
-    /**
-     * Gets the {@link FrameState} associated with this node.
-     * 
-     * @return the {@link FrameState} associated with this node
-     */
-    FrameState getState();
 
     Node asNode();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Sun Mar 30 16:08:33 2014 +0200
@@ -462,4 +462,41 @@
         }
         return v;
     }
+
+    /**
+     * Compute the stamp resulting from the unsigned comparison being true.
+     * 
+     * @return null if it's can't be true or it nothing useful can be encoded.
+     */
+    public static Stamp unsignedCompare(Stamp stamp, Stamp stamp2) {
+        IntegerStamp x = (IntegerStamp) stamp;
+        IntegerStamp y = (IntegerStamp) stamp2;
+        if (x == x.unrestricted() && y == y.unrestricted()) {
+            // Don't know anything.
+            return null;
+        }
+        // c <| n, where c is a constant and n is known to be positive.
+        if (x.lowerBound() == x.upperBound()) {
+            if (y.isPositive()) {
+                if (x.lowerBound() == (1 << x.getBits()) - 1) {
+                    // Constant is MAX_VALUE which must fail.
+                    return null;
+                }
+                if (x.lowerBound() <= y.lowerBound()) {
+                    // Test will fail. Return illegalStamp instead?
+                    return null;
+                }
+                // If the test succeeds then this proves that n is at greater than c so the bounds
+                // are [c+1..-n.upperBound)].
+                return StampFactory.forInteger(x.getBits(), false, x.lowerBound() + 1, y.upperBound());
+            }
+            return null;
+        }
+        // n <| c, where c is a strictly positive constant
+        if (y.lowerBound() == y.upperBound() && y.isStrictlyPositive()) {
+            // The test proves that n is positive and less than c, [0..c-1]
+            return StampFactory.forInteger(y.getBits(), false, 0, y.lowerBound() - 1);
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         // nothing to do...
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -91,7 +91,7 @@
     public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks);
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         // nothing to do...
     }
 }
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Sun Mar 30 16:08:33 2014 +0200
@@ -45,10 +45,14 @@
  * }
  * </pre>
  */
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
 @SupportedAnnotationTypes({"com.oracle.graal.options.Option"})
 public class OptionProcessor extends AbstractProcessor {
 
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
     private final Set<Element> processed = new HashSet<>();
 
     private void processElement(Element element, OptionsInfo info) {
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java	Sun Mar 30 16:08:33 2014 +0200
@@ -38,7 +38,7 @@
      * <p>
      * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
      * used:
-     * 
+     *
      * <pre>
      * try (OverrideScope s = OptionValue.override(myOption, myValue) {
      *     // code that depends on myOption == myValue
@@ -65,7 +65,7 @@
      * <p>
      * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
      * used:
-     * 
+     *
      * <pre>
      * Map<OptionValue, Object> overrides = new HashMap<>();
      * overrides.put(myOption1, myValue1);
@@ -96,13 +96,13 @@
      * <p>
      * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
      * used:
-     * 
+     *
      * <pre>
      * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) {
      *     // code that depends on myOption == myValue
      * }
      * </pre>
-     * 
+     *
      * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]}
      */
     public static OverrideScope override(Object... overrides) {
@@ -221,14 +221,14 @@
 
     /**
      * Gets the values of this option including overridden values.
-     * 
+     *
      * @param c the collection to which the values are added. If null, one is allocated.
      * @return the collection to which the values were added in order from most overridden to
      *         current value
      */
     @SuppressWarnings("unchecked")
     public Collection<T> getValues(Collection<T> c) {
-        Collection<T> values = c == null ? new ArrayList<T>() : c;
+        Collection<T> values = c == null ? new ArrayList<>() : c;
         if (!(this instanceof StableOptionValue)) {
             OverrideScope overrideScope = overrideScopes.get();
             if (overrideScope != null) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -273,10 +273,10 @@
 // @formatter:on
         private boolean performReplacement(final Node node, Node canonical) {
             if (canonical == node) {
-                Debug.log("Canonicalizer: work on %s", node);
+                Debug.log("Canonicalizer: work on %1s", node);
                 return false;
             } else {
-                Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
+                Debug.log("Canonicalizer: replacing %1s with %1s", node, canonical);
                 METRIC_CANONICALIZED_NODES.increment();
                 StructuredGraph graph = (StructuredGraph) node.graph();
                 if (node instanceof FloatingNode) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
@@ -63,7 +64,40 @@
     @Override
     protected void run(StructuredGraph inputGraph) {
         graph = inputGraph;
-        new ConditionalElimination(graph.start(), new State()).apply();
+        try (Scope s = Debug.scope("ConditionalElimination")) {
+            new ConditionalElimination(graph.start(), new State()).apply();
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    /**
+     * Type information about a {@code value} that it produced by a {@code guard}. Usage of the
+     * stamp information requires adopting the guard. Usually this means replacing an existing guard
+     * with this guard.
+     */
+    static class GuardedStamp {
+        private final ValueNode value;
+        private final Stamp stamp;
+        private final GuardNode guard;
+
+        GuardedStamp(ValueNode value, Stamp stamp, GuardNode guard) {
+            this.value = value;
+            this.stamp = stamp;
+            this.guard = guard;
+        }
+
+        public Stamp getStamp() {
+            return stamp;
+        }
+
+        public GuardNode getGuard() {
+            return guard;
+        }
+
+        public ValueNode getValue() {
+            return value;
+        }
     }
 
     public static class State extends MergeableState<State> implements Cloneable {
@@ -73,6 +107,7 @@
         private HashSet<ValueNode> knownNull;
         private IdentityHashMap<LogicNode, ValueNode> trueConditions;
         private IdentityHashMap<LogicNode, ValueNode> falseConditions;
+        private IdentityHashMap<ValueNode, GuardedStamp> valueConstraints;
 
         public State() {
             this.knownTypes = new IdentityHashMap<>();
@@ -80,6 +115,7 @@
             this.knownNull = new HashSet<>();
             this.trueConditions = new IdentityHashMap<>();
             this.falseConditions = new IdentityHashMap<>();
+            this.valueConstraints = new IdentityHashMap<>();
         }
 
         public State(State other) {
@@ -88,6 +124,7 @@
             this.knownNull = new HashSet<>(other.knownNull);
             this.trueConditions = new IdentityHashMap<>(other.trueConditions);
             this.falseConditions = new IdentityHashMap<>(other.falseConditions);
+            this.valueConstraints = new IdentityHashMap<>(other.valueConstraints);
         }
 
         @Override
@@ -95,6 +132,7 @@
             IdentityHashMap<ValueNode, ResolvedJavaType> newKnownTypes = new IdentityHashMap<>();
             IdentityHashMap<LogicNode, ValueNode> newTrueConditions = new IdentityHashMap<>();
             IdentityHashMap<LogicNode, ValueNode> newFalseConditions = new IdentityHashMap<>();
+            IdentityHashMap<ValueNode, GuardedStamp> newValueConstraints = new IdentityHashMap<>();
 
             HashSet<ValueNode> newKnownNull = new HashSet<>(knownNull);
             HashSet<ValueNode> newKnownNonNull = new HashSet<>(knownNonNull);
@@ -159,7 +197,7 @@
             // this piece of code handles phis
             if (!(merge instanceof LoopBeginNode)) {
                 for (PhiNode phi : merge.phis()) {
-                    if (phi.type() == PhiType.Value && phi.kind() == Kind.Object) {
+                    if (phi.type() == PhiType.Value && phi.getKind() == Kind.Object) {
                         ValueNode firstValue = phi.valueAt(0);
                         ResolvedJavaType type = getNodeType(firstValue);
                         boolean nonNull = knownNonNull.contains(firstValue);
@@ -191,6 +229,7 @@
             this.knownNull = newKnownNull;
             this.trueConditions = newTrueConditions;
             this.falseConditions = newFalseConditions;
+            this.valueConstraints = newValueConstraints;
             return true;
         }
 
@@ -404,32 +443,145 @@
             }
         }
 
-        private void registerGuard(GuardNode guard) {
+        private GuardedStamp computeGuardedStamp(GuardNode guard) {
+            if (guard.condition() instanceof IntegerBelowThanNode) {
+                if (guard.negated()) {
+                    // Not sure how to reason about negated guards
+                    return null;
+                }
+                IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition();
+                if (below.x().getKind() == Kind.Int && below.x().isConstant() && !below.y().isConstant()) {
+                    Stamp stamp = StampTool.unsignedCompare(below.x().stamp(), below.y().stamp());
+                    if (stamp != null) {
+                        return new GuardedStamp(below.y(), stamp, guard);
+                    }
+                }
+                if (below.y().getKind() == Kind.Int && below.y().isConstant() && !below.x().isConstant()) {
+                    Stamp stamp = StampTool.unsignedCompare(below.x().stamp(), below.y().stamp());
+                    if (stamp != null) {
+                        return new GuardedStamp(below.x(), stamp, guard);
+                    }
+                }
+            }
+            return null;
+        }
+
+        private boolean eliminateTrivialGuard(GuardNode guard) {
             LogicNode condition = guard.condition();
 
             ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition);
             if (existingGuards != null) {
-                guard.replaceAtUsages(existingGuards);
-                GraphUtil.killWithUnusedFloatingInputs(guard);
-                metricGuardsRemoved.increment();
+                eliminateGuard(guard, existingGuards);
+                return true;
             } else {
                 ValueNode anchor = state.trueConditions.get(condition);
                 if (anchor != null) {
                     if (!guard.negated()) {
-                        guard.replaceAtUsages(anchor);
-                        metricGuardsRemoved.increment();
-                        GraphUtil.killWithUnusedFloatingInputs(guard);
+                        eliminateGuard(guard, anchor);
+                        return true;
                     }
                 } else {
                     anchor = state.falseConditions.get(condition);
                     if (anchor != null) {
                         if (guard.negated()) {
-                            guard.replaceAtUsages(anchor);
-                            metricGuardsRemoved.increment();
-                            GraphUtil.killWithUnusedFloatingInputs(guard);
+                            eliminateGuard(guard, anchor);
+                            return true;
                         }
+                    }
+                }
+            }
+            // Can't be eliminated so accumulate any type information from the guard
+            registerConditionalStamp(guard);
+            return false;
+        }
+
+        /**
+         * Replace {@code guard} with {@code anchor} .
+         *
+         * @param guard The guard to eliminate.
+         * @param anchor Node to replace the guard.
+         */
+        private void eliminateGuard(GuardNode guard, ValueNode anchor) {
+            guard.replaceAtUsages(anchor);
+            metricGuardsRemoved.increment();
+            GraphUtil.killWithUnusedFloatingInputs(guard);
+        }
+
+        /**
+         * See if a conditional type constraint can prove this guard.
+         *
+         * @param guard
+         * @return true if the guard was eliminated.
+         */
+        private boolean testImpliedGuard(GuardNode guard) {
+            if (state.valueConstraints.size() == 0) {
+                // Nothing to do.
+                return false;
+            }
+
+            GuardNode existingGuard = null;
+            if (guard.condition() instanceof IntegerBelowThanNode) {
+                IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition();
+                IntegerStamp xStamp = (IntegerStamp) below.x().stamp();
+                IntegerStamp yStamp = (IntegerStamp) below.y().stamp();
+                GuardedStamp cstamp = state.valueConstraints.get(below.x());
+                if (cstamp != null) {
+                    xStamp = (IntegerStamp) cstamp.getStamp();
+                } else {
+                    cstamp = state.valueConstraints.get(below.y());
+                    if (cstamp != null) {
+                        yStamp = (IntegerStamp) cstamp.getStamp();
+                    }
+                }
+                if (cstamp != null) {
+                    if (cstamp.getGuard() == guard) {
+                        // found ourselves
+                        return false;
+                    }
+                    // See if we can use the other guard
+                    if (!guard.negated() && !cstamp.getGuard().negated() && yStamp.isPositive()) {
+                        if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+                            // Proven true
+                            existingGuard = cstamp.getGuard();
+                            Debug.log("existing guard %s %1s proves %1s", existingGuard, existingGuard.condition(), guard.condition());
+                        } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+                            // An earlier guard proves that this will always fail but it's probably
+                            // not worth trying to use it.
+                        }
+                    }
+                }
+            }
+
+            if (existingGuard != null) {
+                // Found a guard which proves this guard to be true, so replace it.
+                eliminateGuard(guard, existingGuard);
+                return true;
+            }
+            return false;
+        }
+
+        private void registerConditionalStamp(GuardNode guard) {
+            GuardedStamp conditional = computeGuardedStamp(guard);
+            if (conditional != null) {
+                GuardedStamp other = state.valueConstraints.get(conditional.getValue());
+                if (other == null) {
+                    state.valueConstraints.put(conditional.getValue(), conditional);
+                } else if (guard.negated() != other.getGuard().negated()) {
+                    // This seems impossible
+                    // Debug.log("negated and !negated guards %1s %1s", guard, other.getGuard());
+                } else if (!guard.negated()) {
+                    // two different constraints, pick the one with the tightest type
+                    // information
+                    Stamp result = conditional.getStamp().join(other.getStamp());
+                    if (result == conditional.getStamp()) {
+                        Debug.log("%1s overrides existing value %1s", guard.condition(), other.getGuard().condition());
+                        state.valueConstraints.put(conditional.getValue(), conditional);
+                    } else if (result == other.getStamp()) {
+                        // existing type constraint is best
+                        Debug.log("existing value is best %s", other.getGuard());
                     } else {
-                        registerCondition(!guard.negated(), condition, guard);
+                        // The merger produced some combination of values
+                        Debug.log("type merge produced new type %s", result);
                     }
                 }
             }
@@ -494,8 +646,29 @@
                 if (pred != null) {
                     registerControlSplitInfo(pred, begin);
                 }
+
+                // First eliminate any guards which can be trivially removed and register any
+                // type constraints the guards produce.
                 for (GuardNode guard : begin.guards().snapshot()) {
-                    registerGuard(guard);
+                    eliminateTrivialGuard(guard);
+                }
+
+                // Collect the guards which have produced conditional stamps.
+                HashSet<GuardNode> provers = new HashSet<>();
+                for (Map.Entry<ValueNode, GuardedStamp> e : state.valueConstraints.entrySet()) {
+                    provers.add(e.getValue().getGuard());
+                }
+
+                // Process the remaining guards. Guards which produced some type constraint should
+                // just be registered since they aren't trivially deleteable. Test the other guards
+                // to see if they can be deleted using type constraints.
+                for (GuardNode guard : begin.guards().snapshot()) {
+                    if (provers.contains(guard) || !testImpliedGuard(guard)) {
+                        registerCondition(!guard.negated(), guard.condition(), guard);
+                    }
+                }
+                for (GuardNode guard : provers) {
+                    assert !testImpliedGuard(guard) : "provers shouldn't be trivially eliminatable";
                 }
             } else if (node instanceof FixedGuardNode) {
                 FixedGuardNode guard = (FixedGuardNode) node;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -88,6 +88,9 @@
                     }
                     for (int i = 0; i < mergePredecessors.size(); ++i) {
                         AbstractEndNode mergePredecessor = mergePredecessors.get(i);
+                        if (!mergePredecessor.isAlive()) {
+                            break;
+                        }
                         if (xs[i] == null) {
                             continue;
                         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -82,7 +82,7 @@
                 }
             }
             if (obsoletes != null) {
-                ((DynamicDeoptimizeNode) ((MergeNode) target).next()).setDeoptimizationState(fs);
+                ((DynamicDeoptimizeNode) ((MergeNode) target).next()).setStateBefore(fs);
                 for (AbstractDeoptimizeNode obsolete : obsoletes) {
                     obsolete.safeDelete();
                 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -49,24 +49,41 @@
 
         @Override
         protected FrameState processNode(FixedNode node, FrameState currentState) {
-            if (node instanceof DeoptimizingNode) {
-                DeoptimizingNode deopt = (DeoptimizingNode) node;
-                if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) {
+            if (node instanceof DeoptimizingNode.DeoptBefore) {
+                DeoptimizingNode.DeoptBefore deopt = (DeoptimizingNode.DeoptBefore) node;
+                if (deopt.canDeoptimize() && deopt.stateBefore() == null) {
                     GraalInternalError.guarantee(currentState != null, "no FrameState at DeoptimizingNode %s", deopt);
-                    deopt.setDeoptimizationState(currentState);
+                    deopt.setStateBefore(currentState);
                 }
             }
 
+            FrameState newState = currentState;
             if (node instanceof StateSplit) {
                 StateSplit stateSplit = (StateSplit) node;
                 FrameState stateAfter = stateSplit.stateAfter();
                 if (stateAfter != null) {
-                    FrameState newState = stateAfter;
+                    newState = stateAfter;
                     stateSplit.setStateAfter(null);
-                    return newState;
                 }
             }
-            return currentState;
+
+            if (node instanceof DeoptimizingNode.DeoptDuring) {
+                DeoptimizingNode.DeoptDuring deopt = (DeoptimizingNode.DeoptDuring) node;
+                if (deopt.canDeoptimize()) {
+                    GraalInternalError.guarantee(newState != null, "no FrameState at DeoptimizingNode %s", deopt);
+                    deopt.computeStateDuring(newState);
+                }
+            }
+
+            if (node instanceof DeoptimizingNode.DeoptAfter) {
+                DeoptimizingNode.DeoptAfter deopt = (DeoptimizingNode.DeoptAfter) node;
+                if (deopt.canDeoptimize() && deopt.stateAfter() == null) {
+                    GraalInternalError.guarantee(newState != null, "no FrameState at DeoptimizingNode %s", deopt);
+                    deopt.setStateAfter(newState);
+                }
+            }
+
+            return newState;
         }
 
         @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -55,6 +55,9 @@
  * does the actual control-flow expansion of the remaining {@link GuardNode GuardNodes}.
  */
 public class GuardLoweringPhase extends BasePhase<MidTierContext> {
+
+    private static final DebugMetric metricImplicitNullCheck = Debug.metric("ImplicitNullCheck");
+
     private static class UseImplicitNullChecks extends ScheduledNodeIterator {
 
         private final IdentityHashMap<ValueNode, GuardNode> nullGuarded = new IdentityHashMap<>();
@@ -88,6 +91,7 @@
         private void processAccess(Access access) {
             GuardNode guard = nullGuarded.get(access.object());
             if (guard != null && isImplicitNullCheck(access.nullCheckLocation())) {
+                metricImplicitNullCheck.increment();
                 access.setGuard(guard.getGuard());
                 FixedAccessNode fixedAccess;
                 if (access instanceof FloatingAccessNode) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Sun Mar 30 16:08:33 2014 +0200
@@ -173,7 +173,10 @@
 
     public static void logInliningDecision(final String msg, final Object... args) {
         try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
-            Debug.log(msg, args);
+            // Can't use log here since we are varargs
+            if (Debug.isLogEnabled()) {
+                Debug.logv(msg, args);
+            }
         }
     }
 
@@ -482,7 +485,7 @@
         private void createGuard(StructuredGraph graph, MetaAccessProvider metaAccess) {
             ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
             ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), metaAccess, graph);
-            LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.kind(), null));
+            LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.getKind(), null));
 
             CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
             FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
@@ -624,7 +627,7 @@
             returnMerge.setStateAfter(invoke.stateAfter());
 
             PhiNode returnValuePhi = null;
-            if (invoke.asNode().kind() != Kind.Void) {
+            if (invoke.asNode().getKind() != Kind.Void) {
                 returnValuePhi = graph.addWithoutUnique(new PhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
             }
 
@@ -812,7 +815,7 @@
 
                 FixedNode lastSucc = successors[concretes.size()];
                 for (int i = concretes.size() - 1; i >= 0; --i) {
-                    LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].kind()));
+                    LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].getKind()));
                     CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
                     IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
                     method.setNext(ifNode);
@@ -910,7 +913,7 @@
             result.asNode().replaceFirstInput(result.callTarget(), callTarget);
             result.setUseForInlining(useForInlining);
 
-            Kind kind = invoke.asNode().kind();
+            Kind kind = invoke.asNode().getKind();
             if (kind != Kind.Void) {
                 FrameState stateAfter = invoke.stateAfter();
                 stateAfter = stateAfter.duplicate(stateAfter.bci);
@@ -1314,7 +1317,7 @@
         assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
         assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
 
-        Kind returnKind = invokeNode.kind();
+        Kind returnKind = invokeNode.getKind();
 
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter == null || stateAfter.isAlive();
@@ -1431,7 +1434,7 @@
                         if (frameState.outerFrameState() == null) {
                             assert frameState.bci == FrameState.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
                             if (outerFrameState == null) {
-                                outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.kind());
+                                outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.getKind());
                                 outerFrameState.setDuringCall(true);
                             }
                             frameState.setOuterFrameState(outerFrameState);
@@ -1515,7 +1518,7 @@
         assert !callTarget.isStatic() : callTarget.targetMethod();
         StructuredGraph graph = callTarget.graph();
         ValueNode firstParam = callTarget.arguments().get(0);
-        if (firstParam.kind() == Kind.Object && !ObjectStamp.isObjectNonNull(firstParam)) {
+        if (firstParam.getKind() == Kind.Object && !ObjectStamp.isObjectNonNull(firstParam)) {
             IsNullNode condition = graph.unique(new IsNullNode(firstParam));
             Stamp stamp = firstParam.stamp().join(objectNonNull());
             GuardingPiNode nonNullReceiver = graph.add(new GuardingPiNode(firstParam, condition, true, NullCheckException, InvalidateReprofile, stamp));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.schedule.*;
+
+/**
+ * This phase add counters for the dynamically executed number of nodes. Incrementing the counter
+ * for each node would be too costly, so this phase takes the compromise that it trusts split
+ * probabilities, but not loop frequencies. This means that it will insert counters at the start of
+ * a method and at each loop header.
+ * 
+ * A schedule is created so that floating nodes can also be taken into account. The weight of a node
+ * is determined heuristically in the
+ * {@link ProfileCompiledMethodsPhase#getNodeWeight(ScheduledNode)} method.
+ * 
+ * Additionally, there's a second counter that's only increased for code sections without invokes.
+ */
+public class ProfileCompiledMethodsPhase extends Phase {
+
+    private static final String GROUP_NAME = "~profiled weight";
+    private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)";
+
+    private static final boolean WITH_SECTION_HEADER = false;
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        ComputeProbabilityClosure closure = new ComputeProbabilityClosure(graph);
+        NodesToDoubles probabilities = closure.apply();
+        SchedulePhase schedule = new SchedulePhase();
+        schedule.apply(graph, false);
+
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+        for (Loop loop : cfg.getLoops()) {
+            double loopProbability = probabilities.get(loop.loopBegin());
+            if (loopProbability > (1D / Integer.MAX_VALUE)) {
+                addSectionCounters(loop.loopBegin(), loop.blocks, loop.children, schedule, probabilities);
+            }
+        }
+        addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), Arrays.asList(cfg.getLoops()), schedule, probabilities);
+    }
+
+    private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) {
+        HashSet<Block> blocks = new HashSet<>(sectionBlocks);
+        for (Loop loop : childLoops) {
+            blocks.removeAll(loop.blocks);
+        }
+        double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start);
+        DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
+        if (!hasInvoke(blocks)) {
+            DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next());
+        }
+    }
+
+    private static String sectionHead(Node node) {
+        if (WITH_SECTION_HEADER) {
+            return node.toString();
+        } else {
+            return "";
+        }
+    }
+
+    private static double getSectionWeight(SchedulePhase schedule, NodesToDoubles probabilities, Collection<Block> blocks) {
+        double count = 0;
+        for (Block block : blocks) {
+            double blockProbability = probabilities.get(block.getBeginNode());
+            for (ScheduledNode node : schedule.getBlockToNodesMap().get(block)) {
+                count += blockProbability * getNodeWeight(node);
+            }
+        }
+        return count;
+    }
+
+    private static double getNodeWeight(ScheduledNode node) {
+        if (node instanceof MergeNode) {
+            return ((MergeNode) node).phiPredecessorCount();
+        } else if (node instanceof AbstractBeginNode || node instanceof AbstractEndNode || node instanceof MonitorIdNode || node instanceof ConstantNode || node instanceof ParameterNode ||
+                        node instanceof CallTargetNode || node instanceof ValueProxy || node instanceof VirtualObjectNode || node instanceof ReinterpretNode) {
+            return 0;
+        } else if (node instanceof AccessMonitorNode) {
+            return 10;
+        } else if (node instanceof Access) {
+            return 2;
+        } else if (node instanceof LogicNode || node instanceof ConvertNode || node instanceof BinaryNode || node instanceof NotNode) {
+            return 1;
+        } else if (node instanceof IntegerDivNode || node instanceof FloatDivNode || node instanceof IntegerRemNode || node instanceof FloatRemNode) {
+            return 10;
+        } else if (node instanceof IntegerMulNode || node instanceof FloatMulNode) {
+            return 3;
+        } else if (node instanceof Invoke) {
+            return 5;
+        } else if (node instanceof IfNode || node instanceof SafepointNode) {
+            return 1;
+        } else if (node instanceof SwitchNode) {
+            return node.successors().count();
+        } else if (node instanceof ReturnNode || node instanceof UnwindNode || node instanceof DeoptimizeNode) {
+            return node.successors().count();
+        } else if (node instanceof AbstractNewObjectNode) {
+            return 10;
+        }
+        return 2;
+    }
+
+    private static boolean hasInvoke(Collection<Block> blocks) {
+        boolean hasInvoke = false;
+        for (Block block : blocks) {
+            for (FixedNode fixed : block.getNodes()) {
+                if (fixed instanceof Invoke) {
+                    hasInvoke = true;
+                }
+            }
+        }
+        return hasInvoke;
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -76,7 +76,7 @@
         AbstractBeginNode nonTrappingContinuation = ifNode.falseSuccessor();
         AbstractBeginNode trappingContinuation = ifNode.trueSuccessor();
         NullCheckNode trappingNullCheck = deopt.graph().add(new NullCheckNode(isNullNode.object()));
-        trappingNullCheck.setDeoptimizationState(deopt.getDeoptimizationState());
+        trappingNullCheck.setStateBefore(deopt.stateBefore());
         deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation);
 
         GraphUtil.killCFG(trappingContinuation);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -36,38 +36,7 @@
  */
 public abstract class BasePhase<C> {
 
-    /**
-     * Phase name lazily computed from the phase class.
-     */
-    class Name extends LazyName {
-
-        @Override
-        public String createString() {
-            String s = BasePhase.this.getClass().getSimpleName();
-            if (s.endsWith("Phase")) {
-                return s.substring(0, s.length() - "Phase".length());
-            }
-            return s;
-        }
-    }
-
-    /**
-     * Lazily computed debug value name composed of a prefix and a phase's name.
-     */
-    class DebugValueName extends LazyName {
-        final String prefix;
-
-        public DebugValueName(String prefix) {
-            this.prefix = prefix;
-        }
-
-        @Override
-        public String createString() {
-            return prefix + name;
-        }
-    }
-
-    private final CharSequence name;
+    private CharSequence name;
 
     private final DebugTimer phaseTimer;
     private final DebugMetric phaseMetric;
@@ -80,17 +49,15 @@
     }
 
     protected BasePhase() {
-        name = new Name();
-        assert checkName(name.toString());
-        phaseTimer = Debug.timer(new DebugValueName("PhaseTime_"));
-        phaseMetric = Debug.metric(new DebugValueName("PhaseCount_"));
+        phaseTimer = Debug.timer("PhaseTime_%s", getClass());
+        phaseMetric = Debug.metric("PhaseCount_%s", getClass());
     }
 
     protected BasePhase(String name) {
         assert checkName(name);
         this.name = name;
-        phaseTimer = Debug.timer(new DebugValueName("PhaseTime_"));
-        phaseMetric = Debug.metric(new DebugValueName("PhaseCount_"));
+        phaseTimer = Debug.timer("PhaseTime_%s", getClass());
+        phaseMetric = Debug.metric("PhaseCount_%s", getClass());
     }
 
     protected CharSequence getDetailedName() {
@@ -102,11 +69,11 @@
     }
 
     public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
-        try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(name, this)) {
+        try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this)) {
             BasePhase.this.run(graph, context);
             phaseMetric.increment();
             if (dumpGraph) {
-                Debug.dump(graph, "After phase %s", name);
+                Debug.dump(graph, "After phase %s", getName());
             }
             assert graph.verify();
         } catch (Throwable t) {
@@ -115,6 +82,13 @@
     }
 
     public final CharSequence getName() {
+        if (name == null) {
+            String s = BasePhase.this.getClass().getSimpleName();
+            if (s.endsWith("Phase")) {
+                s = s.substring(0, s.length() - "Phase".length());
+            }
+            name = s;
+        }
         return name;
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sun Mar 30 16:08:33 2014 +0200
@@ -271,6 +271,8 @@
     public static final OptionValue<Boolean> OptDevirtualizeInvokesOptimistically = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true);
+    @Option(help = "Allow backend to emit arithmetic and compares directly against memory.")
+    public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(true);
 
 
     /**
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/LazyName.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/LazyName.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,8 +26,8 @@
 
 /**
  * A name whose {@link String} value is computed only when it is needed. This is useful in
- * combination with debugging facilities such as {@link Debug#scope(CharSequence, Object...)} where
- * the {@link String} value of a name is only needed if debugging is enabled.
+ * combination with debugging facilities such as {@link Debug#scope(Object)} where the
+ * {@link String} value of a name is only needed if debugging is enabled.
  */
 public abstract class LazyName implements CharSequence {
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
@@ -64,98 +63,14 @@
     }
 
     public NodesToDoubles apply() {
-        adjustControlSplitProbabilities();
+        // adjustControlSplitProbabilities();
         new PropagateProbability(graph.start()).apply();
         computeLoopFactors();
         new PropagateLoopFrequency(graph.start()).apply();
-        assert verifyProbabilities();
+        // assert verifyProbabilities();
         return nodeProbabilities;
     }
 
-    /**
-     * Assume that paths with a DeoptimizeNode at their end are taken infrequently.
-     */
-    private void adjustControlSplitProbabilities() {
-        Set<ControlSplitNode> result = new ArraySet<>();
-        NodeBitMap visitedNodes = new NodeBitMap(graph);
-        for (AbstractDeoptimizeNode n : graph.getNodes(AbstractDeoptimizeNode.class)) {
-            if (!(n instanceof DeoptimizeNode) || ((DeoptimizeNode) n).action().doesInvalidateCompilation()) {
-                findParentControlSplitNodes(result, n, visitedNodes);
-            }
-        }
-
-        for (ControlSplitNode n : result) {
-            if (!allSuxVisited(n, visitedNodes)) {
-                modifyProbabilities(n, visitedNodes);
-            }
-        }
-    }
-
-    private static void findParentControlSplitNodes(Set<ControlSplitNode> result, AbstractDeoptimizeNode n, NodeBitMap visitedNodes) {
-        ArrayDeque<FixedNode> nodes = new ArrayDeque<>();
-        nodes.push(n);
-
-        Node currentNode;
-        do {
-            currentNode = nodes.pop();
-            visitedNodes.mark(currentNode);
-
-            for (Node pred : currentNode.cfgPredecessors()) {
-                FixedNode fixedPred = (FixedNode) pred;
-                if (visitedNodes.isMarked(fixedPred) && allPredsVisited(fixedPred, visitedNodes)) {
-                    DebugScope.dump(n.graph(), "ComputeProbabilityClosure");
-                    GraalInternalError.shouldNotReachHere(String.format("Endless loop because %s was already visited", fixedPred));
-                } else if (allSuxVisited(fixedPred, visitedNodes)) {
-                    nodes.push(fixedPred);
-                } else {
-                    assert fixedPred instanceof ControlSplitNode : "only control splits can have more than one sux";
-                    result.add((ControlSplitNode) fixedPred);
-                }
-            }
-        } while (!nodes.isEmpty());
-    }
-
-    private static void modifyProbabilities(ControlSplitNode controlSplit, NodeBitMap visitedNodes) {
-        assert !allSuxVisited(controlSplit, visitedNodes);
-        for (Node sux : controlSplit.successors()) {
-            if (visitedNodes.isMarked(sux)) {
-                controlSplit.setProbability((AbstractBeginNode) sux, 0);
-            }
-        }
-    }
-
-    private static boolean allSuxVisited(FixedNode node, NodeBitMap visitedNodes) {
-        return allVisited(node.successors(), visitedNodes);
-    }
-
-    private static boolean allPredsVisited(FixedNode node, NodeBitMap visitedNodes) {
-        return allVisited(node.cfgPredecessors(), visitedNodes);
-    }
-
-    private static boolean allVisited(Iterable<? extends Node> nodes, NodeBitMap visitedNodes) {
-        for (Node sux : nodes) {
-            if (!visitedNodes.contains(sux)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean verifyProbabilities() {
-        if (doesNotAlwaysDeopt(graph)) {
-            for (AbstractDeoptimizeNode n : graph.getNodes(AbstractDeoptimizeNode.class)) {
-                if (nodeProbabilities.get(n) > 0.01 && (!(n instanceof DeoptimizeNode) || ((DeoptimizeNode) n).action().doesInvalidateCompilation())) {
-                    throw new AssertionError(String.format("%s with probability %f in graph %s", n, nodeProbabilities.get(n), graph));
-                }
-            }
-        }
-        return true;
-    }
-
-    private static boolean doesNotAlwaysDeopt(StructuredGraph graph) {
-        return graph.getNodes(ReturnNode.class).isNotEmpty();
-    }
-
     private void computeLoopFactors() {
         for (LoopInfo info : loopInfos) {
             double frequency = info.loopFrequency(nodeProbabilities);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -59,7 +59,7 @@
         /**
          * This constructor creates a {@link SchedulingError} with a message assembled via
          * {@link String#format(String, Object...)}.
-         * 
+         *
          * @param format a {@linkplain Formatter format} string
          * @param args parameters to {@link String#format(String, Object...)}
          */
@@ -164,9 +164,9 @@
 
     /**
      * gather all kill locations by iterating trough the nodes assigned to a block.
-     * 
+     *
      * assumptions: {@link MemoryCheckpoint MemoryCheckPoints} are {@link FixedNode FixedNodes}.
-     * 
+     *
      * @param block block to analyze
      * @param excludeNode if null, compute normal set of kill locations. if != null, don't add kills
      *            until we reach excludeNode.
@@ -293,19 +293,20 @@
 
     private void printSchedule(String desc) {
         if (Debug.isLogEnabled()) {
-            Debug.printf("=== %s / %s / %s (%s) ===\n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, memsched, desc);
+            Formatter buf = new Formatter();
+            buf.format("=== %s / %s / %s (%s) ===%n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, memsched, desc);
             for (Block b : getCFG().getBlocks()) {
-                Debug.printf("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth());
-                Debug.printf("dom: %s. ", b.getDominator());
-                Debug.printf("post-dom: %s. ", b.getPostdominator());
-                Debug.printf("preds: %s. ", b.getPredecessors());
-                Debug.printf("succs: %s ====\n", b.getSuccessors());
+                buf.format("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth());
+                buf.format("dom: %s. ", b.getDominator());
+                buf.format("post-dom: %s. ", b.getPostdominator());
+                buf.format("preds: %s. ", b.getPredecessors());
+                buf.format("succs: %s ====%n", b.getSuccessors());
                 BlockMap<KillSet> killSets = blockToKillSet;
                 if (killSets != null) {
-                    Debug.printf("X block kills: \n");
+                    buf.format("X block kills: %n");
                     if (killSets.get(b) != null) {
                         for (LocationIdentity locId : killSets.get(b)) {
-                            Debug.printf("X %s killed by %s\n", locId, "dunno anymore");
+                            buf.format("X %s killed by %s%n", locId, "dunno anymore");
                         }
                     }
                 }
@@ -320,28 +321,30 @@
                     }
                 }
             }
-            Debug.printf("\n\n");
+            buf.format("%n");
+            Debug.log("%s", buf);
         }
     }
 
     private static void printNode(Node n) {
-        Debug.printf("%s", n);
+        Formatter buf = new Formatter();
+        buf.format("%s", n);
         if (n instanceof MemoryCheckpoint.Single) {
-            Debug.printf(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity());
+            buf.format(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity());
         } else if (n instanceof MemoryCheckpoint.Multi) {
-            Debug.printf(" // kills ");
+            buf.format(" // kills ");
             for (LocationIdentity locid : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
-                Debug.printf("%s, ", locid);
+                buf.format("%s, ", locid);
             }
         } else if (n instanceof FloatingReadNode) {
             FloatingReadNode frn = (FloatingReadNode) n;
-            Debug.printf(" // from %s", frn.location().getLocationIdentity());
-            Debug.printf(", lastAccess: %s", frn.getLastLocationAccess());
-            Debug.printf(", object: %s", frn.object());
+            buf.format(" // from %s", frn.location().getLocationIdentity());
+            buf.format(", lastAccess: %s", frn.getLastLocationAccess());
+            buf.format(", object: %s", frn.object());
         } else if (n instanceof GuardNode) {
-            Debug.printf(", guard: %s", ((GuardNode) n).getGuard());
+            buf.format(", guard: %s", ((GuardNode) n).getGuard());
         }
-        Debug.printf("\n");
+        Debug.log("%s", buf);
     }
 
     public ControlFlowGraph getCFG() {
@@ -410,7 +413,7 @@
                 if (scheduleRead) {
                     FloatingReadNode read = (FloatingReadNode) node;
                     block = optimalBlock(read, strategy);
-                    Debug.printf("schedule for %s: %s\n", read, block);
+                    Debug.log("schedule for %s: %s", read, block);
                     assert earliestBlock.dominates(block) : String.format("%s (%s) cannot be scheduled before earliest schedule (%s). location: %s", read, block, earliestBlock,
                                     read.getLocationIdentity());
                 } else {
@@ -457,9 +460,9 @@
      * this method tries to find the "optimal" schedule for a read, by pushing it down towards its
      * latest schedule starting by the earliest schedule. By doing this, it takes care of memory
      * dependencies using kill sets.
-     * 
+     *
      * In terms of domination relation, it looks like this:
-     * 
+     *
      * <pre>
      *    U      upperbound block, defined by last access location of the floating read
      *    &#9650;
@@ -469,9 +472,9 @@
      *    &#9650;
      *    L      latest block
      * </pre>
-     * 
+     *
      * i.e. <code>upperbound `dom` earliest `dom` optimal `dom` latest</code>.
-     * 
+     *
      */
     private Block optimalBlock(FloatingReadNode n, SchedulingStrategy strategy) {
         assert memsched == MemoryScheduling.OPTIMAL;
@@ -486,14 +489,14 @@
         Block latestBlock = latestBlock(n, strategy);
         assert latestBlock != null && earliestBlock.dominates(latestBlock) : "earliest (" + earliestBlock + ") should dominate latest block (" + latestBlock + ")";
 
-        Debug.printf("processing %s (accessing %s): latest %s, earliest %s, upper bound %s (%s)\n", n, locid, latestBlock, earliestBlock, upperBoundBlock, n.getLastLocationAccess());
+        Debug.log("processing %s (accessing %s): latest %s, earliest %s, upper bound %s (%s)", n, locid, latestBlock, earliestBlock, upperBoundBlock, n.getLastLocationAccess());
         if (earliestBlock == latestBlock) {
             // read is fixed to this block, nothing to schedule
             return latestBlock;
         }
 
         Deque<Block> path = computePathInDominatorTree(earliestBlock, latestBlock);
-        Debug.printf("|path| is %d: %s\n", path.size(), path);
+        Debug.log("|path| is %d: %s", path.size(), path);
 
         // follow path, start at earliest schedule
         while (path.size() > 0) {
@@ -504,7 +507,7 @@
                 assert dominatedBlock.getBeginNode() instanceof MergeNode;
 
                 HashSet<Block> region = computeRegion(currentBlock, dominatedBlock);
-                Debug.printf("> merge.  %s: region for %s -> %s: %s\n", n, currentBlock, dominatedBlock, region);
+                Debug.log("> merge.  %s: region for %s -> %s: %s", n, currentBlock, dominatedBlock, region);
 
                 NewMemoryScheduleClosure closure = null;
                 if (currentBlock == upperBoundBlock) {
@@ -540,7 +543,7 @@
 
     /**
      * compute path in dominator tree from earliest schedule to latest schedule.
-     * 
+     *
      * @return the order of the stack is such as the first element is the earliest schedule.
      */
     private static Deque<Block> computePathInDominatorTree(Block earliestBlock, Block latestBlock) {
@@ -582,7 +585,7 @@
     /**
      * Calculates the last block that the given node could be scheduled in, i.e., the common
      * dominator of all usages. To do so all usages are also assigned to blocks.
-     * 
+     *
      * @param strategy
      */
     private Block latestBlock(ScheduledNode node, SchedulingStrategy strategy) {
@@ -643,7 +646,7 @@
          * implies that the inputs' blocks have a total ordering via their dominance relation. So in
          * order to find the earliest block placement for this node we need to find the input block
          * that is dominated by all other input blocks.
-         * 
+         *
          * While iterating over the inputs a set of dominator blocks of the current earliest
          * placement is maintained. When the block of an input is not within this set, it becomes
          * the current earliest placement and the list of dominator blocks is updated.
@@ -680,7 +683,7 @@
      * Schedules a node out of loop based on its earliest schedule. Note that this movement is only
      * valid if it's done for <b>every</b> other node in the schedule, otherwise this movement is
      * not valid.
-     * 
+     *
      * @param n Node to schedule
      * @param latestBlock latest possible schedule for {@code n}
      * @param earliest earliest possible schedule for {@code n}
@@ -705,7 +708,7 @@
     /**
      * Passes all blocks that a specific usage of a node is in to a given closure. This is more
      * complex than just taking the usage's block because of of PhiNodes and FrameStates.
-     * 
+     *
      * @param node the node that needs to be scheduled
      * @param usage the usage whose blocks need to be considered
      * @param closure the closure that will be called for each block
@@ -966,14 +969,18 @@
             return;
         }
 
-        FrameState state = null;
+        FrameState stateAfter = null;
+        if (i instanceof StateSplit) {
+            stateAfter = ((StateSplit) i).stateAfter();
+        }
+
         for (Node input : i.inputs()) {
             if (input instanceof FrameState) {
-                assert state == null;
-                state = (FrameState) input;
+                if (input != stateAfter) {
+                    addUnscheduledToLatestSorting(b, (FrameState) input, sortedInstructions, visited, reads, beforeLastLocation);
+                }
             } else {
                 addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
-
             }
         }
 
@@ -991,7 +998,7 @@
 
         addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited, reads, beforeLastLocation);
         visited.mark(i);
-        addUnscheduledToLatestSorting(b, state, sortedInstructions, visited, reads, beforeLastLocation);
+        addUnscheduledToLatestSorting(b, stateAfter, sortedInstructions, visited, reads, beforeLastLocation);
 
         // Now predecessors and inputs are scheduled => we can add this node.
         if (!sortedInstructions.contains(i)) {
@@ -1038,7 +1045,7 @@
             }
 
             if (instruction instanceof AbstractBeginNode) {
-                ArrayList<ProxyNode> proxies = (instruction instanceof LoopExitNode) ? new ArrayList<ProxyNode>() : null;
+                ArrayList<ProxyNode> proxies = (instruction instanceof LoopExitNode) ? new ArrayList<>() : null;
                 for (ScheduledNode inBlock : blockToNodesMap.get(b)) {
                     if (!visited.isMarked(inBlock)) {
                         if (inBlock instanceof ProxyNode) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Sun Mar 30 16:08:33 2014 +0200
@@ -60,7 +60,13 @@
                         if (input instanceof FrameState && node instanceof StateSplit && input == ((StateSplit) node).stateAfter()) {
                             // nothing to do - after frame states are known, allowed cycles
                         } else {
-                            assert false : "unexpected cycle detected at input " + node + " -> " + input;
+                            /*
+                             * TODO assertion does not hold for Substrate VM (in general for all
+                             * notDataflow inputs)
+                             * 
+                             * assert false : "unexpected cycle detected at input " + node + " -> "
+                             * + input;
+                             */
                         }
                     }
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyDebugUsage.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.verify;
+
+import static com.oracle.graal.api.meta.MetaUtil.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+
+/**
+ * Verifies that no argument to one of the {@link Debug#log(String)} methods is the result of
+ * {@link StringBuilder#toString()} or {@link StringBuffer#toString()}. Instead, one of the
+ * multi-parameter {@code log()} methods should be used. The goal is to minimize/prevent allocation
+ * at logging call sites.
+ */
+public class VerifyDebugUsage extends VerifyPhase<PhaseContext> {
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.class)) {
+            ResolvedJavaMethod callee = t.targetMethod();
+            ResolvedJavaType debugType = context.getMetaAccess().lookupJavaType(Debug.class);
+            if (callee.getDeclaringClass().equals(debugType)) {
+                if (callee.getName().equals("log")) {
+                    int argIdx = 1;
+                    for (ValueNode arg : t.arguments()) {
+                        if (arg instanceof Invoke) {
+                            Invoke invoke = (Invoke) arg;
+                            CallTargetNode callTarget = invoke.callTarget();
+                            if (callTarget instanceof MethodCallTargetNode) {
+                                ResolvedJavaMethod m = ((MethodCallTargetNode) callTarget).targetMethod();
+                                if (m.getName().equals("toString")) {
+                                    String holder = m.getDeclaringClass().getName();
+                                    if (holder.equals("Ljava/lang/StringBuilder;") || holder.equals("Ljava/lang/StringBuffer;")) {
+                                        StackTraceElement e = graph.method().asStackTraceElement(invoke.bci());
+                                        throw new VerificationError(String.format("%s: parameter %d of call to %s appears to be a String concatenation expression.%n"
+                                                        + "    Use one of the multi-parameter Debug.log() methods or Debug.logv() instead.", e, argIdx, format("%H.%n(%p)", callee)));
+                                    }
+                                }
+                            }
+                        }
+                        argIdx++;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+}
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Sun Mar 30 16:08:33 2014 +0200
@@ -50,7 +50,7 @@
 
     protected TargetDescription target;
     protected LIR lir;
-    protected LIRGenerator lirGenerator;
+    protected NodeLIRGenerator nodeLirGenerator;
     protected ControlFlowGraph cfg;
     protected SchedulePhase schedule;
 
@@ -73,7 +73,7 @@
     public void printCFG(String label, BciBlockMapping blockMap) {
         begin("cfg");
         out.print("name \"").print(label).println('"');
-        for (BciBlockMapping.Block block : blockMap.blocks) {
+        for (BciBlockMapping.BciBlock block : blockMap.blocks) {
             begin("block");
             printBlock(block);
             end("block");
@@ -81,7 +81,7 @@
         end("cfg");
     }
 
-    private void printBlock(BciBlockMapping.Block block) {
+    private void printBlock(BciBlockMapping.BciBlock block) {
         out.print("name \"B").print(block.startBci).println('"');
         out.print("from_bci ").println(block.startBci);
         out.print("to_bci ").println(block.endBci);
@@ -89,7 +89,7 @@
         out.println("predecessors ");
 
         out.print("successors ");
-        for (BciBlockMapping.Block succ : block.successors) {
+        for (BciBlockMapping.BciBlock succ : block.getSuccessors()) {
             if (!succ.isExceptionEntry) {
                 out.print("\"B").print(succ.startBci).print("\" ");
             }
@@ -97,7 +97,7 @@
         out.println();
 
         out.print("xhandlers");
-        for (BciBlockMapping.Block succ : block.successors) {
+        for (BciBlockMapping.BciBlock succ : block.getSuccessors()) {
             if (succ.isExceptionEntry) {
                 out.print("\"B").print(succ.startBci).print("\" ");
             }
@@ -129,10 +129,11 @@
      * @param label A label describing the compilation phase that produced the control flow graph.
      * @param blocks The list of blocks to be printed.
      */
-    public void printCFG(String label, List<Block> blocks, boolean printNodes) {
+    public void printCFG(String label, List<? extends AbstractBlock<?>> blocks, boolean printNodes) {
         if (lir == null) {
             latestScheduling = new NodeMap<>(cfg.getNodeToBlock());
-            for (Block block : blocks) {
+            for (AbstractBlock<?> abstractBlock : blocks) {
+                Block block = (Block) abstractBlock;
                 Node cur = block.getBeginNode();
                 while (true) {
                     assert inFixedSchedule(cur) && latestScheduling.get(cur) == block;
@@ -146,17 +147,15 @@
                 }
             }
         }
-        printedNodes = new NodeBitMap(cfg.graph);
 
         begin("cfg");
         out.print("name \"").print(label).println('"');
-        for (Block block : blocks) {
+        for (AbstractBlock<?> block : blocks) {
             printBlock(block, printNodes);
         }
         end("cfg");
 
         latestScheduling = null;
-        printedNodes = null;
     }
 
     private void scheduleInputs(Node node, Block nodeBlock) {
@@ -187,20 +186,21 @@
         }
     }
 
-    private void printBlock(Block block, boolean printNodes) {
+    private void printBlock(AbstractBlock<?> block, boolean printNodes) {
         printBlockProlog(block);
         if (printNodes) {
-            printNodes(block);
+            assert block instanceof Block;
+            printNodes((Block) block);
         }
         printBlockEpilog(block);
     }
 
-    private void printBlockEpilog(Block block) {
+    private void printBlockEpilog(AbstractBlock<?> block) {
         printLIR(block);
         end("block");
     }
 
-    private void printBlockProlog(Block block) {
+    private void printBlockProlog(AbstractBlock<?> block) {
         begin("block");
 
         out.print("name \"").print(blockToString(block)).println('"');
@@ -208,13 +208,13 @@
         out.println("to_bci -1");
 
         out.print("predecessors ");
-        for (Block pred : block.getPredecessors()) {
+        for (AbstractBlock<?> pred : block.getPredecessors()) {
             out.print("\"").print(blockToString(pred)).print("\" ");
         }
         out.println();
 
         out.print("successors ");
-        for (Block succ : block.getSuccessors()) {
+        for (AbstractBlock<?> succ : block.getSuccessors()) {
             if (!succ.isExceptionEntry()) {
                 out.print("\"").print(blockToString(succ)).print("\" ");
             }
@@ -222,7 +222,7 @@
         out.println();
 
         out.print("xhandlers");
-        for (Block succ : block.getSuccessors()) {
+        for (AbstractBlock<?> succ : block.getSuccessors()) {
             if (succ.isExceptionEntry()) {
                 out.print("\"").print(blockToString(succ)).print("\" ");
             }
@@ -248,6 +248,7 @@
     }
 
     private void printNodes(Block block) {
+        printedNodes = new NodeBitMap(cfg.graph);
         begin("IR");
         out.println("HIR");
         out.disableIndentation();
@@ -281,6 +282,7 @@
 
         out.enableIndentation();
         end("IR");
+        printedNodes = null;
     }
 
     private void printNode(Node node, boolean unscheduled) {
@@ -307,8 +309,8 @@
         }
         out.print("tid ").print(nodeToString(node)).println(COLUMN_END);
 
-        if (lirGenerator != null) {
-            Value operand = lirGenerator.nodeOperands.get(node);
+        if (nodeLirGenerator != null) {
+            Value operand = nodeLirGenerator.getNodeOperands().get(node);
             if (operand != null) {
                 out.print("result ").print(operand.toString()).println(COLUMN_END);
             }
@@ -412,8 +414,8 @@
 
     private String stateValueToString(ValueNode value) {
         String result = nodeToString(value);
-        if (lirGenerator != null && lirGenerator.nodeOperands != null && value != null) {
-            Value operand = lirGenerator.nodeOperands.get(value);
+        if (nodeLirGenerator != null && nodeLirGenerator.getNodeOperands() != null && value != null) {
+            Value operand = nodeLirGenerator.getNodeOperands().get(value);
             if (operand != null) {
                 result += ": " + operand;
             }
@@ -426,11 +428,11 @@
      * 
      * @param block the block to print
      */
-    private void printLIR(Block block) {
+    private void printLIR(AbstractBlock<?> block) {
         if (lir == null) {
             return;
         }
-        List<LIRInstruction> lirInstructions = lir.lir(block);
+        List<LIRInstruction> lirInstructions = lir.getLIRforBlock(block);
         if (lirInstructions == null) {
             return;
         }
@@ -477,10 +479,10 @@
             prefix = "B";
         } else if (node instanceof ValueNode) {
             ValueNode value = (ValueNode) node;
-            if (value.kind() == Kind.Illegal) {
+            if (value.getKind() == Kind.Illegal) {
                 prefix = "v";
             } else {
-                prefix = String.valueOf(value.kind().getTypeChar());
+                prefix = String.valueOf(value.getKind().getTypeChar());
             }
         } else {
             prefix = "?";
@@ -488,13 +490,13 @@
         return prefix + node.toString(Verbosity.Id);
     }
 
-    private String blockToString(Block block) {
-        if (lir == null && schedule == null) {
+    private String blockToString(AbstractBlock<?> block) {
+        if (lir == null && schedule == null && block instanceof Block) {
             // During all the front-end phases, the block schedule is built only for the debug
             // output.
             // Therefore, the block numbers would be different for every CFG printed -> use the id
             // of the first instruction.
-            return "B" + block.getBeginNode().toString(Verbosity.Id);
+            return "B" + ((Block) block).getBeginNode().toString(Verbosity.Id);
         } else {
             // LIR instructions contain references to blocks and these blocks are printed as the
             // blockID -> use the blockID.
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Sun Mar 30 16:08:33 2014 +0200
@@ -137,12 +137,12 @@
         } else {
             cfgPrinter.lir = Debug.contextLookup(LIR.class);
         }
-        cfgPrinter.lirGenerator = Debug.contextLookup(LIRGenerator.class);
-        if (cfgPrinter.lirGenerator != null) {
-            cfgPrinter.target = cfgPrinter.lirGenerator.target();
+        cfgPrinter.nodeLirGenerator = Debug.contextLookup(NodeLIRGenerator.class);
+        if (cfgPrinter.nodeLirGenerator != null) {
+            cfgPrinter.target = cfgPrinter.nodeLirGenerator.getLIRGeneratorTool().target();
         }
-        if (cfgPrinter.lir != null) {
-            cfgPrinter.cfg = cfgPrinter.lir.getControlFlowGraph();
+        if (cfgPrinter.lir != null && cfgPrinter.lir.getControlFlowGraph() instanceof ControlFlowGraph) {
+            cfgPrinter.cfg = (ControlFlowGraph) cfgPrinter.lir.getControlFlowGraph();
         }
 
         CodeCacheProvider codeCache = Debug.contextLookup(CodeCacheProvider.class);
@@ -160,7 +160,7 @@
         } else if (object instanceof LIR) {
             // No need to print the HIR nodes again if this is not the first
             // time dumping the same LIR since the HIR will not have changed.
-            boolean printNodes = previousObject != object;
+            boolean printNodes = previousObject != object && cfgPrinter.cfg != null;
             cfgPrinter.printCFG(message, cfgPrinter.lir.codeEmittingOrder(), printNodes);
 
         } else if (object instanceof SchedulePhase) {
@@ -185,7 +185,7 @@
 
         cfgPrinter.target = null;
         cfgPrinter.lir = null;
-        cfgPrinter.lirGenerator = null;
+        cfgPrinter.nodeLirGenerator = null;
         cfgPrinter.cfg = null;
         cfgPrinter.flush();
 
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Sun Mar 30 16:08:33 2014 +0200
@@ -115,7 +115,7 @@
             if (PrintBinaryGraphs.getValue()) {
                 printer = new BinaryGraphPrinter(FileChannel.open(file.toPath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW));
             } else {
-                printer = new IdealGraphPrinter(new FileOutputStream(file));
+                printer = new IdealGraphPrinter(new FileOutputStream(file), true);
             }
             TTY.println("Dumping IGV graphs to %s", file.getName());
         } catch (IOException e) {
@@ -132,7 +132,7 @@
             if (PrintBinaryGraphs.getValue()) {
                 printer = new BinaryGraphPrinter(SocketChannel.open(new InetSocketAddress(host, port)));
             } else {
-                IdealGraphPrinter xmlPrinter = new IdealGraphPrinter(new Socket(host, port).getOutputStream());
+                IdealGraphPrinter xmlPrinter = new IdealGraphPrinter(new Socket(host, port).getOutputStream(), true);
                 printer = xmlPrinter;
             }
             TTY.println("Connected to the IGV on %s:%d", host, port);
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java	Sun Mar 30 16:08:33 2014 +0200
@@ -293,9 +293,8 @@
         }
 
         void warning(int offset, String message) {
-            // CheckStyle: stop system..print check
-            System.err.println("Warning: " + errorMessage(offset, message));
-            // CheckStyle: resume system..print check
+            PrintStream err = System.err;
+            err.println("Warning: " + errorMessage(offset, message));
         }
 
         String errorMessage(int offset, String message) {
@@ -323,10 +322,9 @@
             int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1;
 
             String l = input.substring(lineStart, lineStart + 10);
-            // CheckStyle: stop system..print check
-            System.out.println("YYY" + input.substring(index, index + 10) + "...");
-            System.out.println("XXX" + l + "...");
-            // CheckStyle: resume system..print check
+            PrintStream out = System.out;
+            out.println("YYY" + input.substring(index, index + 10) + "...");
+            out.println("XXX" + l + "...");
 
             int pos = input.indexOf(HexCodeFile.NEW_LINE, 0);
             int line = 1;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Sun Mar 30 16:08:33 2014 +0200
@@ -42,12 +42,18 @@
  */
 public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter {
 
+    private final boolean tryToSchedule;
+
     /**
      * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
+     * 
+     * @param tryToSchedule If false, no scheduling is done, which avoids exceptions for
+     *            non-schedulable graphs.
      */
-    public IdealGraphPrinter(OutputStream stream) {
+    public IdealGraphPrinter(OutputStream stream, boolean tryToSchedule) {
         super(stream);
         this.begin();
+        this.tryToSchedule = tryToSchedule;
     }
 
     /**
@@ -80,7 +86,7 @@
         beginGraph(title);
         Set<Node> noBlockNodes = new HashSet<>();
         SchedulePhase schedule = predefinedSchedule;
-        if (schedule == null) {
+        if (schedule == null && tryToSchedule) {
             try {
                 schedule = new SchedulePhase();
                 schedule.apply((StructuredGraph) graph);
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -51,7 +51,7 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
-    public void generate(ArithmeticLIRGenerator gen) {
-        gen.setResult(this, gen.emitFloatConvert(op, gen.operand(value)));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitFloatConvert(op, gen.operand(value)));
     }
 }
--- a/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,8 +33,7 @@
 import com.oracle.graal.nodes.calc.FloatingNode;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.spi.ArithmeticLIRGenerator;
-import com.oracle.graal.nodes.spi.ArithmeticLIRLowerable;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.StampFactory;
 
 /**
@@ -77,7 +76,7 @@
      * @param op the math operation
      */
     public HSAILMathIntrinsicsNode(ValueNode x, HSAILArithmetic op) {
-        super(StampFactory.forKind(x.kind()));
+        super(StampFactory.forKind(x.getKind()));
         this.param = x;
         this.operation = op;
     }
@@ -86,24 +85,24 @@
      * Generates the LIR instructions for the math operation represented by this node.
      */
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value input = gen.operand(getParameter());
         Value result;
         switch (operation()) {
             case ABS:
-                result = gen.emitMathAbs(input);
+                result = gen.getLIRGeneratorTool().emitMathAbs(input);
                 break;
             case CEIL:
-                result = ((HSAILLIRGenerator) (gen)).emitMathCeil(input);
+                result = ((HSAILLIRGenerator) (gen.getLIRGeneratorTool())).emitMathCeil(input);
                 break;
             case FLOOR:
-                result = ((HSAILLIRGenerator) (gen)).emitMathFloor(input);
+                result = ((HSAILLIRGenerator) (gen.getLIRGeneratorTool())).emitMathFloor(input);
                 break;
             case RINT:
-                result = ((HSAILLIRGenerator) (gen)).emitMathRint(input);
+                result = ((HSAILLIRGenerator) (gen.getLIRGeneratorTool())).emitMathRint(input);
                 break;
             case SQRT:
-                result = gen.emitMathSqrt(input);
+                result = gen.getLIRGeneratorTool().emitMathSqrt(input);
                 break;
 
             default:
@@ -175,4 +174,5 @@
      */
     @NodeIntrinsic
     public static native double compute(double value, @ConstantNodeParameter HSAILArithmetic op);
+
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,8 +29,12 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.virtual.phases.ea.*;
 
 /**
  * Tests {@link ArraysSubstitutions}.
@@ -350,4 +354,90 @@
         }
     }
 
+    @Test
+    public void testConstants() {
+        test("testConstantsSnippet");
+    }
+
+    public static final int[] constantArray1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+    public static final int[] constantArray2 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+    public static boolean testConstantsSnippet() {
+        constantArray2[0] = 10;
+        try {
+            return Arrays.equals(constantArray1, constantArray2);
+        } finally {
+            constantArray2[0] = 1;
+        }
+    }
+
+    @Test
+    public void testCanonicalLength() {
+        StructuredGraph graph = parse("testCanonicalLengthSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0);
+    }
+
+    public static final int[] constantArray3 = new int[]{1, 2, 3};
+
+    public static boolean testCanonicalLengthSnippet() {
+        return Arrays.equals(constantArray1, constantArray3);
+    }
+
+    @Test
+    public void testCanonicalEqual() {
+        StructuredGraph graph = parse("testCanonicalEqualSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1);
+    }
+
+    public static boolean testCanonicalEqualSnippet() {
+        return Arrays.equals(constantArray1, constantArray1);
+    }
+
+    @Test
+    public void testVirtualEqual() {
+        StructuredGraph graph = parse("testVirtualEqualSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1);
+    }
+
+    public static boolean testVirtualEqualSnippet() {
+        int[] array1 = new int[]{1, 2, 3, 4};
+        int[] array2 = new int[]{1, 2, 3, 4};
+        return Arrays.equals(array1, array2);
+    }
+
+    @Test
+    public void testVirtualNotEqual() {
+        StructuredGraph graph = parse("testVirtualNotEqualSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0);
+    }
+
+    public static boolean testVirtualNotEqualSnippet(int x) {
+        int[] array1 = new int[]{1, 2, 100, x};
+        int[] array2 = new int[]{1, 2, 3, 4};
+        return Arrays.equals(array1, array2);
+    }
 }
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,12 +30,16 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
 public class VerifierAnnotationProcessor extends AbstractProcessor {
 
     private List<AbstractVerifier> verifiers;
 
     @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
         if (!roundEnv.processingOver()) {
             for (AbstractVerifier verifier : getVerifiers()) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -175,7 +175,7 @@
             for (Node returnSideEffect : returnSideEffects) {
                 if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) {
                     StateSplit split = (StateSplit) returnSideEffect;
-                    if (split.getState() != null) {
+                    if (split.stateAfter() != null) {
                         split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI)));
                     }
                 }
@@ -184,7 +184,7 @@
             for (Node unwindSideEffect : unwindSideEffects) {
                 if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) {
                     StateSplit split = (StateSplit) unwindSideEffect;
-                    if (split.getState() != null) {
+                    if (split.stateAfter() != null) {
                         split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_EXCEPTION_BCI)));
                     }
                 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Sun Mar 30 16:08:33 2014 +0200
@@ -106,7 +106,7 @@
      * @param name the name of the invoked method
      * @param args the arguments to the invocation
      */
-    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
         boolean isStatic = invokeKind == InvokeKind.Static;
         ResolvedJavaMethod method = null;
         for (Method m : declaringClass.getDeclaredMethods()) {
@@ -123,7 +123,7 @@
      * 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, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
         assert Modifier.isStatic(method.getModifiers()) == (invokeKind == InvokeKind.Static);
         Signature signature = method.getSignature();
         JavaType returnType = signature.getReturnType(null);
@@ -132,12 +132,12 @@
         InvokeNode invoke = append(new InvokeNode(callTarget, bci));
 
         if (frameStateBuilder != null) {
-            if (invoke.kind() != Kind.Void) {
-                frameStateBuilder.push(invoke.kind(), invoke);
+            if (invoke.getKind() != Kind.Void) {
+                frameStateBuilder.push(invoke.getKind(), invoke);
             }
             invoke.setStateAfter(frameStateBuilder.create(0));
-            if (invoke.kind() != Kind.Void) {
-                frameStateBuilder.pop(invoke.kind());
+            if (invoke.getKind() != Kind.Void) {
+                frameStateBuilder.pop(invoke.getKind());
             }
         }
         return invoke;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -138,7 +138,7 @@
     /**
      * Converts the arguments of an invoke node to object values suitable for use as the arguments
      * to a reflective invocation of a Java constructor or method.
-     * 
+     *
      * @param folding specifies if the invocation is for handling a {@link Fold} annotation
      * @return the arguments for the reflective invocation or null if an argument of {@code invoke}
      *         that is expected to be constant isn't
@@ -326,7 +326,7 @@
 
     public void cleanUpReturnCheckCast(Node newInstance) {
         if (newInstance.recordsUsages() && newInstance instanceof ValueNode &&
-                        (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) {
+                        (((ValueNode) newInstance).getKind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) {
             StructuredGraph graph = (StructuredGraph) newInstance.graph();
             for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) {
                 for (Node checkCastUsage : checkCastNode.usages().snapshot()) {
@@ -395,7 +395,7 @@
             }
             graph.removeFixed(pi);
         } else {
-            DebugScope.dump(graph, "exception");
+            DebugScope.forceDump(graph, "exception");
             assert false : sourceLocation(usage) + " has unexpected usage " + usage + " of checkcast " + input + " at " + sourceLocation(input);
         }
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sun Mar 30 16:08:33 2014 +0200
@@ -40,6 +40,7 @@
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
@@ -99,7 +100,7 @@
                 FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal
                                 : FrameStateProcessing.CollapseFrameForSingleSideEffect;
                 StructuredGraph newGraph = makeGraph(method, recursiveEntry, recursiveEntry, inliningPolicy(method), frameStateProcessing);
-                Debug.metric(new MethodDebugValueName("SnippetNodeCount", method)).add(newGraph.getNodeCount());
+                Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount());
                 if (!UseSnippetGraphCache) {
                     return newGraph;
                 }
@@ -233,7 +234,9 @@
         } else {
             original = metaAccess.lookupJavaConstructor((Constructor) originalMember);
         }
-        Debug.log("substitution: " + MetaUtil.format("%H.%n(%p) %r", original) + " --> " + MetaUtil.format("%H.%n(%p) %r", substitute));
+        if (Debug.isLogEnabled()) {
+            Debug.log("substitution: %s --> %s", MetaUtil.format("%H.%n(%p) %r", original), MetaUtil.format("%H.%n(%p) %r", substitute));
+        }
 
         registeredMethodSubstitutions.put(original, substitute);
         return original;
@@ -340,7 +343,7 @@
 
         public StructuredGraph makeGraph(final SnippetInliningPolicy policy) {
             try (Scope s = Debug.scope("BuildSnippetGraph", method)) {
-                StructuredGraph graph = parseGraph(method, policy);
+                StructuredGraph graph = parseGraph(method, policy, 0);
 
                 // Cannot have a finalized version of a graph in the cache
                 graph = graph.copy();
@@ -380,12 +383,14 @@
             new DeadCodeEliminationPhase().apply(graph);
         }
 
-        private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
+        private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
+
+        private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy, int inliningDepth) {
             StructuredGraph graph = graphCache.get(methodToParse);
             if (graph == null) {
                 StructuredGraph newGraph = null;
                 try (Scope s = Debug.scope("ParseGraph", methodToParse)) {
-                    newGraph = buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy);
+                    newGraph = buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy, inliningDepth);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
@@ -404,7 +409,7 @@
             final StructuredGraph graph = new StructuredGraph(methodToParse);
             try (Scope s = Debug.scope("buildInitialGraph", graph)) {
                 MetaAccessProvider metaAccess = providers.getMetaAccess();
-                new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+                createGraphBuilder(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
                 new WordTypeVerificationPhase(metaAccess, target.wordKind).apply(graph);
                 new WordTypeRewriterPhase(metaAccess, target.wordKind).apply(graph);
 
@@ -417,6 +422,10 @@
             return graph;
         }
 
+        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+            return new GraphBuilderPhase.Instance(metaAccess, graphBuilderConfig, optimisticOpts);
+        }
+
         protected Object beforeInline(@SuppressWarnings("unused") MethodCallTargetNode callTarget, @SuppressWarnings("unused") StructuredGraph callee) {
             return null;
         }
@@ -445,7 +454,8 @@
             }
         }
 
-        private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
+        private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy, int inliningDepth) {
+            assert inliningDepth < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
             assert isInlinableSnippet(methodToParse) : methodToParse;
             final StructuredGraph graph = buildInitialGraph(methodToParse);
             try (Scope s = Debug.scope("buildGraph", graph)) {
@@ -477,7 +487,7 @@
                                                         " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " +
                                                         methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
                                     }
-                                    targetGraph = parseGraph(callee, policy);
+                                    targetGraph = parseGraph(callee, policy, inliningDepth + 1);
                                 }
                                 Object beforeInlineData = beforeInline(callTarget, targetGraph);
                                 InliningUtil.inline(callTarget.invoke(), targetGraph, true);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Sun Mar 30 16:08:33 2014 +0200
@@ -39,6 +39,7 @@
  * snippet specific metrics.
  */
 public class SnippetCounter implements Comparable<SnippetCounter> {
+    private static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
 
     /**
      * A group of related counters.
@@ -134,9 +135,7 @@
      */
     public void inc() {
         if (group != null) {
-            // TODO: instead of ANY_LOCATION we should actually
-            // use the location for the field "value".
-            DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, LocationIdentity.ANY_LOCATION);
+            DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, SNIPPET_COUNTER_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.debug.Debug.*;
+import static java.util.FormattableFlags.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -97,8 +99,8 @@
 
         protected SnippetInfo(ResolvedJavaMethod method) {
             this.method = method;
-            instantiationCounter = Debug.metric(new MethodDebugValueName("SnippetInstantiationCount", method));
-            instantiationTimer = Debug.timer(new MethodDebugValueName("SnippetInstantiationTime", method));
+            instantiationCounter = Debug.metric("SnippetInstantiationCount[%s]", method);
+            instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", method);
             assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + MetaUtil.format("%H.%n", method);
             int count = method.getSignature().getParameterCount(false);
             constantParameters = new boolean[count];
@@ -176,7 +178,7 @@
      * {@link SnippetTemplate#instantiate instantiated}
      * </ul>
      */
-    public static class Arguments {
+    public static class Arguments implements Formattable {
 
         protected final SnippetInfo info;
         protected final CacheKey cacheKey;
@@ -243,6 +245,30 @@
             result.append(">");
             return result.toString();
         }
+
+        public void formatTo(Formatter formatter, int flags, int width, int precision) {
+            if ((flags & ALTERNATE) == 0) {
+                formatter.format(applyFormattingFlagsAndWidth(toString(), flags, width));
+            } else {
+                StringBuilder sb = new StringBuilder();
+                sb.append(info.method.getName()).append('(');
+                String sep = "";
+                for (int i = 0; i < info.getParameterCount(); i++) {
+                    if (info.isConstantParameter(i)) {
+                        sb.append(sep);
+                        if (info.names[i] != null) {
+                            sb.append(info.names[i]);
+                        } else {
+                            sb.append(i);
+                        }
+                        sb.append('=').append(values[i]);
+                        sep = ", ";
+                    }
+                }
+                sb.append(")");
+                formatter.format(applyFormattingFlagsAndWidth(sb.toString(), flags & ~ALTERNATE, width));
+            }
+        }
     }
 
     /**
@@ -440,38 +466,13 @@
         return false;
     }
 
-    private static String debugValueName(String category, Arguments args) {
-        if (Debug.isEnabled()) {
-            StringBuilder result = new StringBuilder(category).append('[');
-            SnippetInfo info = args.info;
-            result.append(info.method.getName()).append('(');
-            String sep = "";
-            for (int i = 0; i < info.getParameterCount(); i++) {
-                if (info.isConstantParameter(i)) {
-                    result.append(sep);
-                    if (info.names[i] != null) {
-                        result.append(info.names[i]);
-                    } else {
-                        result.append(i);
-                    }
-                    result.append('=').append(args.values[i]);
-                    sep = ", ";
-                }
-            }
-            result.append(")]");
-            return result.toString();
-
-        }
-        return null;
-    }
-
     /**
      * Creates a snippet template.
      */
     protected SnippetTemplate(final Providers providers, Arguments args) {
         StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method);
-        instantiationTimer = Debug.timer(debugValueName("SnippetTemplateInstantiationTime", args));
-        instantiationCounter = Debug.metric(debugValueName("SnippetTemplateInstantiationCount", args));
+        instantiationTimer = Debug.timer("SnippetTemplateInstantiationTime[%#s]", args);
+        instantiationCounter = Debug.metric("SnippetTemplateInstantiationCount[%#s]", args);
 
         ResolvedJavaMethod method = snippetGraph.method();
         Signature signature = method.getSignature();
@@ -665,7 +666,7 @@
             }
         }
 
-        Debug.metric(debugValueName("SnippetTemplateNodeCount", args)).add(nodes.size());
+        Debug.metric("SnippetTemplateNodeCount[%#s]", args).add(nodes.size());
         args.info.notifyNewTemplate();
         Debug.dump(snippet, "SnippetTemplate final state");
     }
@@ -727,8 +728,8 @@
     private final ArrayList<StateSplit> sideEffectNodes;
 
     /**
-     * Nodes that inherit the {@link DeoptimizingNode#getDeoptimizationState()} from the replacee
-     * during instantiation.
+     * Nodes that inherit a deoptimization {@link FrameState} from the replacee during
+     * instantiation.
      */
     private final ArrayList<DeoptimizingNode> deoptNodes;
 
@@ -777,7 +778,7 @@
                 if (argument instanceof ValueNode) {
                     replacements.put((ParameterNode) parameter, (ValueNode) argument);
                 } else {
-                    Kind kind = ((ParameterNode) parameter).kind();
+                    Kind kind = ((ParameterNode) parameter).getKind();
                     assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + args.info.names[i];
                     Constant constant = forBoxed(argument, kind);
                     replacements.put((ParameterNode) parameter, ConstantNode.forConstant(constant, metaAccess, replaceeGraph));
@@ -804,7 +805,7 @@
                     if (value instanceof ValueNode) {
                         replacements.put(param, (ValueNode) value);
                     } else {
-                        Constant constant = forBoxed(value, param.kind());
+                        Constant constant = forBoxed(value, param.getKind());
                         ConstantNode element = ConstantNode.forConstant(constant, metaAccess, replaceeGraph);
                         replacements.put(param, element);
                     }
@@ -1023,11 +1024,50 @@
 
             if (replacee instanceof DeoptimizingNode) {
                 DeoptimizingNode replaceeDeopt = (DeoptimizingNode) replacee;
-                FrameState state = replaceeDeopt.getDeoptimizationState();
+
+                FrameState stateBefore = null;
+                FrameState stateDuring = null;
+                FrameState stateAfter = null;
+                if (replaceeDeopt.canDeoptimize()) {
+                    if (replaceeDeopt instanceof DeoptimizingNode.DeoptBefore) {
+                        stateBefore = ((DeoptimizingNode.DeoptBefore) replaceeDeopt).stateBefore();
+                    }
+                    if (replaceeDeopt instanceof DeoptimizingNode.DeoptDuring) {
+                        stateDuring = ((DeoptimizingNode.DeoptDuring) replaceeDeopt).stateDuring();
+                    }
+                    if (replaceeDeopt instanceof DeoptimizingNode.DeoptAfter) {
+                        stateAfter = ((DeoptimizingNode.DeoptAfter) replaceeDeopt).stateAfter();
+                    }
+                }
+
                 for (DeoptimizingNode deoptNode : deoptNodes) {
                     DeoptimizingNode deoptDup = (DeoptimizingNode) duplicates.get(deoptNode);
-                    assert replaceeDeopt.canDeoptimize() || !deoptDup.canDeoptimize();
-                    deoptDup.setDeoptimizationState(state);
+                    if (deoptDup.canDeoptimize()) {
+                        if (deoptDup instanceof DeoptimizingNode.DeoptBefore) {
+                            ((DeoptimizingNode.DeoptBefore) deoptDup).setStateBefore(stateBefore);
+                        }
+                        if (deoptDup instanceof DeoptimizingNode.DeoptDuring) {
+                            DeoptimizingNode.DeoptDuring deoptDupDuring = (DeoptimizingNode.DeoptDuring) deoptDup;
+                            if (stateDuring != null) {
+                                deoptDupDuring.setStateDuring(stateDuring);
+                            } else if (stateAfter != null) {
+                                deoptDupDuring.computeStateDuring(stateAfter);
+                            } else if (stateBefore != null) {
+                                assert !deoptDupDuring.hasSideEffect() : "can't use stateBefore as stateDuring for state split " + deoptDupDuring;
+                                deoptDupDuring.setStateDuring(stateBefore);
+                            }
+                        }
+                        if (deoptDup instanceof DeoptimizingNode.DeoptAfter) {
+                            DeoptimizingNode.DeoptAfter deoptDupAfter = (DeoptimizingNode.DeoptAfter) deoptDup;
+                            if (stateAfter != null) {
+                                deoptDupAfter.setStateAfter(stateAfter);
+                            } else {
+                                assert !deoptDupAfter.hasSideEffect() : "can't use stateBefore as stateAfter for state split " + deoptDupAfter;
+                                deoptDupAfter.setStateAfter(stateBefore);
+                            }
+
+                        }
+                    }
                 }
             }
 
@@ -1171,10 +1211,10 @@
                 buf.append("<constant> ").append(name);
             } else if (value instanceof ParameterNode) {
                 ParameterNode param = (ParameterNode) value;
-                buf.append(param.kind().getJavaName()).append(' ').append(name);
+                buf.append(param.getKind().getJavaName()).append(' ').append(name);
             } else {
                 ParameterNode[] params = (ParameterNode[]) value;
-                String kind = params.length == 0 ? "?" : params[0].kind().getJavaName();
+                String kind = params.length == 0 ? "?" : params[0].getKind().getJavaName();
                 buf.append(kind).append('[').append(params.length).append("] ").append(name);
             }
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,6 +30,8 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.replacements.nodes.*;
 
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
 /**
  * Substitutions for {@link java.lang.String} methods.
  */
@@ -51,6 +53,7 @@
     }
 
     @MethodSubstitution(isStatic = false)
+    @SuppressFBWarnings(value = "ES_COMPARING_PARAMETER_STRING_WITH_EQ", justification = "reference equality on the receiver is what we want")
     public static boolean equals(final String thisString, Object obj) {
         if (thisString == obj) {
             return true;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
@@ -31,12 +29,14 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * Compares two arrays with the same length.
  */
-public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable {
+public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable {
 
     /** {@link Kind} of the arrays to compare. */
     private final Kind kind;
@@ -65,42 +65,45 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (!array1.isConstant() || !array2.isConstant()) {
-            return this;
+        if (usages().isEmpty()) {
+            return null;
         }
+        if (GraphUtil.unproxify(array1) == GraphUtil.unproxify(array2)) {
+            return ConstantNode.forBoolean(true, graph());
+        }
+        return this;
+    }
 
-        Object a1 = array1.asConstant().asObject();
-        Object a2 = array2.asConstant().asObject();
-        boolean x;
-        switch (kind) {
-            case Boolean:
-                x = Arrays.equals((boolean[]) a1, (boolean[]) a2);
-                break;
-            case Byte:
-                x = Arrays.equals((byte[]) a1, (byte[]) a2);
-                break;
-            case Char:
-                x = Arrays.equals((char[]) a1, (char[]) a2);
-                break;
-            case Short:
-                x = Arrays.equals((short[]) a1, (short[]) a2);
-                break;
-            case Int:
-                x = Arrays.equals((int[]) a1, (int[]) a2);
-                break;
-            case Long:
-                x = Arrays.equals((long[]) a1, (long[]) a2);
-                break;
-            case Float:
-                x = Arrays.equals((float[]) a1, (float[]) a2);
-                break;
-            case Double:
-                x = Arrays.equals((double[]) a1, (double[]) a2);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("unknown kind " + kind);
+    public void virtualize(VirtualizerTool tool) {
+        State state1 = tool.getObjectState(array1);
+        if (state1 != null) {
+            State state2 = tool.getObjectState(array2);
+            if (state2 != null) {
+                if (state1.getVirtualObject() == state2.getVirtualObject()) {
+                    // the same virtual objects will always have the same contents
+                    tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
+                } else if (state1.getVirtualObject().entryCount() == state2.getVirtualObject().entryCount()) {
+                    int entryCount = state1.getVirtualObject().entryCount();
+                    boolean allEqual = true;
+                    for (int i = 0; i < entryCount; i++) {
+                        ValueNode entry1 = state1.getEntry(i);
+                        ValueNode entry2 = state2.getEntry(i);
+                        if (entry1 != entry2) {
+                            // the contents might be different
+                            allEqual = false;
+                        }
+                        if (entry1.stamp().alwaysDistinct(entry2.stamp())) {
+                            // the contents are different
+                            tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
+                            return;
+                        }
+                    }
+                    if (allEqual) {
+                        tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
+                    }
+                }
+            }
         }
-        return ConstantNode.forBoolean(x, graph());
     }
 
     @NodeIntrinsic
@@ -128,7 +131,7 @@
     public static native boolean equals(double[] array1, double[] array2, int length);
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGenerator gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -65,7 +65,7 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGenerator gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitCount(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGenerator gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitScanForward(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -79,9 +79,9 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
+    public void generate(NodeLIRGenerator gen) {
         Variable result = gen.newVariable(Kind.Int);
-        gen.emitBitScanReverse(result, gen.operand(value));
+        gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -58,8 +58,8 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, value.kind(), displacement, offset, graph(), 1);
-        WriteNode write = graph().add(new WriteNode(object, value, location, BarrierType.NONE, value.kind() == Kind.Object));
+        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, value.getKind(), displacement, offset, graph(), 1);
+        WriteNode write = graph().add(new WriteNode(object, value, location, BarrierType.NONE, value.getKind() == Kind.Object));
         graph().replaceFixedWithFixed(this, write);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -46,8 +46,8 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), null));
+    public void generate(NodeLIRGeneratorTool gen) {
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, gen.operand(address), null));
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -48,9 +48,9 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value v = gen.operand(value);
-        gen.emitStore(kind, gen.operand(address), v, null);
+        gen.getLIRGeneratorTool().emitStore(kind, gen.operand(address), v, null);
     }
 
     /*
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -159,7 +159,7 @@
         InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci));
         if (stateAfter() != null) {
             invoke.setStateAfter(stateAfter().duplicate());
-            if (kind() != Kind.Void) {
+            if (getKind() != Kind.Void) {
                 invoke.stateAfter().replaceFirstInput(this, invoke);
             }
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -55,30 +55,30 @@
     }
 
     @Override
-    public void generate(ArithmeticLIRGenerator gen) {
+    public void generate(NodeLIRGeneratorTool gen) {
         Value input = gen.operand(x());
         Value result;
         switch (operation()) {
             case ABS:
-                result = gen.emitMathAbs(input);
+                result = gen.getLIRGeneratorTool().emitMathAbs(input);
                 break;
             case SQRT:
-                result = gen.emitMathSqrt(input);
+                result = gen.getLIRGeneratorTool().emitMathSqrt(input);
                 break;
             case LOG:
-                result = gen.emitMathLog(input, false);
+                result = gen.getLIRGeneratorTool().emitMathLog(input, false);
                 break;
             case LOG10:
-                result = gen.emitMathLog(input, true);
+                result = gen.getLIRGeneratorTool().emitMathLog(input, true);
                 break;
             case SIN:
-                result = gen.emitMathSin(input);
+                result = gen.getLIRGeneratorTool().emitMathSin(input);
                 break;
             case COS:
-                result = gen.emitMathCos(input);
+                result = gen.getLIRGeneratorTool().emitMathCos(input);
                 break;
             case TAN:
-                result = gen.emitMathTan(input);
+                result = gen.getLIRGeneratorTool().emitMathTan(input);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -88,7 +88,7 @@
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
-        return Constant.forDouble(compute(inputs[0].asDouble(), operation()));
+        return Constant.forDouble(doCompute(inputs[0].asDouble(), operation()));
     }
 
     @Override
@@ -101,6 +101,10 @@
 
     @NodeIntrinsic
     public static double compute(double value, @ConstantNodeParameter Operation op) {
+        return doCompute(value, op);
+    }
+
+    private static double doCompute(double value, Operation op) throws GraalInternalError {
         switch (op) {
             case ABS:
                 return Math.abs(value);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,17 +24,16 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Access the value of a specific register.
  */
 @NodeInfo(nameTemplate = "ReadRegister %{p#register}")
-public final class ReadRegisterNode extends FixedWithNextNode implements LIRGenLowerable {
+public final class ReadRegisterNode extends FixedWithNextNode implements LIRLowerable {
 
     /**
      * The fixed register to access.
@@ -75,13 +74,13 @@
     }
 
     @Override
-    public void generate(LIRGenerator generator) {
-        Value result = register.asValue(kind());
+    public void generate(NodeLIRGeneratorTool generator) {
+        Value result = register.asValue(getKind());
         if (incoming) {
-            generator.emitIncomingValues(new Value[]{result});
+            generator.getLIRGeneratorTool().emitIncomingValues(new Value[]{result});
         }
         if (!directUse) {
-            result = generator.emitMove(result);
+            result = generator.getLIRGeneratorTool().emitMove(result);
         }
         generator.setResult(this, result);
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -37,8 +37,8 @@
     @Input private ValueNode value;
 
     public ReverseBytesNode(ValueNode value) {
-        super(StampFactory.forKind(value.kind()));
-        assert kind().isNumericInteger();
+        super(StampFactory.forKind(value.getKind()));
+        assert getKind().isNumericInteger();
         this.value = value;
     }
 
@@ -46,9 +46,9 @@
     public Node canonical(CanonicalizerTool tool) {
         if (value.isConstant()) {
             long v = value.asConstant().asLong();
-            if (kind().getStackKind() == Kind.Int) {
+            if (getKind().getStackKind() == Kind.Int) {
                 return ConstantNode.forInt(Integer.reverseBytes((int) v), graph());
-            } else if (kind() == Kind.Long) {
+            } else if (getKind() == Kind.Long) {
                 return ConstantNode.forLong(Long.reverseBytes(v), graph());
             }
         }
@@ -66,9 +66,9 @@
     }
 
     @Override
-    public void generate(LIRGenerator gen) {
-        Variable result = gen.newVariable(value.kind());
-        gen.emitByteSwap(result, gen.operand(value));
+    public void generate(NodeLIRGenerator gen) {
+        Variable result = gen.newVariable(value.getKind());
+        gen.getLIRGenerator().emitByteSwap(result, gen.operand(value));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -52,9 +52,9 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         Value val = generator.operand(value);
-        generator.emitMove(register.asValue(val.getKind()), val);
+        generator.getLIRGeneratorTool().emitMove(register.asValue(val.getKind()), val);
     }
 
     @Override
--- a/graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java	Sun Mar 30 16:08:33 2014 +0200
@@ -34,12 +34,16 @@
 
 import com.oracle.graal.api.runtime.*;
 
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
 @SupportedAnnotationTypes("com.oracle.graal.api.runtime.ServiceProvider")
 public class ServiceProviderProcessor extends AbstractProcessor {
 
     private final Set<TypeElement> processed = new HashSet<>();
 
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
     private boolean verifyAnnotation(TypeMirror serviceInterface, TypeElement serviceProvider) {
         if (!processingEnv.getTypeUtils().isSubtype(serviceProvider.asType(), serviceInterface)) {
             String msg = String.format("Service provider class %s doesn't implement service interface %s", serviceProvider.getSimpleName(), serviceInterface);
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -48,6 +48,15 @@
                 found = m;
             }
         }
+        if (found == null) {
+            /* Now look for non-public methods (but this does not look in superclasses). */
+            for (Method m : clazz.getDeclaredMethods()) {
+                if (m.getName().equals(methodName)) {
+                    Assert.assertNull(found);
+                    found = m;
+                }
+            }
+        }
         if (found != null) {
             return found;
         } else {
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -62,7 +62,7 @@
         @Child private AbstractTestNode child;
 
         public CatchControlFlowExceptionTestNode(AbstractTestNode child) {
-            this.child = adoptChild(child);
+            this.child = child;
         }
 
         @Override
@@ -80,7 +80,7 @@
         @Child private AbstractTestNode child;
 
         public CatchSlowPathAndControlFlowExceptionTestNode(AbstractTestNode child) {
-            this.child = adoptChild(child);
+            this.child = child;
         }
 
         @Override
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -85,7 +85,7 @@
     }
 
     protected StructuredGraph partialEval(RootNode root, Arguments arguments, final Assumptions assumptions, final boolean canonicalizeReads) {
-        final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
+        final OptimizedCallTargetImpl compilable = (OptimizedCallTargetImpl) Truffle.getRuntime().createCallTarget(root);
 
         // Executed AST so that all classes are loaded and initialized.
         compilable.call(null, arguments);
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/AddTestNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/AddTestNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,8 +30,8 @@
     @Child private AbstractTestNode right;
 
     public AddTestNode(AbstractTestNode left, AbstractTestNode right) {
-        this.left = adoptChild(left);
-        this.right = adoptChild(right);
+        this.left = left;
+        this.right = right;
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,7 +30,7 @@
     @Children private final AbstractTestNode[] statements;
 
     public BlockTestNode(AbstractTestNode[] statements) {
-        this.statements = adoptChildren(statements);
+        this.statements = statements;
     }
 
     @ExplodeLoop
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LoopTestNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LoopTestNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -31,7 +31,7 @@
 
     public LoopTestNode(int numberOfIterations, AbstractTestNode child) {
         this.numberOfIterations = numberOfIterations;
-        this.child = adoptChild(child);
+        this.child = child;
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Sun Mar 30 16:08:33 2014 +0200
@@ -132,11 +132,18 @@
         ensureProfiling(reprofile, reprofile);
     }
 
-    void reportInterpreterCall() {
+    public void reportInterpreterCall() {
         callCount++;
         callAndLoopCount++;
     }
 
+    void reportInlinedCall() {
+        callCount++;
+        callAndLoopCount++;
+        compilationCallThreshold++;
+        compilationCallAndLoopThreshold++;
+    }
+
     void reportInterpreterCalls(int calls) {
         this.callCount += calls;
         this.callAndLoopCount += calls;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Sun Mar 30 16:08:33 2014 +0200
@@ -55,7 +55,7 @@
 
     @Override
     public <T extends Arguments> T getArguments(Class<T> clazz) {
-        return CompilerDirectives.unsafeCast(arguments, clazz, true);
+        return CompilerDirectives.unsafeCast(arguments, clazz, true, true);
     }
 
     @Override
@@ -85,15 +85,15 @@
     }
 
     private Object[] getLocals() {
-        return CompilerDirectives.unsafeCast(locals, Object[].class, true);
+        return CompilerDirectives.unsafeCast(locals, Object[].class, true, true);
     }
 
     private long[] getPrimitiveLocals() {
-        return CompilerDirectives.unsafeCast(this.primitiveLocals, long[].class, true);
+        return CompilerDirectives.unsafeCast(this.primitiveLocals, long[].class, true, true);
     }
 
     private byte[] getTags() {
-        return CompilerDirectives.unsafeCast(tags, byte[].class, true);
+        return CompilerDirectives.unsafeCast(tags, byte[].class, true, true);
     }
 
     private Object getObjectUnsafe(FrameSlot slot) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Sun Mar 30 16:08:33 2014 +0200
@@ -77,7 +77,7 @@
         if (truffleCompiler == null) {
             truffleCompiler = new TruffleCompilerImpl();
         }
-        return new OptimizedCallTarget(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode));
+        return new OptimizedCallTargetImpl(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode));
     }
 
     public CallNode createCallNode(CallTarget target) {
@@ -90,7 +90,7 @@
 
     @Override
     public VirtualFrame createVirtualFrame(PackedFrame caller, Arguments arguments, FrameDescriptor frameDescriptor) {
-        return OptimizedCallTarget.createFrame(frameDescriptor, caller, arguments);
+        return OptimizedCallTargetImpl.createFrame(frameDescriptor, caller, arguments);
     }
 
     @Override
@@ -173,7 +173,7 @@
     private static Method getCallMethod() {
         Method method;
         try {
-            method = OptimizedCallTarget.class.getDeclaredMethod("call", new Class[]{PackedFrame.class, Arguments.class});
+            method = OptimizedCallTargetImpl.class.getDeclaredMethod("call", new Class[]{PackedFrame.class, Arguments.class});
         } catch (NoSuchMethodException | SecurityException e) {
             throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle;
 
 import java.util.*;
-import java.util.concurrent.atomic.*;
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
@@ -34,7 +33,7 @@
 /**
  * Call target that is optimized by Graal upon surpassing a specific invocation threshold.
  */
-abstract class OptimizedCallNode extends DefaultCallNode {
+public abstract class OptimizedCallNode extends DefaultCallNode {
 
     protected int callCount;
 
@@ -79,7 +78,7 @@
             throw new IllegalStateException("CallNode must be adopted before it is split.");
         }
 
-        return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), getCurrentCallTarget().getRootNode(), callCount));
+        return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), callCount));
     }
 
     public static OptimizedCallNode create(OptimizedCallTarget target) {
@@ -126,17 +125,11 @@
             if (!isSplittable()) {
                 return false;
             }
-            int nodeCount = NodeUtil.countNodes(getCallTarget().getRootNode(), null, false);
+            int nodeCount = NodeUtil.countNodes(getCallTarget().getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, false);
             if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) {
                 return false;
             }
 
-            // // is the only call target -> do not split
-            // if (getCallTarget().getRootNode().getCachedCallNodes().size() == 1 &&
-            // getCallTarget().getRootNode().getCachedCallNodes().contains(this)) {
-            // return false;
-            // }
-
             // disable recursive splitting for now
             OptimizedCallTarget splitTarget = getCallTarget();
             List<OptimizedCallTarget> compilationRoots = OptimizedCallNodeProfile.findCompilationRoots(this);
@@ -160,17 +153,11 @@
         }
 
         private boolean isMaxSingleCall() {
-            final AtomicInteger count = new AtomicInteger(0);
-            getCurrentCallTarget().getRootNode().accept(new NodeVisitor() {
-
-                public boolean visit(Node node) {
-                    if (node instanceof CallNode) {
-                        return count.incrementAndGet() > 1;
-                    }
-                    return true;
+            return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() {
+                public boolean isCounted(Node node) {
+                    return node instanceof CallNode;
                 }
-            });
-            return count.get() <= 1;
+            }) <= 1;
         }
 
         private int countPolymorphic() {
@@ -224,12 +211,10 @@
 
     private static final class InlinedOptimizedCallNode extends OptimizedCallNode {
 
-        private final RootNode inlinedRoot;
         private final OptimizedCallTarget splittedTarget;
 
-        public InlinedOptimizedCallNode(OptimizedCallTarget target, OptimizedCallTarget splittedTarget, RootNode inlinedRoot, int callCount) {
+        public InlinedOptimizedCallNode(OptimizedCallTarget target, OptimizedCallTarget splittedTarget, int callCount) {
             super(target);
-            this.inlinedRoot = inlinedRoot;
             this.splittedTarget = splittedTarget;
             this.callCount = callCount;
         }
@@ -239,7 +224,7 @@
             if (CompilerDirectives.inInterpreter()) {
                 callCount++;
             }
-            return inlinedRoot.execute(Truffle.getRuntime().createVirtualFrame(caller, arguments, inlinedRoot.getFrameDescriptor()));
+            return getCurrentCallTarget().callInlined(caller, arguments);
         }
 
         @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,11 +27,13 @@
 import java.util.*;
 
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeUtil.*;
 
 public class OptimizedCallNodeProfile implements TruffleInliningProfile {
 
+    static final CountFilter COUNT_FILTER = new CountFilter();
+
     private static final String REASON_RECURSION = "recursion";
-    private static final String REASON_FREQUENCY_CUTOFF = "frequency < " + TruffleInliningMinFrequency.getValue();
     private static final String REASON_MAXIMUM_NODE_COUNT = "shallowTargetCount  > " + TruffleInliningMaxCalleeSize.getValue();
     private static final String REASON_MAXIMUM_TOTAL_NODE_COUNT = "inlinedTotalCount > " + TruffleInliningMaxCallerSize.getValue();
 
@@ -43,17 +45,34 @@
     private final int targetShallowNodeCount;
     private final double averageFrequency;
     private final double score;
+    private final boolean leaf;
     private String reason;
 
     public OptimizedCallNodeProfile(OptimizedCallTarget target, OptimizedCallNode callNode) {
         this.callNode = callNode;
         RootNode inlineRoot = callNode.getCurrentCallTarget().getRootNode();
         this.callTarget = target;
-        this.targetShallowNodeCount = NodeUtil.countNodes(inlineRoot, null, false);
-        this.targetDeepNodeCount = NodeUtil.countNodes(inlineRoot, null, true);
+        this.targetShallowNodeCount = NodeUtil.countNodes(inlineRoot, COUNT_FILTER, false);
+        this.targetDeepNodeCount = NodeUtil.countNodes(inlineRoot, COUNT_FILTER, true);
         this.compilationRoots = findCompilationRoots(callNode);
         this.averageFrequency = calculateFrequency();
         this.score = calculateScore();
+        this.leaf = calculateLeaf();
+
+    }
+
+    private boolean calculateLeaf() {
+        return NodeUtil.countNodes(callNode.getCurrentRootNode(), new NodeCountFilter() {
+            public boolean isCounted(Node node) {
+                if (node instanceof CallNode) {
+                    CallNode childCall = (CallNode) node;
+                    if (!childCall.isInlined()) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }, true) <= 0;
     }
 
     private double calculateFrequency() {
@@ -69,7 +88,7 @@
     }
 
     public double calculateScore() {
-        return averageFrequency / targetDeepNodeCount;
+        return averageFrequency / Math.max(1, targetDeepNodeCount);
     }
 
     public boolean isInliningAllowed() {
@@ -84,18 +103,12 @@
             }
         }
 
-        // frequency cut-off
-        if (averageFrequency < TruffleInliningMinFrequency.getValue() && targetDeepNodeCount > TruffleInliningTrivialSize.getValue()) {
-            reason = REASON_FREQUENCY_CUTOFF;
-            return false;
-        }
-
         if (targetShallowNodeCount > TruffleInliningMaxCalleeSize.getValue()) {
             reason = REASON_MAXIMUM_NODE_COUNT;
             return false;
         }
 
-        this.targetDeepNodeCount = NodeUtil.countNodes(inlineTarget.getRootNode(), null, true);
+        this.targetDeepNodeCount = NodeUtil.countNodes(inlineTarget.getRootNode(), COUNT_FILTER, true);
         // The maximum total node count cannot be cached since it may change during inlining.
         int nextNodeCount = calculateInlinedTotalNodeCount(getCallNode());
         if (nextNodeCount > TruffleInliningMaxCallerSize.getValue()) {
@@ -116,6 +129,20 @@
         return currentNodeCount;
     }
 
+    static class CountFilter implements NodeCountFilter {
+        public boolean isCounted(Node node) {
+            return countNode(node) >= 1;
+        }
+    }
+
+    static int countNode(Node node) {
+        NodeCost cost = node.getCost();
+        if (cost != null && cost != NodeCost.NONE && cost != NodeCost.UNINITIALIZED) {
+            return 1;
+        }
+        return 0;
+    }
+
     private static class TotalNodeCountVisitor implements NodeVisitor {
 
         private final OptimizedCallNode inlinedNode;
@@ -129,7 +156,7 @@
         }
 
         public boolean visit(Node node) {
-            count++;
+            count += countNode(node);
             if (node instanceof OptimizedCallNode) {
                 OptimizedCallNode callNode = ((OptimizedCallNode) node);
                 if (callNode == inlinedNode) {
@@ -178,17 +205,13 @@
         for (OptimizedCallNode c : callStack) {
             int childCallCount = c.getCallCount();
             frequency *= childCallCount / (double) parentCallCount;
-            if (c.isInlined() || c.isSplit()) {
-                parentCallCount = childCallCount;
-            } else {
-                parentCallCount = c.getCurrentCallTarget().getCompilationProfile().getCallCount();
-            }
+            parentCallCount = c.getCurrentCallTarget().getCompilationProfile().getCallCount();
         }
         return frequency;
     }
 
     double calculateSimpleFrequency() {
-        return callNode.getCallCount() / (double) callTarget.getCompilationProfile().getCallCount();
+        return callNode.getCallCount() / (double) ((OptimizedCallTarget) callNode.getRootNode().getCallTarget()).getCompilationProfile().getCallCount();
     }
 
     static List<OptimizedCallTarget> findCompilationRoots(Node call) {
@@ -208,7 +231,11 @@
 
     public int compareTo(TruffleInliningProfile o) {
         if (o instanceof OptimizedCallNodeProfile) {
-            return Double.compare(((OptimizedCallNodeProfile) o).getScore(), getScore());
+            int cmp = Boolean.compare(((OptimizedCallNodeProfile) o).leaf, leaf);
+            if (cmp == 0) {
+                return Double.compare(((OptimizedCallNodeProfile) o).getScore(), getScore());
+            }
+            return cmp;
         }
         return 0;
     }
@@ -221,7 +248,7 @@
         properties.put("inlinedTotalCount", calculateInlinedTotalNodeCount(getCallNode()));
         properties.put("score", score);
         properties.put("frequency", averageFrequency);
-        properties.put("callCount", callNode.getCallCount());
+        properties.put("leaf", leaf);
         properties.put("reason", reason);
         return properties;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Sun Mar 30 16:08:33 2014 +0200
@@ -26,7 +26,6 @@
 
 import java.io.*;
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
@@ -39,34 +38,27 @@
 /**
  * Call target that is optimized by Graal upon surpassing a specific invocation threshold.
  */
-public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, ReplaceObserver {
+public abstract class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, ReplaceObserver {
 
-    private static final PrintStream OUT = TTY.out().out();
+    protected static final PrintStream OUT = TTY.out().out();
 
-    private InstalledCode installedCode;
-    private Future<InstalledCode> installedCodeTask;
-    private boolean compilationEnabled;
+    protected InstalledCode installedCode;
+    protected boolean compilationEnabled;
     private boolean inlined;
-    private int callCount;
+    protected int callCount;
 
-    private final TruffleCompiler compiler;
-    private final CompilationProfile compilationProfile;
-    private final CompilationPolicy compilationPolicy;
-    private final SpeculationLog speculationLog = new SpeculationLog();
+    protected final CompilationProfile compilationProfile;
+    protected final CompilationPolicy compilationPolicy;
+    private SpeculationLog speculationLog = new SpeculationLog();
     private OptimizedCallTarget splitSource;
 
-    OptimizedCallTarget(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) {
+    public OptimizedCallTarget(RootNode rootNode, int invokeCounter, int compilationThreshold, boolean compilationEnabled, CompilationPolicy compilationPolicy) {
         super(rootNode);
-        this.compiler = compiler;
-        this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString());
 
-        if (TruffleUseTimeForCompilationDecision.getValue()) {
-            compilationPolicy = new TimedCompilationPolicy();
-        } else {
-            compilationPolicy = new DefaultCompilationPolicy();
-        }
         this.compilationEnabled = compilationEnabled;
+        this.compilationPolicy = compilationPolicy;
 
+        this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString());
         if (TruffleCallTargetProfiling.getValue()) {
             registerCallTarget(this);
         }
@@ -92,87 +84,18 @@
         return superString;
     }
 
-    public boolean isOptimized() {
-        return installedCode != null || installedCodeTask != null;
-    }
-
-    @CompilerDirectives.SlowPath
-    @Override
-    public Object call(PackedFrame caller, Arguments args) {
-        return callHelper(caller, args);
-    }
-
-    private Object callHelper(PackedFrame caller, Arguments args) {
-        if (installedCode != null && installedCode.isValid()) {
-            reinstallCallMethodShortcut();
-        }
-        if (TruffleCallTargetProfiling.getValue()) {
-            callCount++;
-        }
-        if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, installedCode != null)) {
-            try {
-                return installedCode.execute(this, caller, args);
-            } catch (InvalidInstalledCodeException ex) {
-                return compiledCodeInvalidated(caller, args);
-            }
-        } else {
-            return interpreterCall(caller, args);
-        }
-    }
-
-    private static void reinstallCallMethodShortcut() {
-        if (TraceTruffleCompilation.getValue()) {
-            OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut.");
-        }
-        GraalTruffleRuntime.installOptimizedCallTargetCallMethod();
-    }
-
     public CompilationProfile getCompilationProfile() {
         return compilationProfile;
     }
 
-    private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) {
-        invalidate(null, null, "Compiled code invalidated");
-        return call(caller, args);
-    }
-
-    private void invalidate(Node oldNode, Node newNode, CharSequence reason) {
-        InstalledCode m = this.installedCode;
-        if (m != null) {
-            CompilerAsserts.neverPartOfCompilation();
-            installedCode = null;
-            compilationProfile.reportInvalidated();
-            logOptimizedInvalidated(this, oldNode, newNode, reason);
-        }
-        cancelInstalledTask(oldNode, newNode, reason);
-    }
+    @Override
+    public abstract Object call(PackedFrame caller, Arguments args);
 
-    private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) {
-        Future<InstalledCode> task = this.installedCodeTask;
-        if (task != null) {
-            task.cancel(true);
-            this.installedCodeTask = null;
-            logOptimizingUnqueued(this, oldNode, newNode, reason);
-            compilationProfile.reportInvalidated();
+    public Object callInlined(PackedFrame caller, Arguments arguments) {
+        if (CompilerDirectives.inInterpreter()) {
+            compilationProfile.reportInlinedCall();
         }
-    }
-
-    private Object interpreterCall(PackedFrame caller, Arguments args) {
-        CompilerAsserts.neverPartOfCompilation();
-        compilationProfile.reportInterpreterCall();
-
-        if (compilationEnabled && compilationPolicy.shouldCompile(compilationProfile)) {
-            InstalledCode code = compile();
-            if (code != null && code.isValid()) {
-                this.installedCode = code;
-                try {
-                    return code.execute(this, caller, args);
-                } catch (InvalidInstalledCodeException ex) {
-                    return compiledCodeInvalidated(caller, args);
-                }
-            }
-        }
-        return executeHelper(caller, args);
+        return executeHelper(caller, arguments);
     }
 
     public void performInlining() {
@@ -196,8 +119,8 @@
         while (callSite != null) {
             if (callSite.isInliningAllowed()) {
                 OptimizedCallNode callNode = callSite.getCallNode();
+                RootNode inlinedRoot = callNode.inlineImpl().getCurrentRootNode();
                 logInlined(this, callSite);
-                RootNode inlinedRoot = callNode.inlineImpl().getCurrentRootNode();
                 assert inlinedRoot != null;
                 queueCallSitesForInlining(this, inlinedRoot, visitedCallNodes, queue);
             } else {
@@ -227,61 +150,22 @@
         });
     }
 
-    private boolean isCompiling() {
-        Future<InstalledCode> codeTask = this.installedCodeTask;
-        if (codeTask != null) {
-            if (codeTask.isCancelled()) {
-                installedCodeTask = null;
-                return false;
-            }
-            return true;
-        }
-        return false;
+    protected boolean shouldCompile() {
+        return compilationPolicy.shouldCompile(compilationProfile);
     }
 
-    public InstalledCode compile() {
-        if (isCompiling()) {
-            if (installedCodeTask.isDone()) {
-                return receiveInstalledCode();
-            }
-            return null;
-        } else {
-            performInlining();
-            logOptimizingQueued(this);
-            this.installedCodeTask = compiler.compile(this);
-            if (!TruffleBackgroundCompilation.getValue()) {
-                return receiveInstalledCode();
-            }
-        }
-        return null;
+    protected static boolean shouldInline() {
+        return TruffleFunctionInlining.getValue();
     }
 
-    private InstalledCode receiveInstalledCode() {
-        try {
-            return installedCodeTask.get();
-        } catch (InterruptedException | ExecutionException e) {
-            compilationEnabled = false;
-            logOptimizingFailed(this, e.getMessage());
-            if (e.getCause() instanceof BailoutException) {
-                // Bailout => move on.
-            } else {
-                if (TraceTruffleCompilationExceptions.getValue()) {
-                    e.printStackTrace(OUT);
-                }
-                if (TruffleCompilationExceptionsAreFatal.getValue()) {
-                    System.exit(-1);
-                }
-            }
-            return null;
-        }
-    }
+    protected abstract void invalidate(Node oldNode, Node newNode, CharSequence reason);
 
     public Object executeHelper(PackedFrame caller, Arguments args) {
         VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), caller, args);
         return getRootNode().execute(frame);
     }
 
-    protected static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) {
+    public static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) {
         return new FrameWithoutBoxing(descriptor, caller, args);
     }
 
@@ -334,7 +218,7 @@
         }
     }
 
-    private static void logInlined(@SuppressWarnings("unused") final OptimizedCallTarget target, TruffleInliningProfile callSite) {
+    private static void logInlined(final OptimizedCallTarget target, TruffleInliningProfile callSite) {
         if (TraceTruffleInliningDetails.getValue() || TraceTruffleInlining.getValue()) {
             log(2, "inline success", callSite.getCallNode().getCurrentCallTarget().toString(), callSite.getDebugProperties());
 
@@ -348,13 +232,23 @@
                             OptimizedCallNode callNode = ((OptimizedCallNode) node);
                             RootNode inlinedRoot = callNode.getCurrentRootNode();
 
-                            if (inlinedRoot != null && callNode.isInlined()) {
+                            if (inlinedRoot != null) {
                                 Map<String, Object> properties = new LinkedHashMap<>();
                                 addASTSizeProperty(callNode.getCurrentRootNode(), properties);
-                                log(2 + (depth * 2), "inline success", callNode.getCurrentCallTarget().toString(), properties);
-                                depth++;
-                                inlinedRoot.accept(this);
-                                depth--;
+                                properties.putAll(callNode.createInliningProfile(target).getDebugProperties());
+                                String message;
+                                if (callNode.isInlined()) {
+                                    message = "inline success";
+                                } else {
+                                    message = "inline dispatch";
+                                }
+                                log(2 + (depth * 2), message, callNode.getCurrentCallTarget().toString(), properties);
+
+                                if (callNode.isInlined()) {
+                                    depth++;
+                                    inlinedRoot.accept(this);
+                                    depth--;
+                                }
                             }
                         }
                         return true;
@@ -376,13 +270,13 @@
         }
     }
 
-    private static void logOptimizingQueued(OptimizedCallTarget target) {
+    protected static void logOptimizingQueued(OptimizedCallTarget target) {
         if (TraceTruffleCompilationDetails.getValue()) {
             log(0, "opt queued", target.toString(), target.getDebugProperties());
         }
     }
 
-    private static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) {
+    protected static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) {
         if (TraceTruffleCompilationDetails.getValue()) {
             Map<String, Object> properties = new LinkedHashMap<>();
             addReplaceProperties(properties, oldNode, newNode);
@@ -405,7 +299,7 @@
         }
     }
 
-    private static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) {
+    protected static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) {
         if (TraceTruffleCompilation.getValue()) {
             Map<String, Object> properties = new LinkedHashMap<>();
             addReplaceProperties(properties, oldNode, newNode);
@@ -414,7 +308,7 @@
         }
     }
 
-    private static void logOptimizingFailed(OptimizedCallTarget callSite, CharSequence reason) {
+    protected static void logOptimizingFailed(OptimizedCallTarget callSite, CharSequence reason) {
         Map<String, Object> properties = new LinkedHashMap<>();
         properties.put("Reason", reason);
         log(0, "opt fail", callSite.toString(), properties);
@@ -473,7 +367,7 @@
             }
         }, true);
 
-        String value = String.format("%4d (%d/%d)", NodeUtil.countNodes(target.getRootNode(), null, true), //
+        String value = String.format("%4d (%d/%d)", NodeUtil.countNodes(target.getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, true), //
                         polymorphicCount, megamorphicCount); //
 
         properties.put("ASTSize", value);
@@ -533,8 +427,8 @@
                 continue;
             }
 
-            int nodeCount = NodeUtil.countNodes(callTarget.getRootNode(), null, true);
-            int inlinedCallSiteCount = countInlinedNodes(callTarget.getRootNode());
+            int nodeCount = NodeUtil.countNodes(callTarget.getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, false);
+            int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, true);
             String comment = callTarget.installedCode == null ? " int" : "";
             comment += callTarget.compilationEnabled ? "" : " fail";
             OUT.printf("%-50s | %10d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, nodeCount,
@@ -548,21 +442,6 @@
         OUT.printf("%-50s | %10d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNodeCount, totalInvalidationCount);
     }
 
-    private static int countInlinedNodes(Node rootNode) {
-        List<CallNode> callers = NodeUtil.findAllNodeInstances(rootNode, CallNode.class);
-        int count = 0;
-        for (CallNode callNode : callers) {
-            if (callNode.isInlined()) {
-                count++;
-                RootNode root = callNode.getCurrentRootNode();
-                if (root != null) {
-                    count += countInlinedNodes(root);
-                }
-            }
-        }
-        return count;
-    }
-
     private static void registerCallTarget(OptimizedCallTarget callTarget) {
         callTargets.put(callTarget, 0);
     }
@@ -581,4 +460,5 @@
             });
         }
     }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetImpl.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
+
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Call target for running truffle on a standard VM (and not in SubstrateVM).
+ */
+public final class OptimizedCallTargetImpl extends OptimizedCallTarget {
+
+    protected final TruffleCompiler compiler;
+    private Future<InstalledCode> installedCodeTask;
+
+    OptimizedCallTargetImpl(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) {
+        super(rootNode, invokeCounter, compilationThreshold, compilationEnabled, TruffleUseTimeForCompilationDecision.getValue() ? new TimedCompilationPolicy() : new DefaultCompilationPolicy());
+        this.compiler = compiler;
+    }
+
+    public boolean isOptimized() {
+        return installedCode != null || installedCodeTask != null;
+    }
+
+    @CompilerDirectives.SlowPath
+    @Override
+    public Object call(PackedFrame caller, Arguments args) {
+        return callHelper(caller, args);
+    }
+
+    private Object callHelper(PackedFrame caller, Arguments args) {
+        if (installedCode != null && installedCode.isValid()) {
+            reinstallCallMethodShortcut();
+        }
+        if (TruffleCallTargetProfiling.getValue()) {
+            callCount++;
+        }
+        if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, installedCode != null)) {
+            try {
+                return installedCode.execute(this, caller, args);
+            } catch (InvalidInstalledCodeException ex) {
+                return compiledCodeInvalidated(caller, args);
+            }
+        } else {
+            return interpreterCall(caller, args);
+        }
+    }
+
+    private static void reinstallCallMethodShortcut() {
+        if (TraceTruffleCompilation.getValue()) {
+            OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut.");
+        }
+        GraalTruffleRuntime.installOptimizedCallTargetCallMethod();
+    }
+
+    private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) {
+        invalidate(null, null, "Compiled code invalidated");
+        return call(caller, args);
+    }
+
+    @Override
+    protected void invalidate(Node oldNode, Node newNode, CharSequence reason) {
+        InstalledCode m = this.installedCode;
+        if (m != null) {
+            CompilerAsserts.neverPartOfCompilation();
+            installedCode = null;
+            compilationProfile.reportInvalidated();
+            logOptimizedInvalidated(this, oldNode, newNode, reason);
+        }
+        cancelInstalledTask(oldNode, newNode, reason);
+    }
+
+    private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) {
+        Future<InstalledCode> task = this.installedCodeTask;
+        if (task != null) {
+            task.cancel(true);
+            this.installedCodeTask = null;
+            logOptimizingUnqueued(this, oldNode, newNode, reason);
+            compilationProfile.reportInvalidated();
+        }
+    }
+
+    private Object interpreterCall(PackedFrame caller, Arguments args) {
+        CompilerAsserts.neverPartOfCompilation();
+        compilationProfile.reportInterpreterCall();
+
+        if (compilationEnabled && compilationPolicy.shouldCompile(compilationProfile)) {
+            InstalledCode code = compile();
+            if (code != null && code.isValid()) {
+                this.installedCode = code;
+                try {
+                    return code.execute(this, caller, args);
+                } catch (InvalidInstalledCodeException ex) {
+                    return compiledCodeInvalidated(caller, args);
+                }
+            }
+        }
+        return executeHelper(caller, args);
+    }
+
+    private boolean isCompiling() {
+        Future<InstalledCode> codeTask = this.installedCodeTask;
+        if (codeTask != null) {
+            if (codeTask.isCancelled()) {
+                installedCodeTask = null;
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public InstalledCode compile() {
+        if (isCompiling()) {
+            if (installedCodeTask.isDone()) {
+                return receiveInstalledCode();
+            }
+            return null;
+        } else {
+            performInlining();
+            logOptimizingQueued(this);
+            this.installedCodeTask = compiler.compile(this);
+            if (!TruffleBackgroundCompilation.getValue()) {
+                return receiveInstalledCode();
+            }
+            return null;
+        }
+    }
+
+    private InstalledCode receiveInstalledCode() {
+        try {
+            return installedCodeTask.get();
+        } catch (InterruptedException | ExecutionException e) {
+            compilationEnabled = false;
+            logOptimizingFailed(this, e.getMessage());
+            if (e.getCause() instanceof BailoutException) {
+                // Bailout => move on.
+            } else {
+                if (TraceTruffleCompilationExceptions.getValue()) {
+                    e.printStackTrace(OUT);
+                }
+                if (TruffleCompilationExceptionsAreFatal.getValue()) {
+                    System.exit(-1);
+                }
+            }
+            return null;
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -37,7 +37,6 @@
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -57,7 +56,6 @@
 import com.oracle.graal.truffle.phases.*;
 import com.oracle.graal.virtual.phases.ea.*;
 import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
 /**
@@ -66,25 +64,17 @@
 public class PartialEvaluator {
 
     private final Providers providers;
-    private final ResolvedJavaMethod executeHelperMethod;
     private final CanonicalizerPhase canonicalizer;
-    private final GraphBuilderConfiguration config;
     private Set<Constant> constantReceivers;
     private final TruffleCache truffleCache;
     private final ResolvedJavaType frameType;
 
-    public PartialEvaluator(Providers providers, TruffleCache truffleCache, GraphBuilderConfiguration config) {
+    public PartialEvaluator(Providers providers, TruffleCache truffleCache) {
         this.providers = providers;
         CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(providers.getMetaAccess(), providers.getConstantReflection());
         this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue(), customCanonicalizer);
-        this.config = config;
         this.truffleCache = truffleCache;
         this.frameType = providers.getMetaAccess().lookupJavaType(FrameWithoutBoxing.class);
-        try {
-            executeHelperMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class));
-        } catch (NoSuchMethodException ex) {
-            throw new RuntimeException(ex);
-        }
     }
 
     public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) {
@@ -98,10 +88,10 @@
             constantReceivers = new HashSet<>();
         }
 
-        final StructuredGraph graph = new StructuredGraph(executeHelperMethod);
+        final StructuredGraph graph = truffleCache.createRootGraph();
+        assert graph != null : "no graph for root method";
 
-        try (Scope s = Debug.scope("createGraph", graph)) {
-            new GraphBuilderPhase.Instance(providers.getMetaAccess(), config, TruffleCompilerImpl.Optimizations).apply(graph);
+        try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph.method())) {
 
             // Replace thisNode with constant.
             ParameterNode thisNode = graph.getParameter(0);
@@ -187,42 +177,54 @@
             changed = false;
             for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class)) {
                 InvokeKind kind = methodCallTargetNode.invokeKind();
-                if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || isFrame(methodCallTargetNode.receiver())))) {
-                    if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) {
-                        ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first();
-                        constantReceivers.add(constantNode.asConstant());
-                    }
-                    Replacements replacements = providers.getReplacements();
-                    Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
-                    if (macroSubstitution != null) {
-                        InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
-                        changed = true;
-                        continue;
-                    }
+                try (Indent id1 = Debug.logAndIndent("try inlining %s, kind = %s", methodCallTargetNode.targetMethod(), kind)) {
+                    if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || isFrame(methodCallTargetNode.receiver())))) {
+                        if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) {
+                            ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first();
+                            constantReceivers.add(constantNode.asConstant());
+                        }
+                        Replacements replacements = providers.getReplacements();
+                        Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
+                        if (macroSubstitution != null) {
+                            InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
+                            changed = true;
+                            continue;
+                        }
+
+                        if (TraceTruffleCompilationDetails.getValue() && kind == InvokeKind.Special) {
+                            ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first();
+                            constantReceivers.add(constantNode.asConstant());
+                        }
+
+                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
+                        if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers())) {
+                            inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext);
+                        }
 
-                    StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                    if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) &&
-                                    methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null) {
-                        inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext);
-                    }
+                        if (inlineGraph != null) {
+                            try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) {
 
-                    if (inlineGraph != null) {
-                        int nodeCountBefore = graph.getNodeCount();
-                        Mark mark = graph.getMark();
-                        if (TraceTruffleExpansion.getValue()) {
-                            expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
+                                int nodeCountBefore = graph.getNodeCount();
+                                Mark mark = graph.getMark();
+                                if (TraceTruffleExpansion.getValue()) {
+                                    expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
+                                }
+                                List<Node> invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot();
+                                // try (Indent in2 = Debug.logAndIndent(false, "do inlining")) {
+                                Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
+                                if (TraceTruffleExpansion.getValue()) {
+                                    expansionLogger.postExpand(inlined);
+                                }
+                                // }
+                                if (Debug.isDumpEnabled()) {
+                                    Debug.log("dump enabled");
+                                    int nodeCountAfter = graph.getNodeCount();
+                                    Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
+                                }
+                                canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark);
+                                changed = true;
+                            }
                         }
-                        List<Node> invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot();
-                        Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
-                        if (TraceTruffleExpansion.getValue()) {
-                            expansionLogger.postExpand(inlined);
-                        }
-                        if (Debug.isDumpEnabled()) {
-                            int nodeCountAfter = graph.getNodeCount();
-                            Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
-                        }
-                        canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark);
-                        changed = true;
                     }
                 }
 
@@ -249,8 +251,8 @@
 
         StructuredGraph graph = truffleCache.lookup(targetMethod, arguments, assumptions, canonicalizer);
 
-        if (targetMethod.getAnnotation(ExplodeLoop.class) != null) {
-            assert graph.hasLoops();
+        if (graph != null && targetMethod.getAnnotation(ExplodeLoop.class) != null) {
+            assert graph.hasLoops() : graph + " does not contain a loop";
             final StructuredGraph graphCopy = graph.copy();
             final List<Node> modifiedNodes = new ArrayList<>();
             for (ParameterNode param : graphCopy.getNodes(ParameterNode.class)) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Sun Mar 30 16:08:33 2014 +0200
@@ -44,12 +44,14 @@
         this.constantReflection = constantReflection;
     }
 
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
     @Override
     public Node canonicalize(Node node) {
         if (node instanceof LoadFieldNode) {
             LoadFieldNode loadFieldNode = (LoadFieldNode) node;
             if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) {
-                if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.kind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
+                if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.getKind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
                                 loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
                     Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
                     assert verifyFieldValue(loadFieldNode.field(), constant);
@@ -62,8 +64,8 @@
                 Object array = loadIndexedNode.array().asConstant().asObject();
                 long index = loadIndexedNode.index().asConstant().asLong();
                 if (index >= 0 && index < Array.getLength(array)) {
-                    int arrayBaseOffset = Unsafe.getUnsafe().arrayBaseOffset(array.getClass());
-                    int arrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(array.getClass());
+                    int arrayBaseOffset = unsafe.arrayBaseOffset(array.getClass());
+                    int arrayIndexScale = unsafe.arrayIndexScale(array.getClass());
                     Constant constant = constantReflection.readUnsafeConstant(loadIndexedNode.elementKind(), array, arrayBaseOffset + index * arrayIndexScale,
                                     loadIndexedNode.elementKind() == Kind.Object);
                     return ConstantNode.forConstant(constant, metaAccess, loadIndexedNode.graph());
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TimedCompilationPolicy.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TimedCompilationPolicy.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
+import java.io.*;
+
 public class TimedCompilationPolicy extends DefaultCompilationPolicy {
 
     @Override
@@ -39,9 +41,8 @@
             // maybe introduce another method?
             profile.reportTiminingFailed(timestamp);
             if (TruffleCompilationDecisionTimePrintFail.getValue()) {
-                // Checkstyle: stop
-                System.out.println(profile.getName() + ": timespan  " + (timespan / 1000000) + " ms  larger than threshold");
-                // Checkstyle: resume
+                PrintStream out = System.out;
+                out.println(profile.getName() + ": timespan  " + (timespan / 1000000) + " ms  larger than threshold");
             }
         }
         return false;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,232 +22,21 @@
  */
 package com.oracle.graal.truffle;
 
-import static com.oracle.graal.phases.GraalOptions.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.Map.Entry;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-import com.oracle.graal.truffle.phases.*;
-import com.oracle.graal.virtual.phases.ea.*;
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Implementation of a cache for Truffle graphs for improving partial evaluation time.
- */
-public final class TruffleCache {
-
-    private final Providers providers;
-    private final GraphBuilderConfiguration config;
-    private final OptimisticOptimizations optimisticOptimizations;
-
-    private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
-    private final HashMap<List<Object>, Long> lastUsed = new HashMap<>();
-    private final StructuredGraph markerGraph = new StructuredGraph();
-    private final ResolvedJavaType stringBuilderClass;
-    private long counter;
-
-    public TruffleCache(Providers providers, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations) {
-        this.providers = providers;
-        this.config = config;
-        this.optimisticOptimizations = optimisticOptimizations;
-        this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class);
-    }
-
-    @SuppressWarnings("unused")
-    public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) {
 
-        List<Object> key = new ArrayList<>(arguments.size() + 1);
-        key.add(method);
-        for (ValueNode v : arguments) {
-            if (v.kind() == Kind.Object) {
-                key.add(v.stamp());
-            }
-        }
-        StructuredGraph resultGraph = cache.get(key);
-        if (resultGraph != null) {
-            lastUsed.put(key, counter++);
-            return resultGraph;
-        }
-
-        if (resultGraph == markerGraph) {
-            // Avoid recursive inline.
-            return null;
-        }
-
-        if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) {
-            List<Long> lastUsedList = new ArrayList<>();
-            for (long l : lastUsed.values()) {
-                lastUsedList.add(l);
-            }
-            Collections.sort(lastUsedList);
-            long mid = lastUsedList.get(lastUsedList.size() / 2);
-
-            List<List<Object>> toRemoveList = new ArrayList<>();
-            for (Entry<List<Object>, Long> entry : lastUsed.entrySet()) {
-                if (entry.getValue() < mid) {
-                    toRemoveList.add(entry.getKey());
-                }
-            }
-
-            for (List<Object> entry : toRemoveList) {
-                cache.remove(entry);
-                lastUsed.remove(entry);
-            }
-        }
-
-        lastUsed.put(key, counter++);
-        cache.put(key, markerGraph);
-        try (Scope s = Debug.scope("TruffleCache", new Object[]{providers.getMetaAccess(), method})) {
-
-            final StructuredGraph graph = new StructuredGraph(method);
-            final PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false));
-            Mark mark = graph.getMark();
-            new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph);
-
-            for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
-                if (param.kind() == Kind.Object) {
-                    ValueNode actualArgument = arguments.get(param.index());
-                    param.setStamp(param.stamp().join(actualArgument.stamp()));
-                }
-            }
-
-            // Intrinsify methods.
-            new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
-
-            // Convert deopt to guards.
-            new ConvertDeoptimizeToGuardPhase().apply(graph);
-
-            CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!ImmutableCode.getValue());
-            PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase);
+public interface TruffleCache {
 
-            while (true) {
-
-                partialEscapePhase.apply(graph, phaseContext);
-
-                // Conditional elimination.
-                ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess());
-                conditionalEliminationPhase.apply(graph);
-
-                // Canonicalize / constant propagate.
-                canonicalizerPhase.apply(graph, phaseContext);
-
-                boolean inliningProgress = false;
-                for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
-                    if (!graph.getMark().equals(mark)) {
-                        // Make sure macro substitutions such as
-                        // CompilerDirectives.transferToInterpreter get processed first.
-                        for (Node newNode : graph.getNewNodes(mark)) {
-                            if (newNode instanceof MethodCallTargetNode) {
-                                MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
-                                Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
-                                if (macroSubstitution != null) {
-                                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
-                                } else {
-                                    tryCutOffRuntimeExceptions(methodCallTargetNode);
-                                }
-                            }
-                        }
-                        mark = graph.getMark();
-                    }
-                    if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) {
-                        inliningProgress = true;
-                        List<Node> canonicalizerUsages = new ArrayList<Node>();
-                        for (Node n : methodCallTarget.invoke().asNode().usages()) {
-                            if (n instanceof Canonicalizable) {
-                                canonicalizerUsages.add(n);
-                            }
-                        }
-                        List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
-                        Mark beforeInvokeMark = graph.getMark();
-                        expandInvoke(methodCallTarget);
-                        for (Node arg : argumentSnapshot) {
-                            if (arg != null && arg.recordsUsages()) {
-                                for (Node argUsage : arg.usages()) {
-                                    if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
-                                        canonicalizerUsages.add(argUsage);
-                                    }
-                                }
-                            }
-                        }
-                        canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages);
-                    }
-                }
-
-                // Convert deopt to guards.
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
+    /**
+     * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#executeHelper}.
+     */
+    StructuredGraph createRootGraph();
 
-                new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext);
-
-                if (!inliningProgress) {
-                    break;
-                }
-            }
-
-            cache.put(key, graph);
-            if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
-                TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount()));
-            }
-            return graph;
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-    }
-
-    private void expandInvoke(MethodCallTargetNode methodCallTargetNode) {
-        StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod());
-        if (inlineGraph == null) {
-            inlineGraph = TruffleCache.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null);
-        }
-        if (inlineGraph == this.markerGraph) {
-            // Can happen for recursive calls.
-            throw GraphUtil.approxSourceException(methodCallTargetNode, new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() +
-                            ", must annotate such calls with @CompilerDirectives.SlowPath!"));
-        }
-        Invoke invoke = methodCallTargetNode.invoke();
-        InliningUtil.inline(invoke, inlineGraph, true);
-    }
-
-    private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) {
-        if (methodCallTargetNode.targetMethod().isConstructor()) {
-            ResolvedJavaType runtimeException = providers.getMetaAccess().lookupJavaType(RuntimeException.class);
-            ResolvedJavaType controlFlowException = providers.getMetaAccess().lookupJavaType(ControlFlowException.class);
-            ResolvedJavaType exceptionType = Objects.requireNonNull(ObjectStamp.typeOrNull(methodCallTargetNode.receiver().stamp()));
-            if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) {
-                DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
-                FixedNode invokeNode = methodCallTargetNode.invoke().asNode();
-                invokeNode.replaceAtPredecessor(deoptNode);
-                GraphUtil.killCFG(invokeNode);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) {
-        return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
-                        !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
-                        methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null &&
-                        !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass);
-    }
+    /**
+     * Returns a cached graph for a method with given arguments.
+     */
+    StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import static com.oracle.graal.phases.GraalOptions.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.truffle.phases.*;
+import com.oracle.graal.virtual.phases.ea.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Implementation of a cache for Truffle graphs for improving partial evaluation time.
+ */
+public final class TruffleCacheImpl implements TruffleCache {
+
+    private final Providers providers;
+    private final GraphBuilderConfiguration config;
+    private final GraphBuilderConfiguration configForRootGraph;
+    private final OptimisticOptimizations optimisticOptimizations;
+
+    private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
+    private final HashMap<List<Object>, Long> lastUsed = new HashMap<>();
+    private final StructuredGraph markerGraph = new StructuredGraph();
+    private final ResolvedJavaType stringBuilderClass;
+    private final ResolvedJavaMethod executeHelperMethod;
+    private long counter;
+
+    public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRootGraph, OptimisticOptimizations optimisticOptimizations) {
+        this.providers = providers;
+        this.config = config;
+        this.configForRootGraph = configForRootGraph;
+        this.optimisticOptimizations = optimisticOptimizations;
+        this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class);
+        try {
+            executeHelperMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class));
+        } catch (NoSuchMethodException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public StructuredGraph createRootGraph() {
+        StructuredGraph graph = new StructuredGraph(executeHelperMethod);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRootGraph, TruffleCompilerImpl.Optimizations).apply(graph);
+        return graph;
+    }
+
+    @SuppressWarnings("unused")
+    public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) {
+
+        if (method.getAnnotation(CompilerDirectives.SlowPath.class) != null) {
+            return null;
+        }
+
+        List<Object> key = new ArrayList<>(arguments.size() + 1);
+        key.add(method);
+        for (ValueNode v : arguments) {
+            if (v.getKind() == Kind.Object) {
+                key.add(v.stamp());
+            }
+        }
+        StructuredGraph resultGraph = cache.get(key);
+        if (resultGraph != null) {
+            lastUsed.put(key, counter++);
+            return resultGraph;
+        }
+
+        if (resultGraph == markerGraph) {
+            // Avoid recursive inline.
+            return null;
+        }
+
+        if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) {
+            List<Long> lastUsedList = new ArrayList<>();
+            for (long l : lastUsed.values()) {
+                lastUsedList.add(l);
+            }
+            Collections.sort(lastUsedList);
+            long mid = lastUsedList.get(lastUsedList.size() / 2);
+
+            List<List<Object>> toRemoveList = new ArrayList<>();
+            for (Entry<List<Object>, Long> entry : lastUsed.entrySet()) {
+                if (entry.getValue() < mid) {
+                    toRemoveList.add(entry.getKey());
+                }
+            }
+
+            for (List<Object> entry : toRemoveList) {
+                cache.remove(entry);
+                lastUsed.remove(entry);
+            }
+        }
+
+        lastUsed.put(key, counter++);
+        cache.put(key, markerGraph);
+        try (Scope s = Debug.scope("TruffleCache", providers.getMetaAccess(), method)) {
+
+            final StructuredGraph graph = new StructuredGraph(method);
+            final PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false));
+            Mark mark = graph.getMark();
+            new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph);
+
+            for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+                if (param.getKind() == Kind.Object) {
+                    ValueNode actualArgument = arguments.get(param.index());
+                    param.setStamp(param.stamp().join(actualArgument.stamp()));
+                }
+            }
+
+            // Intrinsify methods.
+            new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
+
+            // Convert deopt to guards.
+            new ConvertDeoptimizeToGuardPhase().apply(graph);
+
+            CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!ImmutableCode.getValue());
+            PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase);
+
+            while (true) {
+
+                partialEscapePhase.apply(graph, phaseContext);
+
+                // Conditional elimination.
+                ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess());
+                conditionalEliminationPhase.apply(graph);
+
+                // Canonicalize / constant propagate.
+                canonicalizerPhase.apply(graph, phaseContext);
+
+                boolean inliningProgress = false;
+                for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
+                    if (!graph.getMark().equals(mark)) {
+                        // Make sure macro substitutions such as
+                        // CompilerDirectives.transferToInterpreter get processed first.
+                        for (Node newNode : graph.getNewNodes(mark)) {
+                            if (newNode instanceof MethodCallTargetNode) {
+                                MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
+                                Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
+                                if (macroSubstitution != null) {
+                                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
+                                } else {
+                                    tryCutOffRuntimeExceptions(methodCallTargetNode);
+                                }
+                            }
+                        }
+                        mark = graph.getMark();
+                    }
+                    if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) {
+                        inliningProgress = true;
+                        List<Node> canonicalizerUsages = new ArrayList<Node>();
+                        for (Node n : methodCallTarget.invoke().asNode().usages()) {
+                            if (n instanceof Canonicalizable) {
+                                canonicalizerUsages.add(n);
+                            }
+                        }
+                        List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
+                        Mark beforeInvokeMark = graph.getMark();
+                        expandInvoke(methodCallTarget);
+                        for (Node arg : argumentSnapshot) {
+                            if (arg != null && arg.recordsUsages()) {
+                                for (Node argUsage : arg.usages()) {
+                                    if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
+                                        canonicalizerUsages.add(argUsage);
+                                    }
+                                }
+                            }
+                        }
+                        canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages);
+                    }
+                }
+
+                // Convert deopt to guards.
+                new ConvertDeoptimizeToGuardPhase().apply(graph);
+
+                new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext);
+
+                if (!inliningProgress) {
+                    break;
+                }
+            }
+
+            cache.put(key, graph);
+            if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
+                TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount()));
+            }
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+    }
+
+    private void expandInvoke(MethodCallTargetNode methodCallTargetNode) {
+        StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod());
+        if (inlineGraph == null) {
+            inlineGraph = TruffleCacheImpl.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null);
+        }
+        if (inlineGraph == this.markerGraph) {
+            // Can happen for recursive calls.
+            throw GraphUtil.approxSourceException(methodCallTargetNode, new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() +
+                            ", must annotate such calls with @CompilerDirectives.SlowPath!"));
+        }
+        Invoke invoke = methodCallTargetNode.invoke();
+        InliningUtil.inline(invoke, inlineGraph, true);
+    }
+
+    private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) {
+        if (methodCallTargetNode.targetMethod().isConstructor()) {
+            ResolvedJavaType runtimeException = providers.getMetaAccess().lookupJavaType(RuntimeException.class);
+            ResolvedJavaType controlFlowException = providers.getMetaAccess().lookupJavaType(ControlFlowException.class);
+            ResolvedJavaType exceptionType = Objects.requireNonNull(ObjectStamp.typeOrNull(methodCallTargetNode.receiver().stamp()));
+            if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) {
+                DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
+                FixedNode invokeNode = methodCallTargetNode.invoke().asNode();
+                invokeNode.replaceAtPredecessor(deoptNode);
+                GraphUtil.killCFG(invokeNode);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) {
+        return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
+                        !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
+                        methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null &&
+                        !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass);
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Sun Mar 30 16:08:33 2014 +0200
@@ -98,18 +98,19 @@
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
         GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault();
         eagerConfig.setSkippedExceptionTypes(skippedExceptionTypes);
-        this.truffleCache = new TruffleCache(providers, eagerConfig, TruffleCompilerImpl.Optimizations);
-
         this.config = GraphBuilderConfiguration.getDefault();
         this.config.setSkippedExceptionTypes(skippedExceptionTypes);
-        this.partialEvaluator = new PartialEvaluator(providers, truffleCache, config);
+
+        this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations);
+
+        this.partialEvaluator = new PartialEvaluator(providers, truffleCache);
 
         if (Debug.isEnabled()) {
             DebugEnvironment.initialize(System.out);
         }
     }
 
-    private static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) {
+    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]);
@@ -122,7 +123,7 @@
             @Override
             public InstalledCode call() throws Exception {
                 try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(compilable))) {
-                    return compileMethodImpl(compilable);
+                    return compileMethodImpl((OptimizedCallTargetImpl) compilable);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
@@ -134,11 +135,11 @@
     public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
     public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
 
-    private InstalledCode compileMethodImpl(final OptimizedCallTarget compilable) {
+    private InstalledCode compileMethodImpl(final OptimizedCallTargetImpl compilable) {
         final StructuredGraph graph;
 
         if (TraceTruffleCompilation.getValue()) {
-            OptimizedCallTarget.logOptimizingStart(compilable);
+            OptimizedCallTargetImpl.logOptimizingStart(compilable);
         }
 
         if (TraceTruffleInliningTree.getValue()) {
@@ -178,7 +179,7 @@
             properties.put("CodeSize", code != null ? code.length : 0);
             properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection()));
 
-            OptimizedCallTarget.logOptimizingDone(compilable, properties);
+            OptimizedCallTargetImpl.logOptimizingDone(compilable, properties);
         }
         return compiledMethod;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Sun Mar 30 16:08:33 2014 +0200
@@ -58,7 +58,7 @@
     @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit")
     public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2250);
     @Option(help = "Skip inlining candidate if its tree size exceeds this limit")
-    public static final OptionValue<Integer> TruffleInliningMaxCalleeSize = new OptionValue<>(250);
+    public static final OptionValue<Integer> TruffleInliningMaxCalleeSize = new OptionValue<>(350);
     @Option(help = "Call frequency relative to call target")
     public static final OptionValue<Double> TruffleInliningMinFrequency = new OptionValue<>(0.3);
     @Option(help = "Allow inlining of less hot candidates if tree size is small")
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java	Sun Mar 30 16:08:33 2014 +0200
@@ -30,7 +30,7 @@
 
 /**
  * Enables a Truffle compilable to masquerade as a {@link JavaMethod} for use as a context value in
- * {@linkplain Debug#scope(String, Object...) debug scopes}.
+ * {@linkplain Debug#scope(Object) debug scopes}.
  */
 public class TruffleDebugJavaMethod implements JavaMethod {
     private final RootCallTarget compilable;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Sun Mar 30 16:08:33 2014 +0200
@@ -43,7 +43,7 @@
     }
 
     public void preExpand(MethodCallTargetNode callTarget, StructuredGraph inliningGraph) {
-        ResolvedJavaMethod sourceMethod = callTarget.invoke().getState().method();
+        ResolvedJavaMethod sourceMethod = callTarget.invoke().stateAfter().method();
 
         int sourceMethodBci = callTarget.invoke().bci();
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Sun Mar 30 16:08:33 2014 +0200
@@ -47,17 +47,17 @@
         this.graalReplacements = providers.getReplacements();
     }
 
-    static Replacements makeInstance() {
+    public static Replacements makeInstance() {
         Providers graalProviders = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders();
         Replacements truffleReplacements = new TruffleReplacements(graalProviders);
 
         truffleReplacements.registerSubstitutions(CompilerAssertsSubstitutions.class);
         truffleReplacements.registerSubstitutions(CompilerDirectivesSubstitutions.class);
         truffleReplacements.registerSubstitutions(ExactMathSubstitutions.class);
-        truffleReplacements.registerSubstitutions(UnexpectedResultExceptionSubstitutions.class);
         truffleReplacements.registerSubstitutions(FrameWithoutBoxingSubstitutions.class);
         truffleReplacements.registerSubstitutions(OptimizedAssumptionSubstitutions.class);
         truffleReplacements.registerSubstitutions(OptimizedCallTargetSubstitutions.class);
+        truffleReplacements.registerSubstitutions(OptimizedCallTargetImplSubstitutions.class);
 
         return truffleReplacements;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -34,7 +34,7 @@
     }
 
     @Override
-    protected Value generateArithmetic(LIRGeneratorTool gen) {
-        return gen.emitAdd(gen.operand(getX()), gen.operand(getY()));
+    protected Value generateArithmetic(NodeLIRGeneratorTool gen) {
+        return gen.getLIRGeneratorTool().emitAdd(gen.operand(getX()), gen.operand(getY()));
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,14 +23,12 @@
 package com.oracle.graal.truffle.nodes.arithmetic;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class IntegerExactArithmeticSplitNode extends ControlSplitNode implements LIRGenLowerable {
+public abstract class IntegerExactArithmeticSplitNode extends ControlSplitNode implements LIRLowerable {
 
     @Successor private AbstractBeginNode overflowSuccessor;
     @Successor private AbstractBeginNode next;
@@ -72,12 +70,12 @@
     }
 
     @Override
-    public void generate(LIRGenerator generator) {
+    public void generate(NodeLIRGeneratorTool generator) {
         generator.setResult(this, generateArithmetic(generator));
-        generator.emitOverflowCheckBranch(generator.getLIRBlock(getOverflowSuccessor()), generator.getLIRBlock(getNext()), probability(getOverflowSuccessor()));
+        generator.emitOverflowCheckBranch(getOverflowSuccessor(), getNext(), probability(getOverflowSuccessor()));
     }
 
-    protected abstract Value generateArithmetic(LIRGeneratorTool generator);
+    protected abstract Value generateArithmetic(NodeLIRGeneratorTool generator);
 
     static void lower(LoweringTool tool, IntegerExactArithmeticNode node) {
         if (node.asNode().graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -34,7 +34,7 @@
     }
 
     @Override
-    protected Value generateArithmetic(LIRGeneratorTool gen) {
-        return gen.emitMul(gen.operand(getX()), gen.operand(getY()));
+    protected Value generateArithmetic(NodeLIRGeneratorTool gen) {
+        return gen.getLIRGeneratorTool().emitMul(gen.operand(getX()), gen.operand(getY()));
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -34,7 +34,7 @@
     }
 
     @Override
-    protected Value generateArithmetic(LIRGeneratorTool gen) {
-        return gen.emitSub(gen.operand(getX()), gen.operand(getY()));
+    protected Value generateArithmetic(NodeLIRGeneratorTool gen) {
+        return gen.getLIRGeneratorTool().emitSub(gen.operand(getX()), gen.operand(getY()));
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -75,7 +75,7 @@
                 int entryIndex = state.getVirtualObject().entryIndexForOffset(constantOffset);
                 if (entryIndex != -1) {
                     ValueNode entry = state.getEntry(entryIndex);
-                    if (entry.kind() == kind() || state.getVirtualObject().entryKind(entryIndex) == accessKind) {
+                    if (entry.getKind() == getKind() || state.getVirtualObject().entryKind(entryIndex) == accessKind) {
                         tool.replaceWith(entry);
                     }
                 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -33,14 +33,15 @@
 import com.oracle.truffle.api.*;
 
 /**
- * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean)}.
+ * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean, boolean)}.
  */
 public class UnsafeTypeCastMacroNode extends NeverPartOfCompilationNode implements Canonicalizable {
 
-    private static final int ARGUMENT_COUNT = 3;
     private static final int OBJECT_ARGUMENT_INDEX = 0;
     private static final int CLASS_ARGUMENT_INDEX = 1;
     private static final int CONDITION_ARGUMENT_INDEX = 2;
+    private static final int NONNULL_ARGUMENT_INDEX = 3;
+    private static final int ARGUMENT_COUNT = 4;
 
     public UnsafeTypeCastMacroNode(Invoke invoke) {
         super(invoke, "The class of the unsafe cast could not be reduced to a compile time constant.");
@@ -50,7 +51,8 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         ValueNode classArgument = arguments.get(CLASS_ARGUMENT_INDEX);
-        if (classArgument.isConstant()) {
+        ValueNode nonNullArgument = arguments.get(NONNULL_ARGUMENT_INDEX);
+        if (classArgument.isConstant() && nonNullArgument.isConstant()) {
             ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
             ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
             Class c = (Class) classArgument.asConstant().asObject();
@@ -58,8 +60,9 @@
                 return objectArgument;
             }
             ResolvedJavaType lookupJavaType = tool.getMetaAccess().lookupJavaType(c);
+            Stamp stamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0);
             ConditionAnchorNode valueAnchorNode = graph().add(new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
-            UnsafeCastNode piCast = graph().unique(new UnsafeCastNode(objectArgument, StampFactory.declaredNonNull(lookupJavaType), valueAnchorNode));
+            UnsafeCastNode piCast = graph().unique(new UnsafeCastNode(objectArgument, stamp, valueAnchorNode));
             this.replaceAtUsages(piCast);
             return valueAnchorNode;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Sun Mar 30 16:08:33 2014 +0200
@@ -71,7 +71,7 @@
     public static native void bailout(String reason);
 
     @MacroSubstitution(macro = UnsafeTypeCastMacroNode.class, isStatic = true)
-    public static native Object unsafeCast(Object value, Class clazz, boolean condition);
+    public static native Object unsafeCast(Object value, Class clazz, boolean condition, boolean nonNull);
 
     @MethodSubstitution
     private static Class<? extends MaterializedFrame> getUnsafeFrameType() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetImplSubstitutions.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.substitutions;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.truffle.*;
+import com.oracle.graal.truffle.nodes.asserts.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+@ClassSubstitution(OptimizedCallTargetImpl.class)
+public class OptimizedCallTargetImplSubstitutions {
+
+    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
+    public static native Object callHelper(OptimizedCallTarget target, PackedFrame caller, Arguments args);
+
+    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
+    public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args);
+
+    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
+    public static native Object compiledCodeInvalidated(OptimizedCallTarget target, PackedFrame caller, Arguments args);
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Sun Mar 30 16:08:33 2014 +0200
@@ -23,9 +23,7 @@
 package com.oracle.graal.truffle.substitutions;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.truffle.*;
-import com.oracle.graal.truffle.nodes.asserts.*;
 import com.oracle.graal.truffle.nodes.frame.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
@@ -33,15 +31,6 @@
 @ClassSubstitution(OptimizedCallTarget.class)
 public class OptimizedCallTargetSubstitutions {
 
-    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
-    public static native Object callHelper(OptimizedCallTarget target, PackedFrame caller, Arguments args);
-
-    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
-    public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args);
-
-    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
-    public static native Object compiledCodeInvalidated(OptimizedCallTarget target, PackedFrame caller, Arguments args);
-
     @MethodSubstitution
     private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) {
         return NewFrameNode.allocate(FrameWithoutBoxing.class, descriptor, caller, args);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java	Wed Mar 19 11:43:57 2014 +0100
+++ /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.truffle.substitutions;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Deoptimize on creation of a new UnexpectedResultException instance.
- */
-@ClassSubstitution(UnexpectedResultException.class)
-public class UnexpectedResultExceptionSubstitutions {
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(value = "<init>")
-    public static void init(Object result) {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode);
-    }
-}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
+import static com.oracle.graal.debug.Debug.*;
+
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
@@ -59,8 +61,7 @@
     public boolean runAnalysis(final StructuredGraph graph, final PhaseContextT context) {
         boolean changed = false;
         for (int iteration = 0; iteration < maxIterations; iteration++) {
-
-            try (Scope s = Debug.scope("iteration " + iteration)) {
+            try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) {
                 SchedulePhase schedule = new SchedulePhase();
                 schedule.apply(graph, false);
                 Closure<?> closure = createEffectsClosure(context, schedule);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
+import static com.oracle.graal.debug.Debug.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
@@ -41,8 +42,8 @@
     }
 
     public static final void trace(String format, Object... obj) {
-        if (TraceEscapeAnalysis.getValue()) {
-            Debug.log(format, obj);
+        if (TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj);
         }
     }
 
@@ -54,7 +55,7 @@
 
     private void runIterations(final StructuredGraph graph, final boolean simple, final HighTierContext context) {
         for (int iteration = 0; iteration < EscapeAnalysisIterations.getValue(); iteration++) {
-            try (Scope s = Debug.scope("iteration " + iteration)) {
+            try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) {
                 boolean progress = false;
                 PartialEscapePhase ea = new PartialEscapePhase(false, canonicalizer);
                 boolean eaResult = ea.runAnalysis(graph, context);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Sun Mar 30 16:08:33 2014 +0200
@@ -173,7 +173,7 @@
                 }
             }
             for (PhiNode phi : merge.phis()) {
-                if (phi.kind() == Kind.Object) {
+                if (phi.getKind() == Kind.Object) {
                     for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
                         if (entry.getKey().object == phi.valueAt(0)) {
                             mergeReadCachePhi(phi, entry.getKey().identity, states);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Sun Mar 30 16:08:33 2014 +0200
@@ -132,75 +132,78 @@
     }
 
     private void processNodeWithState(NodeWithState nodeWithState, final BlockT state, final GraphEffectList effects) {
-        FrameState frameState = nodeWithState.getState();
-        if (frameState != null) {
-            if (frameState.usages().count() > 1) {
-                nodeWithState.asNode().replaceFirstInput(frameState, frameState.copyWithInputs());
-                frameState = nodeWithState.getState();
-            }
-            final Set<ObjectState> virtual = new ArraySet<>();
-            frameState.applyToNonVirtual(new NodeClosure<ValueNode>() {
+        for (Node input : nodeWithState.asNode().inputs()) {
+            if (input instanceof FrameState) {
+                FrameState frameState = (FrameState) input;
+                if (frameState.usages().count() > 1) {
+                    FrameState copy = (FrameState) frameState.copyWithInputs();
+                    nodeWithState.asNode().replaceFirstInput(frameState, copy);
+                    frameState = copy;
+                }
+                final Set<ObjectState> virtual = new ArraySet<>();
+                frameState.applyToNonVirtual(new NodeClosure<ValueNode>() {
 
-                @Override
-                public void apply(Node usage, ValueNode value) {
-                    ObjectState valueObj = getObjectState(state, value);
-                    if (valueObj != null) {
-                        virtual.add(valueObj);
-                        effects.replaceFirstInput(usage, value, valueObj.virtual);
-                    } else if (value instanceof VirtualObjectNode) {
-                        ObjectState virtualObj = null;
-                        for (ObjectState obj : state.getStates()) {
-                            if (value == obj.virtual) {
-                                virtualObj = obj;
-                                break;
+                    @Override
+                    public void apply(Node usage, ValueNode value) {
+                        ObjectState valueObj = getObjectState(state, value);
+                        if (valueObj != null) {
+                            virtual.add(valueObj);
+                            effects.replaceFirstInput(usage, value, valueObj.virtual);
+                        } else if (value instanceof VirtualObjectNode) {
+                            ObjectState virtualObj = null;
+                            for (ObjectState obj : state.getStates()) {
+                                if (value == obj.virtual) {
+                                    virtualObj = obj;
+                                    break;
+                                }
+                            }
+                            if (virtualObj != null) {
+                                virtual.add(virtualObj);
                             }
                         }
-                        if (virtualObj != null) {
-                            virtual.add(virtualObj);
-                        }
+                    }
+                });
+                for (ObjectState obj : state.getStates()) {
+                    if (obj.isVirtual() && obj.hasLocks()) {
+                        virtual.add(obj);
                     }
                 }
-            });
-            for (ObjectState obj : state.getStates()) {
-                if (obj.isVirtual() && obj.hasLocks()) {
-                    virtual.add(obj);
-                }
-            }
 
-            ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual);
-            while (!queue.isEmpty()) {
-                ObjectState obj = queue.removeLast();
-                if (obj.isVirtual()) {
-                    for (ValueNode field : obj.getEntries()) {
-                        if (field instanceof VirtualObjectNode) {
-                            ObjectState fieldObj = state.getObjectState((VirtualObjectNode) field);
-                            if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
-                                virtual.add(fieldObj);
-                                queue.addLast(fieldObj);
+                ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual);
+                while (!queue.isEmpty()) {
+                    ObjectState obj = queue.removeLast();
+                    if (obj.isVirtual()) {
+                        for (ValueNode field : obj.getEntries()) {
+                            if (field instanceof VirtualObjectNode) {
+                                ObjectState fieldObj = state.getObjectState((VirtualObjectNode) field);
+                                if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
+                                    virtual.add(fieldObj);
+                                    queue.addLast(fieldObj);
+                                }
                             }
                         }
                     }
                 }
-            }
-            for (ObjectState obj : virtual) {
-                EscapeObjectState v;
-                if (obj.isVirtual()) {
-                    ValueNode[] fieldState = obj.getEntries().clone();
-                    for (int i = 0; i < fieldState.length; i++) {
-                        ObjectState valueObj = getObjectState(state, fieldState[i]);
-                        if (valueObj != null) {
-                            if (valueObj.isVirtual()) {
-                                fieldState[i] = valueObj.virtual;
-                            } else {
-                                fieldState[i] = valueObj.getMaterializedValue();
+                for (ObjectState obj : virtual) {
+                    EscapeObjectState v;
+                    if (obj.isVirtual()) {
+                        ValueNode[] fieldState = obj.getEntries().clone();
+                        for (int i = 0; i < fieldState.length; i++) {
+                            ObjectState valueObj = getObjectState(state, fieldState[i]);
+                            if (valueObj != null) {
+                                if (valueObj.isVirtual()) {
+                                    fieldState[i] = valueObj.virtual;
+                                } else {
+                                    fieldState[i] = valueObj.getMaterializedValue();
+                                }
                             }
                         }
+                        v = new VirtualObjectState(obj.virtual, fieldState);
+                    } else {
+                        v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
                     }
-                    v = new VirtualObjectState(obj.virtual, fieldState);
-                } else {
-                    v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
+                    effects.addVirtualMapping(frameState, v);
                 }
-                effects.addVirtualMapping(frameState, v);
             }
         }
     }
@@ -411,7 +414,7 @@
                 ValueNode[] entries = objStates[i].getEntries();
                 int valueIndex = 0;
                 while (valueIndex < values.length) {
-                    Kind otherKind = entries[valueIndex].kind();
+                    Kind otherKind = entries[valueIndex].getKind();
                     Kind entryKind = object.entryKind(valueIndex);
                     if (entryKind == Kind.Int && (otherKind == Kind.Long || otherKind == Kind.Double)) {
                         if (twoSlotKinds == null) {
@@ -437,7 +440,7 @@
                         assert valueIndex < object.entryCount() - 1 && object.entryKind(valueIndex) == Kind.Int && object.entryKind(valueIndex + 1) == Kind.Int;
                         for (int i = 0; i < objStates.length; i++) {
                             ValueNode value = objStates[i].getEntry(valueIndex);
-                            Kind valueKind = value.kind();
+                            Kind valueKind = value.getKind();
                             if (valueKind != twoSlotKinds[valueIndex]) {
                                 ValueNode nextValue = objStates[i].getEntry(valueIndex + 1);
                                 if (value.isConstant() && value.asConstant().equals(Constant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(Constant.INT_0)) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Sun Mar 30 16:08:33 2014 +0200
@@ -94,6 +94,9 @@
                 ReadCacheEntry identifier = new ReadCacheEntry(object, read.location());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
                 if (cachedValue != null) {
+                    if (read.getGuard() != null && !(read.getGuard() instanceof FixedNode)) {
+                        effects.addFixedNodeBefore(new ValueAnchorNode((ValueNode) read.getGuard()), read);
+                    }
                     effects.replaceAtUsages(read, cachedValue);
                     addScalarAlias(read, cachedValue);
                     deleted = true;
@@ -241,7 +244,7 @@
                 }
             }
             for (PhiNode phi : merge.phis()) {
-                if (phi.kind() == Kind.Object) {
+                if (phi.getKind() == Kind.Object) {
                     for (Map.Entry<CacheEntry<?>, ValueNode> entry : states.get(0).readCache.entrySet()) {
                         if (entry.getKey().object == phi.valueAt(0)) {
                             mergeReadCachePhi(phi, entry.getKey(), states);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Sun Mar 30 16:08:33 2014 +0200
@@ -109,8 +109,8 @@
     }
 
     public static void trace(String format, Object... obj) {
-        if (TraceEscapeAnalysis.getValue()) {
-            Debug.log(format, obj);
+        if (TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj);
         }
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Sun Mar 30 16:08:33 2014 +0200
@@ -93,11 +93,11 @@
             ObjectState valueState = closure.getObjectState(state, value);
             if (valueState == null) {
                 newValue = getReplacedValue(value);
-                assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).kind() == newValue.kind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
+                assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
             } else {
                 if (valueState.getState() != EscapeState.Virtual) {
                     newValue = valueState.getMaterializedValue();
-                    assert newValue.kind() == Kind.Object;
+                    assert newValue.getKind() == Kind.Object;
                 } else {
                     newValue = valueState.getVirtualObject();
                 }
@@ -108,7 +108,7 @@
     }
 
     private static boolean isObjectEntry(ValueNode value) {
-        return value.kind() == Kind.Object || value instanceof VirtualObjectNode;
+        return value.getKind() == Kind.Object || value instanceof VirtualObjectNode;
     }
 
     @Override
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -37,12 +37,12 @@
 public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
 
     public static WordCastNode wordToObject(ValueNode input, Kind wordKind) {
-        assert input.kind() == wordKind;
+        assert input.getKind() == wordKind;
         return new WordCastNode(StampFactory.object(), input);
     }
 
     public static WordCastNode objectToWord(ValueNode input, Kind wordKind) {
-        assert input.kind() == Kind.Object;
+        assert input.getKind() == Kind.Object;
         return new WordCastNode(StampFactory.forKind(wordKind), input);
     }
 
@@ -67,12 +67,12 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
-        assert kind() != input.kind();
-        assert generator.target().getSizeInBytes(kind()) == generator.target().getSizeInBytes(input.kind());
+    public void generate(NodeLIRGeneratorTool generator) {
+        assert getKind() != input.getKind();
+        assert generator.getLIRGeneratorTool().target().getSizeInBytes(getKind()) == generator.getLIRGeneratorTool().target().getSizeInBytes(input.getKind());
 
-        AllocatableValue result = generator.newVariable(kind());
-        generator.emitMove(result, generator.operand(input));
+        AllocatableValue result = generator.getLIRGeneratorTool().newVariable(getKind());
+        generator.getLIRGeneratorTool().emitMove(result, generator.operand(input));
         generator.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Sun Mar 30 16:08:33 2014 +0200
@@ -116,7 +116,7 @@
      * Remove casts between word types (which by now no longer have kind Object).
      */
     protected void rewriteCheckCast(StructuredGraph graph, CheckCastNode node) {
-        if (node.kind() == wordKind) {
+        if (node.getKind() == wordKind) {
             node.replaceAtUsages(node.object());
             graph.removeFixed(node);
         }
@@ -173,7 +173,7 @@
         }
 
         if (!callTargetNode.isStatic()) {
-            assert callTargetNode.receiver().kind() == wordKind : "changeToWord() missed the receiver";
+            assert callTargetNode.receiver().getKind() == wordKind : "changeToWord() missed the receiver";
             targetMethod = wordImplType.resolveMethod(targetMethod);
         }
         Operation operation = targetMethod.getAnnotation(Word.Operation.class);
@@ -214,7 +214,7 @@
                 } else {
                     location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
                 }
-                replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, BarrierType.NONE, false));
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, StampFactory.forKind(readKind.getStackKind()), BarrierType.NONE, false));
                 break;
             }
             case READ_HEAP: {
@@ -222,7 +222,8 @@
                 Kind readKind = asKind(callTargetNode.returnType());
                 LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
                 BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject();
-                replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
+                boolean compressible = arguments.get(3).asConstant().asInt() != 0;
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, StampFactory.forKind(readKind.getStackKind()), barrierType, compressible));
                 break;
             }
             case WRITE:
@@ -295,16 +296,16 @@
     }
 
     private static ValueNode convert(StructuredGraph graph, ValueNode value, Kind toKind, boolean unsigned) {
-        if (value.kind() == toKind) {
+        if (value.getKind() == toKind) {
             return value;
         }
 
         if (toKind == Kind.Int) {
-            assert value.kind() == Kind.Long;
+            assert value.getKind() == Kind.Long;
             return graph.unique(new NarrowNode(value, 32));
         } else {
             assert toKind == Kind.Long;
-            assert value.kind().getStackKind() == Kind.Int;
+            assert value.getKind().getStackKind() == Kind.Int;
             if (unsigned) {
                 return graph.unique(new ZeroExtendNode(value, 64));
             } else {
@@ -328,7 +329,7 @@
     }
 
     private ValueNode comparisonOp(StructuredGraph graph, Condition condition, ValueNode left, ValueNode right) {
-        assert left.kind() == wordKind && right.kind() == wordKind;
+        assert left.getKind() == wordKind && right.getKind() == wordKind;
 
         // mirroring gets the condition into canonical form
         boolean mirror = condition.canonicalMirror();
@@ -369,8 +370,8 @@
         return IndexedLocationNode.create(locationIdentity, readKind, 0, fromSigned(graph, offset), graph, 1);
     }
 
-    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Kind readKind, BarrierType barrierType, boolean compressible) {
-        ReadNode read = graph.add(new ReadNode(base, location, StampFactory.forKind(readKind.getStackKind()), barrierType, compressible));
+    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Stamp stamp, BarrierType barrierType, boolean compressible) {
+        ReadNode read = graph.add(new ReadNode(base, location, stamp, barrierType, compressible));
         graph.addBeforeFixed(invoke.asNode(), read);
         /*
          * The read must not float outside its block otherwise it may float above an explicit zero
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -71,6 +71,7 @@
     public void testImplicitCast0() {
         ImplicitCast0Node node = ImplicitCast0NodeFactory.create(null);
         TestRootNode<ImplicitCast0Node> root = new TestRootNode<>(node);
+        root.adoptChildren();
         Assert.assertEquals("2", root.getNode().executeEvaluated(null, "2"));
         Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1));
         Assert.assertEquals("1", root.getNode().executeEvaluated(null, "1"));
@@ -106,6 +107,7 @@
     public void testImplicitCast1() {
         ImplicitCast1Node node = ImplicitCast1NodeFactory.create(null);
         TestRootNode<ImplicitCast1Node> root = new TestRootNode<>(node);
+        root.adoptChildren();
         Assert.assertEquals("2", root.getNode().executeEvaluated(null, "2"));
         Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1));
         Assert.assertEquals("1", root.getNode().executeEvaluated(null, "1"));
@@ -146,6 +148,7 @@
     public void testImplicitCast2() {
         ImplicitCast2Node node = ImplicitCast2NodeFactory.create(null, null);
         TestRootNode<ImplicitCast2Node> root = new TestRootNode<>(node);
+        root.adoptChildren();
         Assert.assertEquals("42", root.getNode().executeEvaluated(null, "4", "2"));
         Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1, 1));
         Assert.assertEquals("42", root.getNode().executeEvaluated(null, "4", "2"));
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -64,7 +64,7 @@
         TestRootNode<Node1> node = TestHelper.createRoot(Node1Factory.getInstance());
         assertEquals("(int,boolean)", executeWith(node, 42, false));
         assertEquals("(int,int)", executeWith(node, 42, 42));
-        assertEquals(NodeCost.NONE, node.getNode().getCost());
+        assertEquals(NodeCost.POLYMORPHIC, node.getNode().getCost());
         assertParent(node.getNode(), node.getNode().getLeft());
         assertParent(node.getNode(), node.getNode().getRight());
     }
@@ -75,7 +75,7 @@
         assertEquals("(int,boolean)", executeWith(node, 42, false));
         assertEquals("(boolean,boolean)", executeWith(node, true, false));
         assertEquals("(int,int)", executeWith(node, 42, 42));
-        assertEquals(NodeCost.NONE, node.getNode().getCost());
+        assertEquals(NodeCost.POLYMORPHIC, node.getNode().getCost());
         assertParent(node.getNode(), node.getNode().getLeft());
         assertParent(node.getNode(), node.getNode().getRight());
     }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java	Sun Mar 30 16:08:33 2014 +0200
@@ -42,7 +42,7 @@
         assertEquals(21, executeWith(node, false, false));
         assertEquals(42, executeWith(node, 21, 21));
         assertEquals("(boolean,int)", executeWith(node, false, 42));
-        assertEquals(NodeCost.NONE, node.getNode().getCost());
+        assertEquals(NodeCost.POLYMORPHIC, node.getNode().getCost());
     }
 
     @SuppressWarnings("unused")
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Sun Mar 30 16:08:33 2014 +0200
@@ -76,11 +76,15 @@
     }
 
     static <E extends ValueNode> TestRootNode<E> createRoot(NodeFactory<E> factory, Object... constants) {
-        return new TestRootNode<>(createNode(factory, constants));
+        TestRootNode<E> rootNode = new TestRootNode<>(createNode(factory, constants));
+        rootNode.adoptChildren();
+        return rootNode;
     }
 
     static <E extends ValueNode> TestRootNode<E> createGenericRoot(NodeFactory<E> factory, Object... constants) {
-        return new TestRootNode<>(createGenericNode(factory, constants));
+        TestRootNode<E> rootNode = new TestRootNode<>(createGenericNode(factory, constants));
+        rootNode.adoptChildren();
+        return rootNode;
     }
 
     static CallTarget createCallTarget(ValueNode node) {
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -100,7 +100,7 @@
 
         public TestRootNode(E node) {
             super(null);
-            this.node = adoptChild(node);
+            this.node = node;
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -61,7 +61,7 @@
         Assert.assertEquals(42, result);
     }
 
-    class TestArguments extends Arguments {
+    private static class TestArguments extends Arguments {
 
         final int[] values;
 
@@ -70,13 +70,13 @@
         }
     }
 
-    class TestRootNode extends RootNode {
+    private static class TestRootNode extends RootNode {
 
-        @Children private TestArgumentNode[] children;
+        @Children private final TestArgumentNode[] children;
 
         TestRootNode(TestArgumentNode[] children) {
             super(null);
-            this.children = adoptChildren(children);
+            this.children = children;
         }
 
         @Override
@@ -89,7 +89,7 @@
         }
     }
 
-    class TestArgumentNode extends Node {
+    private static class TestArgumentNode extends Node {
 
         private final int index;
 
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -61,13 +61,13 @@
         TestChildNode leftChild = new TestChildNode();
         TestChildNode rightChild = new TestChildNode();
         TestRootNode rootNode = new TestRootNode(leftChild, rightChild);
+        CallTarget target = runtime.createCallTarget(rootNode);
         Assert.assertEquals(rootNode, leftChild.getParent());
         Assert.assertEquals(rootNode, rightChild.getParent());
         Iterator<Node> iterator = rootNode.getChildren().iterator();
         Assert.assertEquals(leftChild, iterator.next());
         Assert.assertEquals(rightChild, iterator.next());
         Assert.assertFalse(iterator.hasNext());
-        CallTarget target = runtime.createCallTarget(rootNode);
         Object result = target.call();
         Assert.assertEquals(42, result);
     }
@@ -79,8 +79,8 @@
 
         public TestRootNode(TestChildNode left, TestChildNode right) {
             super(null);
-            this.left = adoptChild(left);
-            this.right = adoptChild(right);
+            this.left = left;
+            this.right = right;
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -55,13 +55,13 @@
         TestChildNode firstChild = new TestChildNode();
         TestChildNode secondChild = new TestChildNode();
         TestRootNode rootNode = new TestRootNode(new TestChildNode[]{firstChild, secondChild});
+        CallTarget target = runtime.createCallTarget(rootNode);
         Assert.assertEquals(rootNode, firstChild.getParent());
         Assert.assertEquals(rootNode, secondChild.getParent());
         Iterator<Node> iterator = rootNode.getChildren().iterator();
         Assert.assertEquals(firstChild, iterator.next());
         Assert.assertEquals(secondChild, iterator.next());
         Assert.assertFalse(iterator.hasNext());
-        CallTarget target = runtime.createCallTarget(rootNode);
         Object result = target.call();
         Assert.assertEquals(42, result);
     }
@@ -72,7 +72,7 @@
 
         public TestRootNode(TestChildNode[] children) {
             super(null);
-            this.children = adoptChildren(children);
+            this.children = children;
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -60,13 +60,13 @@
         Assert.assertEquals(42, result);
     }
 
-    class TestRootNode extends RootNode {
+    private static class TestRootNode extends RootNode {
 
-        @Children TestChildNode[] children;
+        @Children private final TestChildNode[] children;
 
         public TestRootNode(TestChildNode[] children) {
             super(null);
-            this.children = adoptChildren(children);
+            this.children = children;
         }
 
         @Override
@@ -79,7 +79,7 @@
         }
     }
 
-    class TestChildNode extends Node {
+    private static class TestChildNode extends Node {
 
         private final int value;
 
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -64,8 +64,8 @@
 
         public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
             super(null, descriptor);
-            this.left = adoptChild(left);
-            this.right = adoptChild(right);
+            this.left = left;
+            this.right = right;
         }
 
         @Override
@@ -108,7 +108,7 @@
 
         IntAssignLocal(FrameSlot slot, TestChildNode value) {
             super(slot);
-            this.value = adoptChild(value);
+            this.value = value;
         }
 
         @Override
@@ -130,7 +130,7 @@
 
         ObjectAssignLocal(FrameSlot slot, TestChildNode value) {
             super(slot);
-            this.value = adoptChild(value);
+            this.value = value;
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -88,8 +88,8 @@
 
         public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
             super(null, descriptor);
-            this.left = adoptChild(left);
-            this.right = adoptChild(right);
+            this.left = left;
+            this.right = right;
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -59,13 +59,13 @@
         UnresolvedNode leftChild = new UnresolvedNode("20");
         UnresolvedNode rightChild = new UnresolvedNode("22");
         TestRootNode rootNode = new TestRootNode(new ValueNode[]{leftChild, rightChild});
+        CallTarget target = runtime.createCallTarget(rootNode);
         assertEquals(rootNode, leftChild.getParent());
         assertEquals(rootNode, rightChild.getParent());
         Iterator<Node> iterator = rootNode.getChildren().iterator();
         Assert.assertEquals(leftChild, iterator.next());
         Assert.assertEquals(rightChild, iterator.next());
         Assert.assertFalse(iterator.hasNext());
-        CallTarget target = runtime.createCallTarget(rootNode);
         Object result = target.call();
         assertEquals(42, result);
         assertEquals(42, target.call());
@@ -85,7 +85,7 @@
 
         public TestRootNode(ValueNode[] children) {
             super(null);
-            this.children = adoptChildren(children);
+            this.children = children;
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -63,8 +63,8 @@
 
         public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
             super(null, descriptor);
-            this.left = adoptChild(left);
-            this.right = adoptChild(right);
+            this.left = left;
+            this.right = right;
         }
 
         @Override
@@ -115,7 +115,7 @@
 
         IntAssignLocal(FrameSlot slot, TestChildNode value) {
             super(slot);
-            this.value = adoptChild(value);
+            this.value = value;
         }
 
         @Override
@@ -137,7 +137,7 @@
 
         ObjectAssignLocal(FrameSlot slot, TestChildNode value) {
             super(slot);
-            this.value = adoptChild(value);
+            this.value = value;
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,197 @@
+/*
+ * 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.api.test;
+
+import static org.junit.Assert.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Test node rewriting in a tree shared across multiple threads (run with -ea).
+ */
+public class ThreadSafetyTest {
+
+    @Test
+    public void test() throws InterruptedException {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestRootNode rootNode1 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new ConstNode(42)))))));
+        final CallTarget target1 = runtime.createCallTarget(rootNode1);
+        NodeUtil.verify(rootNode1);
+
+        RecursiveCallNode callNode = new RecursiveCallNode(new ConstNode(42));
+        TestRootNode rootNode2 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(callNode))))));
+        final CallTarget target2 = runtime.createCallTarget(rootNode2);
+        callNode.setCallNode(runtime.createCallNode(target2));
+        NodeUtil.verify(rootNode2);
+
+        testTarget(target1, 47, 1_000_000);
+        testTarget(target2, 72, 1_000_000);
+    }
+
+    private static void testTarget(final CallTarget target, final int expectedResult, final int numberOfIterations) throws InterruptedException {
+        ExecutorService executorService = Executors.newFixedThreadPool(20);
+        final AtomicInteger ai = new AtomicInteger();
+        for (int i = 0; i < numberOfIterations; i++) {
+            executorService.submit(new Runnable() {
+                public void run() {
+                    try {
+                        Object result = target.call(new TestArguments(5));
+                        assertEquals(expectedResult, result);
+                        ai.incrementAndGet();
+                    } catch (Throwable t) {
+                        PrintStream out = System.out;
+                        out.println(t);
+                    }
+                }
+            });
+        }
+        executorService.shutdown();
+        executorService.awaitTermination(90, TimeUnit.SECONDS);
+        assertTrue("test did not terminate", executorService.isTerminated());
+        assertEquals(numberOfIterations, ai.get());
+    }
+
+    static class TestArguments extends Arguments {
+        final int arg;
+
+        public TestArguments(int arg) {
+            this.arg = arg;
+        }
+    }
+
+    static class TestRootNode extends RootNode {
+
+        @Child private ValueNode child;
+
+        public TestRootNode(ValueNode child) {
+            super(null);
+            this.child = child;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return child.execute(frame);
+        }
+    }
+
+    abstract static class ValueNode extends Node {
+
+        public ValueNode() {
+            super(null);
+        }
+
+        abstract int execute(VirtualFrame frame);
+    }
+
+    static class RewritingNode extends ValueNode {
+
+        @Child private ValueNode child;
+        private final Random random;
+
+        public RewritingNode(ValueNode child) {
+            this(child, new Random());
+        }
+
+        public RewritingNode(ValueNode child, Random random) {
+            this.child = child;
+            this.random = random;
+        }
+
+        @Override
+        int execute(VirtualFrame frame) {
+            boolean replace = random.nextBoolean();
+            if (replace) {
+                ValueNode newNode = this.replace(new OtherRewritingNode(child, random));
+                return newNode.execute(frame);
+            }
+            return 1 + child.execute(frame);
+        }
+    }
+
+    static class OtherRewritingNode extends ValueNode {
+
+        @Child private ValueNode child;
+        private final Random random;
+
+        public OtherRewritingNode(ValueNode child, Random random) {
+            this.child = child;
+            this.random = random;
+        }
+
+        @Override
+        int execute(VirtualFrame frame) {
+            boolean replace = random.nextBoolean();
+            if (replace) {
+                ValueNode newNode = this.replace(new RewritingNode(child, random));
+                return newNode.execute(frame);
+            }
+            return 1 + child.execute(frame);
+        }
+    }
+
+    static class ConstNode extends ValueNode {
+
+        private final int value;
+
+        ConstNode(int value) {
+            this.value = value;
+        }
+
+        @Override
+        int execute(VirtualFrame frame) {
+            return value;
+        }
+    }
+
+    static class RecursiveCallNode extends ValueNode {
+        @Child CallNode callNode;
+        @Child private ValueNode valueNode;
+
+        RecursiveCallNode(ValueNode value) {
+            this.valueNode = value;
+        }
+
+        @Override
+        int execute(VirtualFrame frame) {
+            int arg = frame.getArguments(TestArguments.class).arg;
+            if (arg > 0) {
+                return (int) callNode.call(frame.pack(), new TestArguments(arg - 1));
+            } else {
+                return valueNode.execute(frame);
+            }
+        }
+
+        void setCallNode(CallNode callNode) {
+            this.callNode = insert(callNode);
+        }
+    }
+}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderDeserializerTest.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderDeserializerTest.java	Sun Mar 30 16:08:33 2014 +0200
@@ -151,6 +151,8 @@
             return;
         }
 
+        expectedAst.adoptChildren();
+
         Assert.assertNotNull(actualAst);
         // fields are asserted using the corresponding equals implementation
         Assert.assertEquals(expectedAst, actualAst);
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestNodes.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestNodes.java	Sun Mar 30 16:08:33 2014 +0200
@@ -84,7 +84,7 @@
         @Child Node child;
 
         public NodeWithOneChild(Node child) {
-            this.child = adoptChild(child);
+            this.child = child;
         }
 
     }
@@ -95,8 +95,8 @@
         @Child Node child2;
 
         public NodeWithTwoChilds(Node child1, Node child2) {
-            this.child1 = adoptChild(child1);
-            this.child2 = adoptChild(child2);
+            this.child1 = child1;
+            this.child2 = child2;
         }
 
     }
@@ -108,9 +108,9 @@
         @Child Node child3;
 
         public NodeWithThreeChilds(Node child1, Node child2, Node child3) {
-            this.child1 = adoptChild(child1);
-            this.child2 = adoptChild(child2);
-            this.child3 = adoptChild(child3);
+            this.child1 = child1;
+            this.child2 = child2;
+            this.child3 = child3;
         }
 
     }
@@ -120,7 +120,7 @@
         @Children private final Node[] childNodes;
 
         NodeWithArray(Node[] children) {
-            this.childNodes = adoptChildren(children);
+            this.childNodes = children;
         }
 
         Node[] getChildNodes() {
@@ -134,8 +134,8 @@
         @Children private final Node[] childNodes2;
 
         NodeWithTwoArray(Node[] childs1, Node[] childs2) {
-            this.childNodes1 = adoptChildren(childs1);
-            this.childNodes2 = adoptChildren(childs2);
+            this.childNodes1 = childs1;
+            this.childNodes2 = childs2;
         }
 
         Node[] getChildNodes1() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Sun Mar 30 16:08:33 2014 +0200
@@ -76,7 +76,7 @@
 
     /**
      * Returns a boolean value indicating whether the method is executed in the interpreter.
-     * 
+     *
      * @return {@code true} when executed in the interpreter, {@code false} in compiled code.
      */
     public static boolean inInterpreter() {
@@ -86,7 +86,7 @@
     /**
      * Directive for the compiler that the given runnable should only be executed in the interpreter
      * and ignored in the compiled code.
-     * 
+     *
      * @param runnable the closure that should only be executed in the interpreter
      */
     public static void interpreterOnly(Runnable runnable) {
@@ -96,7 +96,7 @@
     /**
      * Directive for the compiler that the given callable should only be executed in the
      * interpreter.
-     * 
+     *
      * @param callable the closure that should only be executed in the interpreter
      * @return the result of executing the closure in the interpreter and null in the compiled code
      * @throws Exception If the closure throws an exception when executed in the interpreter.
@@ -109,30 +109,30 @@
      * Injects a probability for the given condition into the probability information of the
      * immediately succeeding branch instruction for the condition. The probability must be a value
      * between 0.0 and 1.0 (inclusive). The condition should not be a combined condition.
-     * 
+     *
      * Example usage immediately before an if statement (it specifies that the likelihood for a to
      * be greater than b is 90%):
-     * 
+     *
      * <code>
      * if (injectBranchProbability(0.9, a > b)) {
      *    // ...
      * }
      * </code>
-     * 
+     *
      * Example usage for a combined condition (it specifies that the likelihood for a to be greater
      * than b is 90% and under the assumption that this is true, the likelihood for a being 0 is
      * 10%):
-     * 
+     *
      * <code>
      * if (injectBranchProbability(0.9, a > b) && injectBranchProbability(0.1, a == 0)) {
      *    // ...
      * }
      * </code>
-     * 
+     *
      * There are predefined constants for commonly used probabilities (see
      * {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY},
      * {@link #FASTPATH_PROBABILITY} ).
-     * 
+     *
      * @param probability the probability value between 0.0 and 1.0 that should be injected
      */
     public static boolean injectBranchProbability(double probability, boolean condition) {
@@ -142,7 +142,7 @@
 
     /**
      * Bails out of a compilation (e.g., for guest language features that should never be compiled).
-     * 
+     *
      * @param reason the reason for the bailout
      */
     public static void bailout(String reason) {
@@ -161,21 +161,37 @@
      * Casts the given value to the value of the given type without any checks. The class must
      * evaluate to a constant. The condition parameter gives a hint to the compiler under which
      * circumstances this cast can be moved to an earlier location in the program.
-     * 
+     *
      * @param value the value that is known to have the specified type
      * @param type the specified new type of the value
      * @param condition the condition that makes this cast safe also at an earlier location of the
      *            program
      * @return the value to be casted to the new type
      */
+    public static <T> T unsafeCast(Object value, Class<T> type, boolean condition) {
+        return unsafeCast(value, type, condition, false);
+    }
+
+    /**
+     * Casts the given value to the value of the given type without any checks. The class must
+     * evaluate to a constant. The condition parameter gives a hint to the compiler under which
+     * circumstances this cast can be moved to an earlier location in the program.
+     *
+     * @param value the value that is known to have the specified type
+     * @param type the specified new type of the value
+     * @param condition the condition that makes this cast safe also at an earlier location of the
+     *            program
+     * @param nonNull whether value is known to never be null
+     * @return the value to be casted to the new type
+     */
     @SuppressWarnings("unchecked")
-    public static <T> T unsafeCast(Object value, Class<T> type, boolean condition) {
+    public static <T> T unsafeCast(Object value, Class<T> type, boolean condition, boolean nonNull) {
         return (T) value;
     }
 
     /**
      * Asserts that this value is not null and retrieved from a call to Frame.materialize.
-     * 
+     *
      * @param value the value that is known to have been obtained via Frame.materialize
      * @return the value to be casted to the new type
      */
@@ -192,7 +208,7 @@
      * the compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -210,7 +226,7 @@
      * compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -228,7 +244,7 @@
      * compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -246,7 +262,7 @@
      * compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -264,7 +280,7 @@
      * compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -282,7 +298,7 @@
      * compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -300,7 +316,7 @@
      * compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -318,7 +334,7 @@
      * the compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -334,7 +350,7 @@
     /**
      * Write a boolean value within an object. The location identity gives a hint to the compiler
      * for improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -348,7 +364,7 @@
     /**
      * Write a byte value within an object. The location identity gives a hint to the compiler for
      * improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -362,7 +378,7 @@
     /**
      * Write a short value within an object. The location identity gives a hint to the compiler for
      * improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -376,7 +392,7 @@
     /**
      * Write an int value within an object. The location identity gives a hint to the compiler for
      * improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -390,7 +406,7 @@
     /**
      * Write a long value within an object. The location identity gives a hint to the compiler for
      * improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -404,7 +420,7 @@
     /**
      * Write a float value within an object. The location identity gives a hint to the compiler for
      * improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -418,7 +434,7 @@
     /**
      * Write a double value within an object. The location identity gives a hint to the compiler for
      * improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -432,7 +448,7 @@
     /**
      * Write an Object value within an object. The location identity gives a hint to the compiler
      * for improved global value numbering.
-     * 
+     *
      * @param receiver the object that is written to
      * @param offset the offset at which to write to the object in bytes
      * @param value the value to be written
@@ -448,7 +464,7 @@
      * to the compiler under which circumstances this access can be moved to an earlier location in
      * the program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -466,7 +482,7 @@
      * the compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -484,7 +500,7 @@
      * to the compiler under which circumstances this access can be moved to an earlier location in
      * the program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -502,7 +518,7 @@
      * the compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -520,7 +536,7 @@
      * the compiler under which circumstances this access can be moved to an earlier location in the
      * program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -538,7 +554,7 @@
      * to the compiler under which circumstances this access can be moved to an earlier location in
      * the program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -556,7 +572,7 @@
      * to the compiler under which circumstances this access can be moved to an earlier location in
      * the program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
@@ -574,7 +590,7 @@
      * to the compiler under which circumstances this access can be moved to an earlier location in
      * the program. The location identity gives a hint to the compiler for improved global value
      * numbering.
-     * 
+     *
      * @param receiver the object that is accessed
      * @param offset the offset at which to access the object in bytes
      * @param condition the condition that makes this access safe also at an earlier location in the
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java	Sun Mar 30 16:08:33 2014 +0200
@@ -37,6 +37,7 @@
     public RootCallTarget(RootNode function) {
         this.rootNode = function;
         this.rootNode.setCallTarget(this);
+        this.rootNode.adoptChildren();
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Sun Mar 30 16:08:33 2014 +0200
@@ -27,6 +27,7 @@
 import java.io.*;
 import java.lang.annotation.*;
 import java.util.*;
+import java.util.concurrent.*;
 
 import com.oracle.truffle.api.*;
 
@@ -133,11 +134,36 @@
      * @param newChildren the array of new children whose parent should be updated
      * @return the array of new children
      */
-    protected final <T extends Node> T[] adoptChildren(T[] newChildren) {
-        if (newChildren != null) {
-            for (T n : newChildren) {
-                adoptChild(n);
-            }
+    @SuppressWarnings("static-method")
+    @Deprecated
+    protected final <T extends Node> T[] adoptChildren(final T[] newChildren) {
+        return newChildren;
+    }
+
+    /**
+     * Method that updates the link to the parent in the specified new child node to this node.
+     * 
+     * @param newChild the new child whose parent should be updated
+     * @return the new child
+     */
+    @SuppressWarnings("static-method")
+    @Deprecated
+    protected final <T extends Node> T adoptChild(final T newChild) {
+        return newChild;
+    }
+
+    /**
+     * Method that updates the link to the parent in the array of specified new child nodes to this
+     * node.
+     * 
+     * @param newChildren the array of new children whose parent should be updated
+     * @return the array of new children
+     */
+    protected final <T extends Node> T[] insert(final T[] newChildren) {
+        CompilerDirectives.transferToInterpreterAndInvalidate();
+        assert newChildren != null;
+        for (Node newChild : newChildren) {
+            adoptHelper(newChild);
         }
         return newChildren;
     }
@@ -148,14 +174,52 @@
      * @param newChild the new child whose parent should be updated
      * @return the new child
      */
-    protected final <T extends Node> T adoptChild(T newChild) {
-        if (newChild != null) {
-            if (newChild == this) {
-                throw new IllegalStateException("The parent of a node can never be the node itself.");
+    protected final <T extends Node> T insert(final T newChild) {
+        CompilerDirectives.transferToInterpreterAndInvalidate();
+        assert newChild != null;
+        adoptHelper(newChild);
+        return newChild;
+    }
+
+    public final void adoptChildren() {
+        CompilerDirectives.transferToInterpreterAndInvalidate();
+        adoptHelper();
+    }
+
+    private void adoptHelper(final Node newChild) {
+        assert newChild != null;
+        if (newChild == this) {
+            throw new IllegalStateException("The parent of a node can never be the node itself.");
+        }
+        newChild.parent = this;
+        newChild.adoptHelper();
+    }
+
+    private void adoptHelper() {
+        Iterable<Node> children = this.getChildren();
+        for (Node child : children) {
+            if (child != null && child.getParent() != this) {
+                this.adoptHelper(child);
             }
-            ((Node) newChild).parent = this;
+        }
+    }
+
+    private void adoptUnadoptedHelper(final Node newChild) {
+        assert newChild != null;
+        if (newChild == this) {
+            throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
-        return newChild;
+        newChild.parent = this;
+        newChild.adoptUnadoptedHelper();
+    }
+
+    private void adoptUnadoptedHelper() {
+        Iterable<Node> children = this.getChildren();
+        for (Node child : children) {
+            if (child != null && child.getParent() == null) {
+                this.adoptUnadoptedHelper(child);
+            }
+        }
     }
 
     /**
@@ -186,54 +250,17 @@
      * @param reason a description of the reason for the replacement
      * @return the new node
      */
-    public final <T extends Node> T replace(T newNode, CharSequence reason) {
+    public final <T extends Node> T replace(final T newNode, final CharSequence reason) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
-        if (this.getParent() == null) {
-            throw new IllegalStateException("This node cannot be replaced, because it does not yet have a parent.");
-        }
-        if (sourceSection != null && newNode.getSourceSection() == null) {
-            // Pass on the source section to the new node.
-            newNode.assignSourceSection(sourceSection);
-        }
-        onReplace(newNode, reason);
-        ((Node) newNode).parent = this.parent;
-        if (!NodeUtil.replaceChild(this.parent, this, newNode)) {
-            fixupTree();
-        }
-        reportReplace(this, newNode, reason);
+        atomic(new Runnable() {
+            public void run() {
+                replaceHelper(newNode, reason);
+            }
+        });
         return newNode;
     }
 
     /**
-     * Rewrite has failed; the tree is likely inconsistent, so fix any stale parent references.
-     * 
-     * This is a rather expensive operation but rare to occur.
-     */
-    private void fixupTree() {
-        Node rootNode = getRootNode();
-        if (rootNode == null) {
-            throw new UnsupportedOperationException("Tree does not have a root node.");
-        }
-        int fixCount = rootNode.fixupChildren();
-        assert fixCount != 0 : "sanity check failed: missing @Child[ren] or adoptChild?";
-        // if nothing had to be fixed, rewrite failed due to node not being a proper child.
-    }
-
-    private int fixupChildren() {
-        int fixCount = 0;
-        for (Node child : getChildren()) {
-            if (child != null) {
-                if (child.parent != this) {
-                    child.parent = this;
-                    fixCount++;
-                }
-                fixCount += child.fixupChildren();
-            }
-        }
-        return fixCount;
-    }
-
-    /**
      * Replaces this node with another node. If there is a source section (see
      * {@link #getSourceSection()}) associated with this node, it is transferred to the new node.
      * 
@@ -244,6 +271,27 @@
         return replace(newNode, "");
     }
 
+    private void replaceHelper(Node newNode, CharSequence reason) {
+        CompilerAsserts.neverPartOfCompilation();
+        if (this.getParent() == null) {
+            throw new IllegalStateException("This node cannot be replaced, because it does not yet have a parent.");
+        }
+        if (sourceSection != null && newNode.getSourceSection() == null) {
+            // Pass on the source section to the new node.
+            newNode.assignSourceSection(sourceSection);
+        }
+        // (aw) need to set parent *before* replace, so that (unsynchronized) getRootNode()
+        // will always find the root node
+        newNode.parent = this.parent;
+        if (NodeUtil.replaceChild(this.parent, this, newNode)) {
+            this.parent.adoptHelper(newNode);
+        } else {
+            this.parent.adoptUnadoptedHelper(newNode);
+        }
+        reportReplace(this, newNode, reason);
+        onReplace(newNode, reason);
+    }
+
     /**
      * Checks if this node is properly adopted by a parent and can be replaced.
      * 
@@ -435,4 +483,32 @@
         sb.append("@").append(Integer.toHexString(hashCode()));
         return sb.toString();
     }
+
+    public final void atomic(Runnable closure) {
+        RootNode rootNode = getRootNode();
+        if (rootNode != null) {
+            synchronized (rootNode) {
+                closure.run();
+            }
+        } else {
+            closure.run();
+        }
+    }
+
+    public final <T> T atomic(Callable<T> closure) {
+        try {
+            RootNode rootNode = getRootNode();
+            if (rootNode != null) {
+                synchronized (rootNode) {
+                    return closure.call();
+                }
+            } else {
+                return closure.call();
+            }
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Sun Mar 30 16:08:33 2014 +0200
@@ -122,6 +122,20 @@
                 return unsafe.getObject(node, offset);
             }
         }
+
+        @Override
+        public int hashCode() {
+            return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof NodeField) {
+                NodeField other = (NodeField) obj;
+                return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind);
+            }
+            return false;
+        }
     }
 
     /**
@@ -198,6 +212,21 @@
         public long[] getChildrenOffsets() {
             return childrenOffsets;
         }
+
+        @Override
+        public int hashCode() {
+            return Arrays.hashCode(fields) ^ Arrays.hashCode(childOffsets) ^ Arrays.hashCode(childrenOffsets) ^ ((Long) parentOffset).hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof NodeClass) {
+                NodeClass other = (NodeClass) obj;
+                return Arrays.equals(fields, other.fields) && Arrays.equals(childOffsets, other.childOffsets) && Arrays.equals(childrenOffsets, other.childrenOffsets) &&
+                                parentOffset == other.parentOffset;
+            }
+            return false;
+        }
     }
 
     static class NodeIterator implements Iterator<Node> {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Sun Mar 30 16:08:33 2014 +0200
@@ -24,6 +24,8 @@
  */
 package com.oracle.truffle.api.nodes;
 
+import com.oracle.truffle.api.*;
+
 /**
  * An exception that should be thrown if the return value cannot be represented as a value of the
  * return type. The Truffle optimizer has special knowledge of this exception class and will never
@@ -41,6 +43,7 @@
      * @param result the alternative result
      */
     public UnexpectedResultException(Object result) {
+        CompilerDirectives.transferToInterpreter();
         this.result = result;
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -62,7 +62,7 @@
      */
     protected void internalAppendProbe(InstrumentationProbeNode newProbeNode) {
         if (next == null) {
-            this.next = adoptChild(newProbeNode);
+            this.next = insert(newProbeNode);
         } else {
             next.internalAppendProbe(newProbeNode);
         }
@@ -75,7 +75,7 @@
             if (oldProbeNode.next == null) {
                 this.next = null;
             } else {
-                this.next = adoptChild(oldProbeNode.next);
+                this.next = insert(oldProbeNode.next);
                 oldProbeNode.next = null;
             }
         } else {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Sun Mar 30 16:08:33 2014 +0200
@@ -98,13 +98,17 @@
         return param.getLocalName();
     }
 
-    private static CodeTree createAccessChild(NodeExecutionData targetExecution) {
+    private static CodeTree createAccessChild(NodeExecutionData targetExecution, String thisReference) {
+        String reference = thisReference;
+        if (reference == null) {
+            reference = "this";
+        }
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         Element accessElement = targetExecution.getChild().getAccessElement();
         if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) {
-            builder.string("this.").string(targetExecution.getChild().getName());
+            builder.string(reference).string(".").string(targetExecution.getChild().getName());
         } else if (accessElement.getKind() == ElementKind.FIELD) {
-            builder.string("this.").string(accessElement.getSimpleName().toString());
+            builder.string(reference).string(".").string(accessElement.getSimpleName().toString());
         } else {
             throw new AssertionError();
         }
@@ -357,7 +361,7 @@
                     nodes.nullLiteral();
                     arguments.string(valueName(parameter.getPreviousParameter()));
                 }
-                nodes.tree(createAccessChild(executionData));
+                nodes.tree(createAccessChild(executionData, null));
                 arguments.string(valueName(parameter));
                 empty = false;
             }
@@ -928,12 +932,6 @@
                     var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation()));
                     clazz.add(var);
 
-                    CodeExecutableElement setter = new CodeExecutableElement(modifiers(PROTECTED), context.getType(void.class), "setNext0");
-                    setter.getParameters().add(new CodeVariableElement(clazz.asType(), "next0"));
-                    CodeTreeBuilder builder = setter.createBuilder();
-                    builder.statement("this.next0 = adoptChild(next0)");
-                    clazz.add(setter);
-
                     CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getPolymorphicSpecialization());
                     clazz.add(genericCachedExecute);
 
@@ -948,41 +946,21 @@
             }
 
             if (needsInvokeCopyConstructorMethod()) {
-                clazz.add(createInvokeCopyConstructor(clazz.asType(), null));
-                clazz.add(createCopyPolymorphicConstructor(clazz.asType()));
+                clazz.add(createCopy(clazz.asType(), null));
             }
 
             if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) {
                 clazz.add(createGenericExecute(node, rootGroup));
             }
 
-            clazz.add(createGetCost(node, null, NodeCost.MONOMORPHIC));
         }
 
         protected boolean needsInvokeCopyConstructorMethod() {
             return getModel().getNode().isPolymorphic();
         }
 
-        protected CodeExecutableElement createGetCost(NodeData node, SpecializationData specialization, NodeCost cost) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getNodeCost(), "getCost");
-
-            TypeMirror nodeInfoKind = context.getTruffleTypes().getNodeCost();
-
-            CodeTreeBuilder builder = method.createBuilder();
-            if (node.isPolymorphic() && specialization == null) {
-                // assume next0 exists
-                builder.startIf().string("next0 != null && next0.getCost() != ").staticReference(nodeInfoKind, "UNINITIALIZED").end();
-                builder.startBlock();
-                builder.startReturn().staticReference(nodeInfoKind, "POLYMORPHIC").end();
-                builder.end();
-            }
-
-            builder.startReturn().staticReference(nodeInfoKind, cost.name()).end();
-            return method;
-        }
-
-        protected CodeExecutableElement createInvokeCopyConstructor(TypeMirror baseType, SpecializationData specialization) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), baseType, "invokeCopyConstructor");
+        protected CodeExecutableElement createCopy(TypeMirror baseType, SpecializationData specialization) {
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), baseType, "copyWithConstructor");
             if (specialization == null) {
                 method.getModifiers().add(ABSTRACT);
             } else {
@@ -998,36 +976,6 @@
             return method;
         }
 
-        protected CodeExecutableElement createCopyPolymorphicConstructor(TypeMirror baseType) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), baseType, "copyPolymorphic");
-            CodeTreeBuilder builder = method.createBuilder();
-            CodeTreeBuilder nullBuilder = builder.create();
-            CodeTreeBuilder oldBuilder = builder.create();
-            CodeTreeBuilder resetBuilder = builder.create();
-
-            for (ActualParameter param : getModel().getSignatureParameters()) {
-                NodeExecutionData execution = param.getSpecification().getExecution();
-
-                CodeTree access = createAccessChild(execution);
-
-                String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName());
-                oldBuilder.declaration(execution.getChild().getNodeData().getNodeType(), oldName, access);
-                nullBuilder.startStatement().tree(access).string(" = null").end();
-                resetBuilder.startStatement().tree(access).string(" = ").string(oldName).end();
-            }
-
-            builder.tree(oldBuilder.getRoot());
-            builder.tree(nullBuilder.getRoot());
-
-            builder.startStatement().type(baseType).string(" copy = ");
-            builder.startCall("invokeCopyConstructor").end();
-            builder.end();
-
-            builder.tree(resetBuilder.getRoot());
-            builder.startReturn().string("copy").end();
-            return method;
-        }
-
         private List<CodeExecutableElement> createImplicitChildrenAccessors() {
             NodeData node = getModel().getNode();
             // Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>();
@@ -1210,7 +1158,6 @@
                 String fieldName = var.getSimpleName().toString();
 
                 CodeTree init = createStaticCast(builder, child, fieldName);
-                init = createAdoptChild(builder, var.asType(), init);
 
                 builder.string("this.").string(fieldName).string(" = ").tree(init);
                 builder.end();
@@ -1229,18 +1176,6 @@
             return CodeTreeBuilder.singleString(fieldName);
         }
 
-        private CodeTree createAdoptChild(CodeTreeBuilder parent, TypeMirror type, CodeTree value) {
-            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            if (Utils.isAssignable(getContext(), type, getContext().getTruffleTypes().getNode())) {
-                builder.string("adoptChild(").tree(value).string(")");
-            } else if (Utils.isAssignable(getContext(), type, getContext().getTruffleTypes().getNodeArray())) {
-                builder.string("adoptChildren(").tree(value).string(")");
-            } else {
-                builder.tree(value);
-            }
-            return builder.getRoot();
-        }
-
         private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor, ExecutableElement sourceSectionConstructor) {
             CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
             CodeTreeBuilder builder = method.createBuilder();
@@ -1261,7 +1196,7 @@
                 if (Utils.isAssignable(getContext(), varType, getContext().getTruffleTypes().getNodeArray())) {
                     copyAccess += ".clone()";
                 }
-                CodeTree init = createAdoptChild(builder, varType, CodeTreeBuilder.singleString(copyAccess));
+                CodeTree init = CodeTreeBuilder.singleString(copyAccess);
                 builder.startStatement().string("this.").string(varName).string(" = ").tree(init).end();
             }
 
@@ -1293,7 +1228,7 @@
 
         private CodeExecutableElement createGenericExecuteAndSpecialize(final NodeData node, SpecializationGroup rootGroup) {
             TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_SPECIALIZE_NAME);
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), genericReturnType, EXECUTE_SPECIALIZE_NAME);
             method.addParameter(new CodeVariableElement(getContext().getType(int.class), "minimumState"));
             addInternalValueParameters(method, node.getGenericSpecialization(), true, false);
             method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason"));
@@ -1354,7 +1289,7 @@
 
         private CodeExecutableElement createGenericExecute(NodeData node, SpecializationGroup group) {
             TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_GENERIC_NAME);
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), genericReturnType, EXECUTE_GENERIC_NAME);
 
             if (!node.needsFrame(getContext())) {
                 method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath()));
@@ -1829,11 +1764,16 @@
             String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization());
             CodeTreeBuilder builder = parent.create();
 
-            builder.declaration(getElement().asType(), "currentCopy", currentNode + ".copyPolymorphic()");
+            builder.declaration(getElement().asType(), "currentCopy", currentNode + ".copyWithConstructor()");
+            for (ActualParameter param : getModel().getSignatureParameters()) {
+                NodeExecutionData execution = param.getSpecification().getExecution();
+                builder.startStatement().tree(createAccessChild(execution, "currentCopy")).string(" = ").nullLiteral().end();
+            }
+            builder.startStatement().string("currentCopy.next0 = ").startNew(uninitializedName).string("currentCopy").end().end();
+
             builder.declaration(polyClassName, "polymorphic", builder.create().startNew(polyClassName).string(currentNode).end());
+            builder.startStatement().string("polymorphic.next0 = ").string("currentCopy").end();
             builder.startStatement().startCall(currentNode, "replace").string("polymorphic").string("message").end().end();
-            builder.startStatement().startCall("polymorphic", "setNext0").string("currentCopy").end().end();
-            builder.startStatement().startCall("currentCopy", "setNext0").startNew(uninitializedName).string(currentNode).end().end().end();
 
             builder.startReturn();
             builder.startCall("currentCopy.next0", EXECUTE_POLYMORPHIC_NAME);
@@ -2313,7 +2253,7 @@
         private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, ActualParameter unexpectedParameter) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (targetExecution != null) {
-                builder.tree(createAccessChild(targetExecution));
+                builder.tree(createAccessChild(targetExecution, null));
                 builder.string(".");
             }
 
@@ -2478,7 +2418,7 @@
             }
             CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node), baseType, false);
 
-            clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.NONE));
+            clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.POLYMORPHIC));
 
             for (ActualParameter polymorphParameter : polymorph.getSignatureParameters()) {
                 if (!polymorphParameter.getTypeSystemType().isGeneric()) {
@@ -2521,11 +2461,10 @@
             }
 
             if (needsInvokeCopyConstructorMethod()) {
-                clazz.add(createInvokeCopyConstructor(nodeGen.asType(), specialization));
+                clazz.add(createCopy(nodeGen.asType(), specialization));
             }
 
             createCachedExecuteMethods(specialization);
-            clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.NONE));
         }
 
         private ExecutableElement createUpdateType(ActualParameter parameter) {
@@ -2571,7 +2510,7 @@
             } else if (specialization.isUninitialized()) {
                 cost = NodeCost.UNINITIALIZED;
             } else if (specialization.isPolymorphic()) {
-                cost = NodeCost.NONE;
+                cost = NodeCost.POLYMORPHIC;
             } else if (specialization.isSpecialized()) {
                 cost = NodeCost.MONOMORPHIC;
             } else {
@@ -2607,13 +2546,7 @@
                 getElement().add(createUpdateTypes(nodeGen.asType()));
             }
             if (needsInvokeCopyConstructorMethod()) {
-                clazz.add(createInvokeCopyConstructor(nodeGen.asType(), specialization));
-            }
-
-            if (specialization.isGeneric()) {
-                clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.MEGAMORPHIC));
-            } else if (specialization.isUninitialized()) {
-                clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.UNINITIALIZED));
+                clazz.add(createCopy(nodeGen.asType(), specialization));
             }
         }
 
@@ -2644,7 +2577,7 @@
 
                 if (node.isPolymorphic()) {
                     if (specialization.isSpecialized() || specialization.isPolymorphic()) {
-                        builder.statement("this.next0 = adoptChild(copy.next0)");
+                        builder.statement("this.next0 = copy.next0");
                     }
                 }
                 if (superConstructor != null) {
@@ -2739,9 +2672,9 @@
             builder.end();
 
             builder.startElseBlock();
-            builder.startStatement().startCall("setNext0");
+            builder.startStatement().string("next0 = ");
             builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end();
-            builder.end().end();
+            builder.end();
 
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(builder);
             specializeCall.startCall(EXECUTE_SPECIALIZE_NAME);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -52,7 +52,7 @@
         super(null, frameDescriptor);
         /* Deep copy the body before any specialization occurs during execution. */
         this.uninitializedBodyNode = NodeUtil.cloneNode(bodyNode);
-        this.bodyNode = adoptChild(bodyNode);
+        this.bodyNode = bodyNode;
         this.name = name;
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -53,9 +53,9 @@
 
     protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) {
         this.cachedFunction = cachedFunction;
-        this.callCachedTargetNode = adoptChild(Truffle.getRuntime().createCallNode(cachedFunction.getCallTarget()));
+        this.callCachedTargetNode = Truffle.getRuntime().createCallNode(cachedFunction.getCallTarget());
         this.cachedTargetStable = cachedFunction.getCallTargetStable();
-        this.nextNode = adoptChild(next);
+        this.nextNode = next;
     }
 
     /**
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -48,9 +48,9 @@
     @Child protected SLAbstractDispatchNode dispatchNode;
 
     private SLInvokeNode(SLExpressionNode functionNode, SLExpressionNode[] argumentNodes, SLAbstractDispatchNode dispatchNode) {
-        this.functionNode = adoptChild(functionNode);
-        this.argumentNodes = adoptChildren(argumentNodes);
-        this.dispatchNode = adoptChild(dispatchNode);
+        this.functionNode = functionNode;
+        this.argumentNodes = argumentNodes;
+        this.dispatchNode = dispatchNode;
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -45,7 +45,7 @@
          * It is a Truffle requirement to call adoptChildren(), which performs all the necessary
          * steps to add the new children to the node tree.
          */
-        this.bodyNodes = adoptChildren(bodyNodes);
+        this.bodyNodes = bodyNodes;
     }
 
     /**
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -54,7 +54,7 @@
          * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
          * to add the new child to the node tree.
          */
-        this.bodyNode = adoptChild(bodyNode);
+        this.bodyNode = bodyNode;
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -57,9 +57,9 @@
          * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
          * to add the new child to the node tree.
          */
-        this.conditionNode = adoptChild(conditionNode);
-        this.thenPartNode = adoptChild(thenPartNode);
-        this.elsePartNode = adoptChild(elsePartNode);
+        this.conditionNode = conditionNode;
+        this.thenPartNode = thenPartNode;
+        this.elsePartNode = elsePartNode;
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -40,7 +40,7 @@
     @Child private SLExpressionNode valueNode;
 
     public SLReturnNode(SLExpressionNode valueNode) {
-        this.valueNode = adoptChild(valueNode);
+        this.valueNode = valueNode;
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -55,8 +55,8 @@
          * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps
          * to add the new child to the node tree.
          */
-        this.conditionNode = adoptChild(conditionNode);
-        this.bodyNode = adoptChild(bodyNode);
+        this.conditionNode = conditionNode;
+        this.bodyNode = bodyNode;
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -16,7 +16,7 @@
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 
+ * Please 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/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/demo/SLAddWithoutSpecializationNode.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/demo/SLAddWithoutSpecializationNode.java	Sun Mar 30 16:08:33 2014 +0200
@@ -42,8 +42,8 @@
     @Child private SLExpressionNode rightNode;
 
     public SLAddWithoutSpecializationNode(SLExpressionNode leftNode, SLExpressionNode rightNode) {
-        this.leftNode = adoptChild(leftNode);
-        this.rightNode = adoptChild(rightNode);
+        this.leftNode = leftNode;
+        this.rightNode = rightNode;
     }
 
     @Override
--- a/graal/findbugsExcludeFilter.xml	Wed Mar 19 11:43:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-<FindBugsFilter>
-
-  <Match>
-    <Class name="com.oracle.graal.hotspot.CompilationTask" />
-    <Method name="run" />
-    <Bug pattern="NN_NAKED_NOTIFY" />
-  </Match>
-
-  <!-- justification = "concurrent abstraction calls are in synchronized block" -->
-  <Match>
-    <Class name="com.oracle.graal.hotspot.debug.BenchmarkCounters" />
-    <Method name="getIndex" />
-    <Bug pattern="AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION" />
-  </Match>
-
-  <!-- justification = "counters are only used for statistics" -->
-  <Match>
-    <Class name="com.oracle.graal.hotspot.meta.HotSpotGraphCache" />
-    <Or>
-      <Method name="get" />
-      <Method name="put" />
-      <Method name="removeGraphs" />
-    </Or>
-    <Bug pattern="VO_VOLATILE_INCREMENT" />
-  </Match>
-
-  <!-- justification = "reference equality on the receiver is what we want" -->
-  <Match>
-    <Class name="com.oracle.graal.replacements.StringSubstitutions" />
-    <Method name="equals" />
-    <Bug pattern="ES_COMPARING_PARAMETER_STRING_WITH_EQ" />
-  </Match>
-
-  <!-- justification = "reference equality to test whether string is interned" -->
-  <Match>
-    <Class name="com.oracle.graal.hotspot.phases.AheadOfTimeVerificationPhase" />
-    <Method name="isInternedString" />
-    <Bug pattern="ES_COMPARING_STRINGS_WITH_EQ" />
-  </Match>
-
-</FindBugsFilter>
--- a/mx/mx_graal.py	Wed Mar 19 11:43:57 2014 +0100
+++ b/mx/mx_graal.py	Sun Mar 30 16:08:33 2014 +0200
@@ -79,7 +79,8 @@
 
 _make_eclipse_launch = False
 
-_minVersion = mx.VersionSpec('1.7.0_04')
+# @CallerSensitive introduced in 7u25
+_minVersion = mx.VersionSpec('1.7.0_25')
 
 JDK_UNIX_PERMISSIONS = 0755
 
@@ -583,7 +584,7 @@
         if not exists(vmDir):
             if mx.get_os() != 'windows':
                 chmodRecursive(jdk, JDK_UNIX_PERMISSIONS)
-            mx.log('Creating VM directory in JDK7: ' + vmDir)
+            mx.log('Creating VM directory in JDK: ' + vmDir)
             os.makedirs(vmDir)
 
         def filterXusage(line):
@@ -647,11 +648,17 @@
             env.setdefault('ALT_BOOTDIR', mx.java().jdk)
 
             # extract latest release tag for graal
-            tags = [x.split(' ')[0] for x in subprocess.check_output(['hg', 'tags']).split('\n') if x.startswith("graal-")]
+            try:
+                tags = [x.split(' ')[0] for x in subprocess.check_output(['hg', 'tags']).split('\n') if x.startswith("graal-")]
+            except:
+                # not a mercurial repository or hg commands are not available.
+                tags = None
+
             if tags:
                 # extract the most recent tag
                 tag = sorted(tags, key=lambda e: [int(x) for x in e[len("graal-"):].split('.')], reverse=True)[0]
                 env.setdefault('USER_RELEASE_SUFFIX', tag)
+
             if not mx._opts.verbose:
                 runCmd.append('MAKE_VERBOSE=')
             env['JAVA_HOME'] = jdk
@@ -784,7 +791,7 @@
     matches = lambda line: len([a for a in annotations if line == a or line.startswith(a + '(')]) != 0
     return p.find_classes_with_matching_source_line(pkgRoot, matches, includeInnerClasses)
 
-def _extract_VM_args(args, allowClasspath=False, useDoubleDash=False):
+def _extract_VM_args(args, allowClasspath=False, useDoubleDash=False, defaultAllVMArgs=True):
     """
     Partitions a command line into a leading sequence of HotSpot VM options and the rest.
     """
@@ -805,7 +812,10 @@
                 remainder = args[i:]
                 return vmArgs, remainder
 
-    return args, []
+    if defaultAllVMArgs:
+        return args, []
+    else:
+        return [], args
 
 def _run_tests(args, harness, annotations, testfile):
 
@@ -991,34 +1001,34 @@
 
     with VM('graal', 'fastdebug'):
         t = Task('BootstrapWithSystemAssertions:fastdebug')
-        vm(['-esa', '-version'])
+        vm(['-esa', '-XX:-TieredCompilation', '-version'])
         tasks.append(t.stop())
 
     with VM('graal', 'fastdebug'):
-        t = Task('NoTieredBootstrapWithSystemAssertions:fastdebug')
-        vm(['-esa', '-XX:-TieredCompilation', '-version'])
+        t = Task('BootstrapWithSystemAssertionsNoCoop:fastdebug')
+        vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version'])
         tasks.append(t.stop())
 
     with VM('graal', 'product'):
         t = Task('BootstrapWithGCVerification:product')
         out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
-        vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
+        vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
         tasks.append(t.stop())
 
     with VM('graal', 'product'):
         t = Task('BootstrapWithG1GCVerification:product')
         out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
-        vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
+        vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
         tasks.append(t.stop())
 
     with VM('graal', 'product'):
         t = Task('BootstrapWithRegisterPressure:product')
-        vm(['-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
+        vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
         tasks.append(t.stop())
 
     with VM('graal', 'product'):
         t = Task('BootstrapWithImmutableCode:product')
-        vm(['-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version'])
+        vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version'])
         tasks.append(t.stop())
 
     with VM('server', 'product'):  # hosted mode
@@ -1027,11 +1037,7 @@
         tasks.append(t.stop())
 
     for vmbuild in ['fastdebug', 'product']:
-        for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
-            if 'eclipse' in str(test) and mx.java().version >= mx.VersionSpec('1.8'):
-                # DaCapo eclipse doesn't run under JDK8
-                continue
-
+        for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
             t = Task(str(test) + ':' + vmbuild)
             if not test.test('graal'):
                 t.abort(test.name + ' Failed')
@@ -1139,6 +1145,16 @@
             t.abort('Checkstyle warnings were found')
         tasks.append(t.stop())
 
+        t = Task('Checkheaders')
+        if checkheaders([]) != 0:
+            t.abort('Checkheaders warnings were found')
+        tasks.append(t.stop())
+
+        t = Task('FindBugs')
+        if findbugs([]) != 0:
+            t.abort('FindBugs warnings were found')
+        tasks.append(t.stop())
+
         if exists('jacoco.exec'):
             os.unlink('jacoco.exec')
 
@@ -1680,20 +1696,53 @@
     nonTestProjects = [p for p in mx.projects() if not p.name.endswith('.test') and not p.name.endswith('.jtt')]
     outputDirs = [p.output_dir() for p in nonTestProjects]
     findbugsResults = join(_graal_home, 'findbugs.results')
-    exitcode = mx.run_java(['-jar', findbugsJar, '-textui', '-low', '-maxRank', '15', '-exclude', join(_graal_home, 'graal', 'findbugsExcludeFilter.xml'),
-                 '-auxclasspath', mx.classpath([p.name for p in nonTestProjects]), '-output', findbugsResults, '-progress', '-exitcode'] + args + outputDirs, nonZeroIsFatal=False)
+
+    cmd = ['-jar', findbugsJar, '-textui', '-low', '-maxRank', '15']
+    if sys.stdout.isatty():
+        cmd.append('-progress')
+    cmd = cmd + ['-auxclasspath', mx.classpath([p.name for p in nonTestProjects]), '-output', findbugsResults, '-exitcode'] + args + outputDirs
+    exitcode = mx.run_java(cmd, nonZeroIsFatal=False)
     if exitcode != 0:
         with open(findbugsResults) as fp:
             mx.log(fp.read())
     os.unlink(findbugsResults)
     return exitcode
 
+def checkheaders(args):
+    """check Java source headers against any required pattern"""
+    failures = {}
+    for p in mx.projects():
+        if p.native:
+            continue
+
+        csConfig = join(mx.project(p.checkstyleProj).dir, '.checkstyle_checks.xml')
+        dom = xml.dom.minidom.parse(csConfig)
+        for module in dom.getElementsByTagName('module'):
+            if module.getAttribute('name') == 'RegexpHeader':
+                for prop in module.getElementsByTagName('property'):
+                    if prop.getAttribute('name') == 'header':
+                        value = prop.getAttribute('value')
+                        matcher = re.compile(value, re.MULTILINE)
+                        for sourceDir in p.source_dirs():
+                            for root, _, files in os.walk(sourceDir):
+                                for name in files:
+                                    if name.endswith('.java') and name != 'package-info.java':
+                                        f = join(root, name)
+                                        with open(f) as fp:
+                                            content = fp.read()
+                                        if not matcher.match(content):
+                                            failures[f] = csConfig
+    for n, v in failures.iteritems():
+        mx.log('{}: header does not match RegexpHeader defined in {}'.format(n, v))
+    return len(failures)
+
 def mx_init(suite):
     commands = {
         'build': [build, ''],
         'buildvars': [buildvars, ''],
         'buildvms': [buildvms, '[-options]'],
         'c1visualizer' : [c1visualizer, ''],
+        'checkheaders': [checkheaders, ''],
         'clean': [clean, ''],
         'findbugs': [findbugs, ''],
         'generateZshCompletion' : [generateZshCompletion, ''],
--- a/mx/projects	Wed Mar 19 11:43:57 2014 +0100
+++ b/mx/projects	Sun Mar 30 16:08:33 2014 +0200
@@ -13,6 +13,9 @@
 library@CHECKSTYLE@path=lib/checkstyle-5.5-all.jar
 library@CHECKSTYLE@urls=jar:http://sourceforge.net/projects/checkstyle/files/checkstyle/5.5/checkstyle-5.5-bin.zip/download!/checkstyle-5.5/checkstyle-5.5-all.jar
 
+library@FINDBUGS@path=lib/findbugs-3.0.0-dev-20131204-e3cbbd5.jar
+library@FINDBUGS@urls=jar:http://sourceforge.net/projects/findbugs/files/findbugs/3.0.0/findbugs-3.0.0-dev-20131204-e3cbbd5.zip/download!/findbugs-3.0.0-dev-20131204-e3cbbd5/lib/findbugs.jar
+
 library@DACAPO@path=lib/dacapo-9.12-bach.jar
 library@DACAPO@urls=http://softlayer.dl.sourceforge.net/project/dacapobench/9.12-bach/dacapo-9.12-bach.jar
 
@@ -38,6 +41,10 @@
 library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar
 library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar
 
+library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@sha1=64c0a5329fbcb8284640e58d83252e0a3b08c23e
+
 distribution@GRAAL@path=graal.jar
 distribution@GRAAL@dependencies=\
 com.oracle.graal.hotspot.amd64,\
@@ -47,12 +54,13 @@
 com.oracle.graal.hotspot.sparc,\
 com.oracle.graal.hotspot,\
 com.oracle.graal.hotspot.hsail
+distribution@GRAAL@excludeLibs=FINDBUGS
 
 # graal.api.runtime
 project@com.oracle.graal.api.runtime@subDir=graal
 project@com.oracle.graal.api.runtime@sourceDirs=src
 project@com.oracle.graal.api.runtime@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.api.runtime@javaCompliance=1.7
+project@com.oracle.graal.api.runtime@javaCompliance=1.8
 project@com.oracle.graal.api.runtime@workingSets=API,Graal
 
 # graal.api.test
@@ -60,14 +68,14 @@
 project@com.oracle.graal.api.test@sourceDirs=src
 project@com.oracle.graal.api.test@dependencies=JUNIT,com.oracle.graal.api.runtime
 project@com.oracle.graal.api.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.api.test@javaCompliance=1.7
+project@com.oracle.graal.api.test@javaCompliance=1.8
 project@com.oracle.graal.api.test@workingSets=API,Graal,Test
 
 # graal.api.meta
 project@com.oracle.graal.api.meta@subDir=graal
 project@com.oracle.graal.api.meta@sourceDirs=src
 project@com.oracle.graal.api.meta@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.api.meta@javaCompliance=1.7
+project@com.oracle.graal.api.meta@javaCompliance=1.8
 project@com.oracle.graal.api.meta@workingSets=API,Graal
 
 # graal.api.meta.test
@@ -75,7 +83,7 @@
 project@com.oracle.graal.api.meta.test@sourceDirs=src
 project@com.oracle.graal.api.meta.test@dependencies=JUNIT,com.oracle.graal.runtime,com.oracle.graal.java
 project@com.oracle.graal.api.meta.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.api.meta.test@javaCompliance=1.7
+project@com.oracle.graal.api.meta.test@javaCompliance=1.8
 project@com.oracle.graal.api.meta.test@workingSets=API,Graal,Test
 
 # graal.api.meta.jdk8.test
@@ -91,7 +99,7 @@
 project@com.oracle.graal.api.code@sourceDirs=src
 project@com.oracle.graal.api.code@dependencies=com.oracle.graal.api.meta
 project@com.oracle.graal.api.code@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.api.code@javaCompliance=1.7
+project@com.oracle.graal.api.code@javaCompliance=1.8
 project@com.oracle.graal.api.code@workingSets=API,Graal
 
 # graal.api.replacements
@@ -99,7 +107,7 @@
 project@com.oracle.graal.api.replacements@sourceDirs=src
 project@com.oracle.graal.api.replacements@dependencies=com.oracle.graal.api.meta
 project@com.oracle.graal.api.replacements@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.api.replacements@javaCompliance=1.7
+project@com.oracle.graal.api.replacements@javaCompliance=1.8
 project@com.oracle.graal.api.replacements@workingSets=API,Graal,Replacements
 
 # graal.service.processor
@@ -107,7 +115,7 @@
 project@com.oracle.graal.service.processor@sourceDirs=src
 project@com.oracle.graal.service.processor@dependencies=com.oracle.graal.api.runtime
 project@com.oracle.graal.service.processor@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.service.processor@javaCompliance=1.7
+project@com.oracle.graal.service.processor@javaCompliance=1.8
 project@com.oracle.graal.service.processor@workingSets=Codegen,HotSpot
 
 # graal.amd64
@@ -115,7 +123,7 @@
 project@com.oracle.graal.amd64@sourceDirs=src
 project@com.oracle.graal.amd64@dependencies=com.oracle.graal.api.code
 project@com.oracle.graal.amd64@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.amd64@javaCompliance=1.7
+project@com.oracle.graal.amd64@javaCompliance=1.8
 project@com.oracle.graal.amd64@workingSets=Graal,AMD64
 
 # graal.ptx
@@ -123,7 +131,7 @@
 project@com.oracle.graal.ptx@sourceDirs=src
 project@com.oracle.graal.ptx@dependencies=com.oracle.graal.api.code
 project@com.oracle.graal.ptx@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.ptx@javaCompliance=1.7
+project@com.oracle.graal.ptx@javaCompliance=1.8
 project@com.oracle.graal.ptx@workingSets=Graal,PTX
 
 # graal.sparc
@@ -131,16 +139,16 @@
 project@com.oracle.graal.sparc@sourceDirs=src
 project@com.oracle.graal.sparc@dependencies=com.oracle.graal.api.code
 project@com.oracle.graal.sparc@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.sparc@javaCompliance=1.7
+project@com.oracle.graal.sparc@javaCompliance=1.8
 project@com.oracle.graal.sparc@workingSets=Graal,SPARC
 
 # graal.hotspot
 project@com.oracle.graal.hotspot@subDir=graal
 project@com.oracle.graal.hotspot@sourceDirs=src
-project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer
+project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer,com.oracle.graal.baseline
 project@com.oracle.graal.hotspot@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.hotspot@annotationProcessors=com.oracle.graal.replacements.verifier,com.oracle.graal.service.processor
-project@com.oracle.graal.hotspot@javaCompliance=1.7
+project@com.oracle.graal.hotspot@javaCompliance=1.8
 project@com.oracle.graal.hotspot@workingSets=Graal,HotSpot
 
 # graal.hotspot.amd64
@@ -149,7 +157,7 @@
 project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.compiler.amd64,com.oracle.graal.hotspot,com.oracle.graal.replacements.amd64
 project@com.oracle.graal.hotspot.amd64@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.hotspot.amd64@annotationProcessors=com.oracle.graal.service.processor
-project@com.oracle.graal.hotspot.amd64@javaCompliance=1.7
+project@com.oracle.graal.hotspot.amd64@javaCompliance=1.8
 project@com.oracle.graal.hotspot.amd64@workingSets=Graal,HotSpot,AMD64
 
 # graal.hotspot.sparc
@@ -158,25 +166,25 @@
 project@com.oracle.graal.hotspot.sparc@dependencies=com.oracle.graal.compiler.sparc
 project@com.oracle.graal.hotspot.sparc@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.hotspot.sparc@annotationProcessors=com.oracle.graal.service.processor
-project@com.oracle.graal.hotspot.sparc@javaCompliance=1.7
+project@com.oracle.graal.hotspot.sparc@javaCompliance=1.8
 project@com.oracle.graal.hotspot.sparc@workingSets=Graal,HotSpot,SPARC
 
 # graal.hotspot.ptx
 project@com.oracle.graal.hotspot.ptx@subDir=graal
 project@com.oracle.graal.hotspot.ptx@sourceDirs=src
-project@com.oracle.graal.hotspot.ptx@dependencies=com.oracle.graal.ptx,com.oracle.graal.compiler.ptx,com.oracle.graal.hotspot
+project@com.oracle.graal.hotspot.ptx@dependencies=com.oracle.graal.ptx,com.oracle.graal.compiler.ptx,com.oracle.graal.hotspot,com.oracle.graal.gpu
 project@com.oracle.graal.hotspot.ptx@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.hotspot.ptx@annotationProcessors=com.oracle.graal.service.processor
-project@com.oracle.graal.hotspot.ptx@javaCompliance=1.7
+project@com.oracle.graal.hotspot.ptx@javaCompliance=1.8
 project@com.oracle.graal.hotspot.ptx@workingSets=Graal,HotSpot,PTX
 
 # graal.hotspot.hsail
 project@com.oracle.graal.hotspot.hsail@subDir=graal
 project@com.oracle.graal.hotspot.hsail@sourceDirs=src
-project@com.oracle.graal.hotspot.hsail@dependencies=com.oracle.graal.replacements.hsail,com.oracle.graal.hotspot
+project@com.oracle.graal.hotspot.hsail@dependencies=com.oracle.graal.replacements.hsail,com.oracle.graal.hotspot,com.oracle.graal.gpu
 project@com.oracle.graal.hotspot.hsail@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.hotspot.hsail@annotationProcessors=com.oracle.graal.service.processor
-project@com.oracle.graal.hotspot.hsail@javaCompliance=1.7
+project@com.oracle.graal.hotspot.hsail@javaCompliance=1.8
 project@com.oracle.graal.hotspot.hsail@workingSets=Graal,HotSpot,PTX
 
 # graal.hotspot.server
@@ -184,7 +192,7 @@
 project@com.oracle.graal.hotspot.server@sourceDirs=src
 project@com.oracle.graal.hotspot.server@dependencies=com.oracle.graal.hotspot
 project@com.oracle.graal.hotspot.server@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.hotspot.server@javaCompliance=1.7
+project@com.oracle.graal.hotspot.server@javaCompliance=1.8
 project@com.oracle.graal.hotspot.server@workingSets=Graal,HotSpot
 
 # graal.hotspot.test
@@ -192,7 +200,7 @@
 project@com.oracle.graal.hotspot.test@sourceDirs=src
 project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.replacements.test,com.oracle.graal.hotspot
 project@com.oracle.graal.hotspot.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.hotspot.test@javaCompliance=1.7
+project@com.oracle.graal.hotspot.test@javaCompliance=1.8
 project@com.oracle.graal.hotspot.test@workingSets=Graal,HotSpot,Test
 
 # graal.hotspot.jdk8.test
@@ -208,14 +216,14 @@
 project@com.oracle.graal.hotspot.amd64.test@sourceDirs=src
 project@com.oracle.graal.hotspot.amd64.test@dependencies=com.oracle.graal.asm.amd64,com.oracle.graal.compiler.test
 project@com.oracle.graal.hotspot.amd64.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.hotspot.amd64.test@javaCompliance=1.7
+project@com.oracle.graal.hotspot.amd64.test@javaCompliance=1.8
 project@com.oracle.graal.hotspot.amd64.test@workingSets=Graal,HotSpot,AMD64,Test
 
 # graal.options
 project@com.oracle.graal.options@subDir=graal
 project@com.oracle.graal.options@sourceDirs=src
 project@com.oracle.graal.options@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.options@javaCompliance=1.7
+project@com.oracle.graal.options@javaCompliance=1.8
 project@com.oracle.graal.options@annotationProcessorForDependents=true
 project@com.oracle.graal.options@workingSets=Graal,Codegen
 
@@ -224,14 +232,14 @@
 project@com.oracle.graal.options.test@sourceDirs=src
 project@com.oracle.graal.options.test@dependencies=com.oracle.graal.options,JUNIT
 project@com.oracle.graal.options.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.options.test@javaCompliance=1.7
+project@com.oracle.graal.options.test@javaCompliance=1.8
 project@com.oracle.graal.options.test@workingSets=Graal
 
 # graal.graph
 project@com.oracle.graal.graph@subDir=graal
 project@com.oracle.graal.graph@sourceDirs=src
-project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug,com.oracle.graal.api.code
-project@com.oracle.graal.graph@javaCompliance=1.7
+project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug,com.oracle.graal.api.code,FINDBUGS
+project@com.oracle.graal.graph@javaCompliance=1.8
 project@com.oracle.graal.graph@workingSets=Graal,Graph
 
 # graal.graph.test
@@ -239,14 +247,14 @@
 project@com.oracle.graal.graph.test@sourceDirs=src
 project@com.oracle.graal.graph.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.graph.test@dependencies=JUNIT,com.oracle.graal.graph
-project@com.oracle.graal.graph.test@javaCompliance=1.7
+project@com.oracle.graal.graph.test@javaCompliance=1.8
 project@com.oracle.graal.graph.test@workingSets=Graal,Graph,Test
 
 # graal.debug
 project@com.oracle.graal.debug@subDir=graal
 project@com.oracle.graal.debug@sourceDirs=src
 project@com.oracle.graal.debug@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.debug@javaCompliance=1.7
+project@com.oracle.graal.debug@javaCompliance=1.8
 project@com.oracle.graal.debug@workingSets=Graal,Debug
 
 # graal.debug.test
@@ -254,7 +262,7 @@
 project@com.oracle.graal.debug.test@sourceDirs=src
 project@com.oracle.graal.debug.test@dependencies=JUNIT,com.oracle.graal.debug
 project@com.oracle.graal.debug.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.debug.test@javaCompliance=1.7
+project@com.oracle.graal.debug.test@javaCompliance=1.8
 project@com.oracle.graal.debug.test@workingSets=Graal,Debug,Test
 
 # graal.lir
@@ -262,7 +270,7 @@
 project@com.oracle.graal.lir@sourceDirs=src
 project@com.oracle.graal.lir@dependencies=com.oracle.graal.asm,com.oracle.graal.nodes
 project@com.oracle.graal.lir@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.lir@javaCompliance=1.7
+project@com.oracle.graal.lir@javaCompliance=1.8
 project@com.oracle.graal.lir@workingSets=Graal,LIR
 
 # graal.lir.amd64
@@ -270,7 +278,7 @@
 project@com.oracle.graal.lir.amd64@sourceDirs=src
 project@com.oracle.graal.lir.amd64@dependencies=com.oracle.graal.lir,com.oracle.graal.asm.amd64
 project@com.oracle.graal.lir.amd64@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.lir.amd64@javaCompliance=1.7
+project@com.oracle.graal.lir.amd64@javaCompliance=1.8
 project@com.oracle.graal.lir.amd64@workingSets=Graal,LIR,AMD64
 
 # graal.lir.ptx
@@ -278,7 +286,7 @@
 project@com.oracle.graal.lir.ptx@sourceDirs=src
 project@com.oracle.graal.lir.ptx@dependencies=com.oracle.graal.asm.ptx
 project@com.oracle.graal.lir.ptx@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.lir.ptx@javaCompliance=1.7
+project@com.oracle.graal.lir.ptx@javaCompliance=1.8
 project@com.oracle.graal.lir.ptx@workingSets=Graal,LIR,PTX
 
 # graal.lir.sparc
@@ -286,7 +294,7 @@
 project@com.oracle.graal.lir.sparc@sourceDirs=src
 project@com.oracle.graal.lir.sparc@dependencies=com.oracle.graal.asm.sparc
 project@com.oracle.graal.lir.sparc@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.lir.sparc@javaCompliance=1.7
+project@com.oracle.graal.lir.sparc@javaCompliance=1.8
 project@com.oracle.graal.lir.sparc@workingSets=Graal,LIR,SPARC
 
 # graal.alloc
@@ -294,7 +302,7 @@
 project@com.oracle.graal.alloc@sourceDirs=src
 project@com.oracle.graal.alloc@dependencies=com.oracle.graal.nodes
 project@com.oracle.graal.alloc@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.alloc@javaCompliance=1.7
+project@com.oracle.graal.alloc@javaCompliance=1.8
 project@com.oracle.graal.alloc@workingSets=Graal
 
 # graal.word
@@ -302,7 +310,7 @@
 project@com.oracle.graal.word@sourceDirs=src
 project@com.oracle.graal.word@dependencies=com.oracle.graal.phases
 project@com.oracle.graal.word@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.word@javaCompliance=1.7
+project@com.oracle.graal.word@javaCompliance=1.8
 project@com.oracle.graal.word@workingSets=API,Graal
 
 # graal.replacements
@@ -310,7 +318,7 @@
 project@com.oracle.graal.replacements@sourceDirs=src
 project@com.oracle.graal.replacements@dependencies=com.oracle.graal.compiler,com.oracle.graal.java,com.oracle.graal.word
 project@com.oracle.graal.replacements@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.replacements@javaCompliance=1.7
+project@com.oracle.graal.replacements@javaCompliance=1.8
 project@com.oracle.graal.replacements@annotationProcessors=com.oracle.graal.replacements.verifier,com.oracle.graal.service.processor
 project@com.oracle.graal.replacements@workingSets=Graal,Replacements
 
@@ -319,7 +327,7 @@
 project@com.oracle.graal.replacements.amd64@sourceDirs=src
 project@com.oracle.graal.replacements.amd64@dependencies=com.oracle.graal.replacements
 project@com.oracle.graal.replacements.amd64@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.replacements.amd64@javaCompliance=1.7
+project@com.oracle.graal.replacements.amd64@javaCompliance=1.8
 project@com.oracle.graal.replacements.amd64@annotationProcessors=com.oracle.graal.service.processor
 project@com.oracle.graal.replacements.amd64@workingSets=Graal,Replacements,AMD64
 
@@ -328,7 +336,7 @@
 project@com.oracle.graal.replacements.hsail@sourceDirs=src
 project@com.oracle.graal.replacements.hsail@dependencies=com.oracle.graal.compiler.hsail
 project@com.oracle.graal.replacements.hsail@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.replacements.hsail@javaCompliance=1.7
+project@com.oracle.graal.replacements.hsail@javaCompliance=1.8
 project@com.oracle.graal.replacements.hsail@workingSets=Graal,Replacements,HSAIL
 
 # graal.replacements.test
@@ -336,7 +344,7 @@
 project@com.oracle.graal.replacements.test@sourceDirs=src
 project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.compiler.test,com.oracle.graal.replacements
 project@com.oracle.graal.replacements.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.replacements.test@javaCompliance=1.7
+project@com.oracle.graal.replacements.test@javaCompliance=1.8
 project@com.oracle.graal.replacements.test@workingSets=Graal,Replacements,Test
 
 # graal.replacements.verifier
@@ -344,7 +352,7 @@
 project@com.oracle.graal.replacements.verifier@sourceDirs=src
 project@com.oracle.graal.replacements.verifier@dependencies=com.oracle.graal.api.replacements,com.oracle.graal.graph
 project@com.oracle.graal.replacements.verifier@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.replacements.verifier@javaCompliance=1.7
+project@com.oracle.graal.replacements.verifier@javaCompliance=1.8
 project@com.oracle.graal.replacements.verifier@workingSets=Graal,Replacements
 
 # graal.nodes
@@ -352,7 +360,7 @@
 project@com.oracle.graal.nodes@sourceDirs=src
 project@com.oracle.graal.nodes@dependencies=com.oracle.graal.graph,com.oracle.graal.api.replacements
 project@com.oracle.graal.nodes@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.nodes@javaCompliance=1.7
+project@com.oracle.graal.nodes@javaCompliance=1.8
 project@com.oracle.graal.nodes@annotationProcessors=com.oracle.graal.replacements.verifier
 project@com.oracle.graal.nodes@workingSets=Graal,Graph
 
@@ -361,7 +369,7 @@
 project@com.oracle.graal.nodes.test@sourceDirs=src
 project@com.oracle.graal.nodes.test@dependencies=com.oracle.graal.compiler.test
 project@com.oracle.graal.nodes.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.nodes.test@javaCompliance=1.7
+project@com.oracle.graal.nodes.test@javaCompliance=1.8
 project@com.oracle.graal.nodes.test@workingSets=Graal,Graph
 
 # graal.phases
@@ -369,7 +377,7 @@
 project@com.oracle.graal.phases@sourceDirs=src
 project@com.oracle.graal.phases@dependencies=com.oracle.graal.nodes,com.oracle.graal.options
 project@com.oracle.graal.phases@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.phases@javaCompliance=1.7
+project@com.oracle.graal.phases@javaCompliance=1.8
 project@com.oracle.graal.phases@workingSets=Graal,Phases
 
 # graal.phases.common
@@ -377,7 +385,7 @@
 project@com.oracle.graal.phases.common@sourceDirs=src
 project@com.oracle.graal.phases.common@dependencies=com.oracle.graal.phases
 project@com.oracle.graal.phases.common@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.phases.common@javaCompliance=1.7
+project@com.oracle.graal.phases.common@javaCompliance=1.8
 project@com.oracle.graal.phases.common@workingSets=Graal,Phases
 
 # graal.virtual
@@ -385,7 +393,7 @@
 project@com.oracle.graal.virtual@sourceDirs=src
 project@com.oracle.graal.virtual@dependencies=com.oracle.graal.phases.common
 project@com.oracle.graal.virtual@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.virtual@javaCompliance=1.7
+project@com.oracle.graal.virtual@javaCompliance=1.8
 project@com.oracle.graal.virtual@workingSets=Graal,Phases
 
 # graal.loop
@@ -393,7 +401,7 @@
 project@com.oracle.graal.loop@sourceDirs=src
 project@com.oracle.graal.loop@dependencies=com.oracle.graal.phases.common
 project@com.oracle.graal.loop@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.loop@javaCompliance=1.7
+project@com.oracle.graal.loop@javaCompliance=1.8
 project@com.oracle.graal.loop@workingSets=Graal,Phases
 
 # graal.compiler
@@ -401,7 +409,7 @@
 project@com.oracle.graal.compiler@sourceDirs=src
 project@com.oracle.graal.compiler@dependencies=com.oracle.graal.api.runtime,com.oracle.graal.virtual,com.oracle.graal.loop,com.oracle.graal.alloc,com.oracle.graal.lir
 project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler@javaCompliance=1.7
+project@com.oracle.graal.compiler@javaCompliance=1.8
 project@com.oracle.graal.compiler@annotationProcessors=com.oracle.graal.service.processor
 project@com.oracle.graal.compiler@workingSets=Graal
 
@@ -410,7 +418,7 @@
 project@com.oracle.graal.compiler.amd64@sourceDirs=src
 project@com.oracle.graal.compiler.amd64@dependencies=com.oracle.graal.compiler,com.oracle.graal.lir.amd64
 project@com.oracle.graal.compiler.amd64@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.amd64@javaCompliance=1.7
+project@com.oracle.graal.compiler.amd64@javaCompliance=1.8
 project@com.oracle.graal.compiler.amd64@workingSets=Graal,AMD64
 
 # graal.compiler.amd64.test
@@ -418,7 +426,7 @@
 project@com.oracle.graal.compiler.amd64.test@sourceDirs=src
 project@com.oracle.graal.compiler.amd64.test@dependencies=com.oracle.graal.compiler.test
 project@com.oracle.graal.compiler.amd64.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.amd64.test@javaCompliance=1.7
+project@com.oracle.graal.compiler.amd64.test@javaCompliance=1.8
 project@com.oracle.graal.compiler.amd64.test@workingSets=Graal,AMD64,Test
 
 # graal.compiler.ptx
@@ -426,7 +434,7 @@
 project@com.oracle.graal.compiler.ptx@sourceDirs=src
 project@com.oracle.graal.compiler.ptx@dependencies=com.oracle.graal.lir.ptx,com.oracle.graal.compiler
 project@com.oracle.graal.compiler.ptx@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.ptx@javaCompliance=1.7
+project@com.oracle.graal.compiler.ptx@javaCompliance=1.8
 project@com.oracle.graal.compiler.ptx@workingSets=Graal,PTX
 
 # graal.compiler.ptx.test
@@ -434,7 +442,7 @@
 project@com.oracle.graal.compiler.ptx.test@sourceDirs=src
 project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.hotspot.ptx,com.oracle.graal.compiler.test
 project@com.oracle.graal.compiler.ptx.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.7
+project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.8
 project@com.oracle.graal.compiler.ptx.test@workingSets=Graal,PTX,Test
 
 # graal.compiler.sparc
@@ -442,7 +450,7 @@
 project@com.oracle.graal.compiler.sparc@sourceDirs=src
 project@com.oracle.graal.compiler.sparc@dependencies=com.oracle.graal.lir.sparc
 project@com.oracle.graal.compiler.sparc@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.sparc@javaCompliance=1.7
+project@com.oracle.graal.compiler.sparc@javaCompliance=1.8
 project@com.oracle.graal.compiler.sparc@workingSets=Graal,SPARC
 
 # graal.compiler.sparc.test
@@ -450,7 +458,7 @@
 project@com.oracle.graal.compiler.sparc.test@sourceDirs=src
 project@com.oracle.graal.compiler.sparc.test@dependencies=com.oracle.graal.compiler.test
 project@com.oracle.graal.compiler.sparc.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.sparc.test@javaCompliance=1.7
+project@com.oracle.graal.compiler.sparc.test@javaCompliance=1.8
 project@com.oracle.graal.compiler.sparc.test@workingSets=Graal,SPARC,Test
 
 # graal.runtime
@@ -458,14 +466,14 @@
 project@com.oracle.graal.runtime@sourceDirs=src
 project@com.oracle.graal.runtime@dependencies=com.oracle.graal.compiler
 project@com.oracle.graal.runtime@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.runtime@javaCompliance=1.7
+project@com.oracle.graal.runtime@javaCompliance=1.8
 project@com.oracle.graal.runtime@workingSets=Graal
 
 # graal.bytecode
 project@com.oracle.graal.bytecode@subDir=graal
 project@com.oracle.graal.bytecode@sourceDirs=src
 project@com.oracle.graal.bytecode@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.bytecode@javaCompliance=1.7
+project@com.oracle.graal.bytecode@javaCompliance=1.8
 project@com.oracle.graal.bytecode@workingSets=Graal,Java
 
 # graal.java
@@ -473,15 +481,15 @@
 project@com.oracle.graal.java@sourceDirs=src
 project@com.oracle.graal.java@dependencies=com.oracle.graal.phases,com.oracle.graal.bytecode
 project@com.oracle.graal.java@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.java@javaCompliance=1.7
+project@com.oracle.graal.java@javaCompliance=1.8
 project@com.oracle.graal.java@workingSets=Graal,Java
 
 # graal.baseline
 project@com.oracle.graal.baseline@subDir=graal
 project@com.oracle.graal.baseline@sourceDirs=src
-project@com.oracle.graal.baseline@dependencies=com.oracle.graal.java,com.oracle.graal.lir
+project@com.oracle.graal.baseline@dependencies=com.oracle.graal.compiler,com.oracle.graal.java
 project@com.oracle.graal.baseline@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.baseline@javaCompliance=1.7
+project@com.oracle.graal.baseline@javaCompliance=1.8
 project@com.oracle.graal.baseline@workingSets=Graal,Java
 
 # graal.java.decompiler
@@ -489,7 +497,7 @@
 project@com.oracle.graal.java.decompiler@sourceDirs=src
 project@com.oracle.graal.java.decompiler@dependencies=com.oracle.graal.java
 project@com.oracle.graal.java.decompiler@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.java.decompiler@javaCompliance=1.7
+project@com.oracle.graal.java.decompiler@javaCompliance=1.8
 project@com.oracle.graal.java.decompiler@workingSets=Graal
 
 # graal.java.decompiler.test
@@ -497,7 +505,7 @@
 project@com.oracle.graal.java.decompiler.test@sourceDirs=src
 project@com.oracle.graal.java.decompiler.test@dependencies=JUNIT,com.oracle.graal.printer,com.oracle.graal.runtime
 project@com.oracle.graal.java.decompiler.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.java.decompiler.test@javaCompliance=1.7
+project@com.oracle.graal.java.decompiler.test@javaCompliance=1.8
 project@com.oracle.graal.java.decompiler.test@workingSets=Graal,Test
 
 # graal.printer
@@ -505,7 +513,7 @@
 project@com.oracle.graal.printer@sourceDirs=src
 project@com.oracle.graal.printer@dependencies=com.oracle.graal.java.decompiler,com.oracle.graal.compiler
 project@com.oracle.graal.printer@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.printer@javaCompliance=1.7
+project@com.oracle.graal.printer@javaCompliance=1.8
 project@com.oracle.graal.printer@workingSets=Graal,Graph
 
 # graal.test
@@ -513,15 +521,15 @@
 project@com.oracle.graal.test@sourceDirs=src
 project@com.oracle.graal.test@dependencies=JUNIT
 project@com.oracle.graal.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.test@javaCompliance=1.7
+project@com.oracle.graal.test@javaCompliance=1.8
 project@com.oracle.graal.test@workingSets=Graal,Test
 
 # graal.compiler.test
 project@com.oracle.graal.compiler.test@subDir=graal
 project@com.oracle.graal.compiler.test@sourceDirs=src
-project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.printer,com.oracle.graal.runtime,com.oracle.graal.baseline
+project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.printer,com.oracle.graal.runtime,com.oracle.graal.baseline,JAVA_ALLOCATION_INSTRUMENTER
 project@com.oracle.graal.compiler.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.test@javaCompliance=1.7
+project@com.oracle.graal.compiler.test@javaCompliance=1.8
 project@com.oracle.graal.compiler.test@workingSets=Graal,Test
 
 # graal.jtt
@@ -529,7 +537,7 @@
 project@com.oracle.graal.jtt@sourceDirs=src
 project@com.oracle.graal.jtt@dependencies=com.oracle.graal.compiler.test
 project@com.oracle.graal.jtt@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.jtt@javaCompliance=1.7
+project@com.oracle.graal.jtt@javaCompliance=1.8
 project@com.oracle.graal.jtt@workingSets=Graal,Test
 
 # graal.asm
@@ -537,7 +545,7 @@
 project@com.oracle.graal.asm@sourceDirs=src
 project@com.oracle.graal.asm@dependencies=com.oracle.graal.api.code
 project@com.oracle.graal.asm@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.asm@javaCompliance=1.7
+project@com.oracle.graal.asm@javaCompliance=1.8
 project@com.oracle.graal.asm@workingSets=Graal,Assembler
 
 # graal.asm.test
@@ -545,7 +553,7 @@
 project@com.oracle.graal.asm.test@sourceDirs=src
 project@com.oracle.graal.asm.test@dependencies=com.oracle.graal.test,com.oracle.graal.runtime
 project@com.oracle.graal.asm.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.asm.test@javaCompliance=1.7
+project@com.oracle.graal.asm.test@javaCompliance=1.8
 project@com.oracle.graal.asm.test@workingSets=Graal,Assembler,Test
 
 # graal.asm.amd64
@@ -553,7 +561,7 @@
 project@com.oracle.graal.asm.amd64@sourceDirs=src
 project@com.oracle.graal.asm.amd64@dependencies=com.oracle.graal.asm,com.oracle.graal.amd64
 project@com.oracle.graal.asm.amd64@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.asm.amd64@javaCompliance=1.7
+project@com.oracle.graal.asm.amd64@javaCompliance=1.8
 project@com.oracle.graal.asm.amd64@workingSets=Graal,Assembler,AMD64
 
 # graal.asm.amd64.test
@@ -561,57 +569,64 @@
 project@com.oracle.graal.asm.amd64.test@sourceDirs=src
 project@com.oracle.graal.asm.amd64.test@dependencies=com.oracle.graal.asm.test,com.oracle.graal.asm.amd64
 project@com.oracle.graal.asm.amd64.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.asm.amd64.test@javaCompliance=1.7
+project@com.oracle.graal.asm.amd64.test@javaCompliance=1.8
 project@com.oracle.graal.asm.amd64.test@workingSets=Graal,Assembler,AMD64,Test
 
+# graal.gpu
+project@com.oracle.graal.gpu@subDir=graal
+project@com.oracle.graal.gpu@sourceDirs=src
+project@com.oracle.graal.gpu@dependencies=com.oracle.graal.nodes
+project@com.oracle.graal.gpu@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.gpu@javaCompliance=1.8
+
 # graal.hsail
 project@com.oracle.graal.hsail@subDir=graal
 project@com.oracle.graal.hsail@sourceDirs=src
 project@com.oracle.graal.hsail@dependencies=com.oracle.graal.graph
 project@com.oracle.graal.hsail@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.hsail@javaCompliance=1.7
+project@com.oracle.graal.hsail@javaCompliance=1.8
 
 # graal.lir.hsail
 project@com.oracle.graal.lir.hsail@subDir=graal
 project@com.oracle.graal.lir.hsail@sourceDirs=src
 project@com.oracle.graal.lir.hsail@dependencies=com.oracle.graal.lir,com.oracle.graal.asm.hsail
 project@com.oracle.graal.lir.hsail@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.lir.hsail@javaCompliance=1.7
+project@com.oracle.graal.lir.hsail@javaCompliance=1.8
 
 # graal.compiler.hsail
 project@com.oracle.graal.compiler.hsail@subDir=graal
 project@com.oracle.graal.compiler.hsail@sourceDirs=src
 project@com.oracle.graal.compiler.hsail@dependencies=com.oracle.graal.compiler,com.oracle.graal.lir.hsail
 project@com.oracle.graal.compiler.hsail@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.hsail@javaCompliance=1.7
+project@com.oracle.graal.compiler.hsail@javaCompliance=1.8
 
 # graal.compiler.hsail.test.infra - HSAIL compiler test infrastructure
 project@com.oracle.graal.compiler.hsail.test.infra@subDir=graal
 project@com.oracle.graal.compiler.hsail.test.infra@sourceDirs=src
 project@com.oracle.graal.compiler.hsail.test.infra@dependencies=com.oracle.graal.hotspot.hsail,JUNIT,OKRA_WITH_SIM
 project@com.oracle.graal.compiler.hsail.test.infra@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.hsail.test.infra@javaCompliance=1.7
+project@com.oracle.graal.compiler.hsail.test.infra@javaCompliance=1.8
 
 # graal.compiler.hsail.test
 project@com.oracle.graal.compiler.hsail.test@subDir=graal
 project@com.oracle.graal.compiler.hsail.test@sourceDirs=src
 project@com.oracle.graal.compiler.hsail.test@dependencies=com.oracle.graal.compiler.hsail.test.infra,com.oracle.graal.compiler.test
 project@com.oracle.graal.compiler.hsail.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.compiler.hsail.test@javaCompliance=1.7
+project@com.oracle.graal.compiler.hsail.test@javaCompliance=1.8
 
 # graal.asm.hsail
 project@com.oracle.graal.asm.hsail@subDir=graal
 project@com.oracle.graal.asm.hsail@sourceDirs=src
 project@com.oracle.graal.asm.hsail@dependencies=com.oracle.graal.hsail,OKRA,com.oracle.graal.asm
 project@com.oracle.graal.asm.hsail@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.asm.hsail@javaCompliance=1.7
+project@com.oracle.graal.asm.hsail@javaCompliance=1.8
 
 # graal.asm.ptx
 project@com.oracle.graal.asm.ptx@subDir=graal
 project@com.oracle.graal.asm.ptx@sourceDirs=src
 project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.lir
 project@com.oracle.graal.asm.ptx@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.asm.ptx@javaCompliance=1.7
+project@com.oracle.graal.asm.ptx@javaCompliance=1.8
 project@com.oracle.graal.asm.ptx@workingSets=Graal,Assembler,PTX
 
 # graal.asm.sparc
@@ -619,7 +634,7 @@
 project@com.oracle.graal.asm.sparc@sourceDirs=src
 project@com.oracle.graal.asm.sparc@dependencies=com.oracle.graal.hotspot,com.oracle.graal.sparc
 project@com.oracle.graal.asm.sparc@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.asm.sparc@javaCompliance=1.7
+project@com.oracle.graal.asm.sparc@javaCompliance=1.8
 project@com.oracle.graal.asm.sparc@workingSets=Graal,Assembler,SPARC
 
 # truffle.api
@@ -684,7 +699,7 @@
 project@com.oracle.graal.truffle@sourceDirs=src
 project@com.oracle.graal.truffle@dependencies=com.oracle.truffle.api,com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer
 project@com.oracle.graal.truffle@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.truffle@javaCompliance=1.7
+project@com.oracle.graal.truffle@javaCompliance=1.8
 project@com.oracle.graal.truffle@workingSets=Graal,Truffle
 
 # graal.truffle.test
@@ -692,7 +707,7 @@
 project@com.oracle.graal.truffle.test@sourceDirs=src
 project@com.oracle.graal.truffle.test@dependencies=com.oracle.graal.truffle,com.oracle.graal.compiler.test
 project@com.oracle.graal.truffle.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.truffle.test@javaCompliance=1.7
+project@com.oracle.graal.truffle.test@javaCompliance=1.8
 project@com.oracle.graal.truffle.test@workingSets=Graal,Truffle,Test
 
 # graal.truffle.hotspot
@@ -700,7 +715,7 @@
 project@com.oracle.graal.truffle.hotspot@sourceDirs=src
 project@com.oracle.graal.truffle.hotspot@dependencies=com.oracle.graal.truffle,com.oracle.graal.hotspot
 project@com.oracle.graal.truffle.hotspot@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.truffle.hotspot@javaCompliance=1.7
+project@com.oracle.graal.truffle.hotspot@javaCompliance=1.8
 project@com.oracle.graal.truffle.hotspot@annotationProcessors=com.oracle.graal.service.processor
 project@com.oracle.graal.truffle.hotspot@workingSets=Graal,Truffle
 
@@ -709,6 +724,6 @@
 project@com.oracle.graal.truffle.hotspot.amd64@sourceDirs=src
 project@com.oracle.graal.truffle.hotspot.amd64@dependencies=com.oracle.graal.truffle.hotspot,com.oracle.graal.hotspot.amd64
 project@com.oracle.graal.truffle.hotspot.amd64@checkstyle=com.oracle.graal.graph
-project@com.oracle.graal.truffle.hotspot.amd64@javaCompliance=1.7
+project@com.oracle.graal.truffle.hotspot.amd64@javaCompliance=1.8
 project@com.oracle.graal.truffle.hotspot.amd64@annotationProcessors=com.oracle.graal.service.processor
 project@com.oracle.graal.truffle.hotspot.amd64@workingSets=Graal,Truffle
--- a/mx/sanitycheck.py	Wed Mar 19 11:43:57 2014 +0100
+++ b/mx/sanitycheck.py	Sun Mar 30 16:08:33 2014 +0200
@@ -32,7 +32,7 @@
 dacapoSanityWarmup = {
     'avrora':     [0, 0, 3, 6, 13],
     'batik':      [0, 0, 5, 5, 20],
-    'eclipse':    [2, 4, 5, 10, 16],
+    'eclipse':    [0, 0, 0, 0, 0],
     'fop':        [4, 8, 10, 20, 30],
     'h2':         [0, 0, 5, 5, 8],
     'jython':     [0, 0, 5, 10, 13],
@@ -42,17 +42,15 @@
     'sunflow':    [0, 2, 5, 10, 15],
     'tomcat':     [0, 0, 5, 10, 15],
     'tradebeans': [0, 0, 5, 10, 13],
-    'tradesoap':  [2, 4, 5, 10, 15],
+    'tradesoap':  [0, 0, 5, 10, 15],
     'xalan':      [0, 0, 5, 10, 18],
 }
 
 dacapoScalaSanityWarmup = {
-# (tw) actors sometimes fails verification; hardly reproducible
-    'actors':     [0, 0, 0, 0, 0],
-# (lstadler) apparat was disabled due to a deadlock which I think is the benchmarks fault.
-    'apparat':    [0, 0, 0, 0, 0],
+    'actors':     [0, 0, 2, 5, 5],
+    'apparat':    [0, 0, 2, 5, 5],
     'factorie':   [0, 0, 2, 5, 5],
-    'kiama':      [0, 0, 3, 13, 15],
+    'kiama':      [0, 4, 3, 13, 15],
     'scalac':     [0, 0, 5, 15, 20],
     'scaladoc':   [0, 0, 5, 15, 15],
     'scalap':     [0, 0, 5, 15, 20],
@@ -67,7 +65,8 @@
 dacapoGateBuildLevels = {
     'avrora':     ['product', 'fastdebug', 'debug'],
     'batik':      ['product', 'fastdebug', 'debug'],
-    'eclipse':    ['product'],
+    # (lewurm): does not work with JDK8
+    'eclipse':    [],
     'fop':        ['fastdebug', 'debug'],
     'h2':         ['product', 'fastdebug', 'debug'],
     'jython':     ['product', 'fastdebug', 'debug'],
@@ -77,7 +76,8 @@
     'sunflow':    ['fastdebug', 'debug'],
     'tomcat':     ['product', 'fastdebug', 'debug'],
     'tradebeans': ['product', 'fastdebug', 'debug'],
-    # tradesoap is too unreliable for the gate, often crashing with "java.net.BindException: Address already in use"
+    # tradesoap is too unreliable for the gate, often crashing with concurrency problems:
+    # http://sourceforge.net/p/dacapobench/bugs/99/
     'tradesoap':  [],
     'xalan':      ['product', 'fastdebug', 'debug'],
 }
@@ -86,7 +86,7 @@
     'actors':     ['product', 'fastdebug', 'debug'],
     'apparat':    ['product', 'fastdebug', 'debug'],
     'factorie':   ['product', 'fastdebug', 'debug'],
-    'kiama':      ['product', 'fastdebug', 'debug'],
+    'kiama':      ['fastdebug', 'debug'],
     'scalac':     ['product', 'fastdebug', 'debug'],
     'scaladoc':   ['product', 'fastdebug', 'debug'],
     'scalap':     ['product', 'fastdebug', 'debug'],
--- a/mxtool/mx.py	Wed Mar 19 11:43:57 2014 +0100
+++ b/mxtool/mx.py	Sun Mar 30 16:08:33 2014 +0200
@@ -40,6 +40,7 @@
 import xml.parsers.expat
 import shutil, re, xml.dom.minidom
 import pipes
+import difflib
 from collections import Callable
 from threading import Thread
 from argparse import ArgumentParser, REMAINDER
@@ -53,14 +54,14 @@
 _primary_suite_path = None
 _primary_suite = None
 _opts = None
-_java = None
+_java_homes = None
 _warn = False
 
 """
 A distribution is a jar or zip file containing the output from one or more Java projects.
 """
 class Distribution:
-    def __init__(self, suite, name, path, deps):
+    def __init__(self, suite, name, path, deps, excludedLibs):
         self.suite = suite
         self.name = name
         self.path = path.replace('/', os.sep)
@@ -68,6 +69,14 @@
             self.path = join(suite.dir, self.path)
         self.deps = deps
         self.update_listeners = set()
+        self.excludedLibs = excludedLibs
+
+    def sorted_deps(self, includeLibs=False):
+        try:
+            excl = [library(d) for d in self.excludedLibs]
+        except SystemExit as e:
+            abort('invalid excluded library for {} distribution: {}'.format(self.name, e))
+        return [d for d in sorted_deps(self.deps, includeLibs=includeLibs) if d not in excl]
 
     def __str__(self):
         return self.name
@@ -116,6 +125,13 @@
         self.workingSets = workingSets
         self.dir = d
 
+        # Verify that a JDK exists for this project if its compliance level is
+        # less than the compliance level of the default JDK
+        jdk = java(self.javaCompliance)
+        if jdk is None and self.javaCompliance < java().javaCompliance:
+            abort('Cannot find ' + str(self.javaCompliance) + ' JDK required by ' + name + '. ' +
+                  'Specify it with --extra-java-homes option or EXTRA_JAVA_HOMES environment variable.')
+
         # Create directories for projects that don't yet exist
         if not exists(d):
             os.mkdir(d)
@@ -606,7 +622,8 @@
         for name, attrs in distsMap.iteritems():
             path = attrs.pop('path')
             deps = pop_list(attrs, 'dependencies')
-            d = Distribution(self, name, path, deps)
+            exclLibs = pop_list(attrs, 'excludeLibs')
+            d = Distribution(self, name, path, deps, exclLibs)
             d.__dict__.update(attrs)
             self.dists.append(d)
 
@@ -900,6 +917,8 @@
     """
     l = _libs.get(name)
     if l is None and fatalIfMissing:
+        if _projects.get(name):
+            abort(name + ' is a project, not a library')
         abort('library named ' + name + ' not found')
     return l
 
@@ -1035,7 +1054,8 @@
         self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@<args>', default=[])
         self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@<args>', default=[])
         self.add_argument('--user-home', help='users home directory', metavar='<path>', default=os.path.expanduser('~'))
-        self.add_argument('--java-home', help='bootstrap JDK installation directory (must be JDK 6 or later)', metavar='<path>')
+        self.add_argument('--java-home', help='primary JDK directory (must be JDK 7 or later)', metavar='<path>')
+        self.add_argument('--extra-java-homes', help='secondary JDK directories separated by "' + os.pathsep + '"', metavar='<path>')
         self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='<name>', default=[])
         self.add_argument('--kill-with-sigquit', action='store_true', dest='killwithsigquit', help='send sigquit first before killing child processes')
         if get_os() != 'windows':
@@ -1060,6 +1080,8 @@
 
         if opts.java_home is None:
             opts.java_home = os.environ.get('JAVA_HOME')
+        if opts.extra_java_homes is None:
+            opts.extra_java_homes = os.environ.get('EXTRA_JAVA_HOMES')
 
         if opts.java_home is None or opts.java_home == '':
             opts.java_home = _handle_missing_java_home()
@@ -1088,12 +1110,21 @@
         msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0])
     return msg + '\n'
 
-def java():
+def java(requiredCompliance=None):
     """
     Get a JavaConfig object containing Java commands launch details.
+    If requiredCompliance is None, the compliance level specified by --java-home/JAVA_HOME
+    is returned. Otherwise, the JavaConfig exactly matching requiredCompliance is returned
+    or None if there is no exact match.
     """
-    assert _java is not None
-    return _java
+    assert _java_homes
+    if not requiredCompliance:
+        return _java_homes[0]
+    for java in _java_homes:
+        if java.javaCompliance == requiredCompliance:
+            return java
+    return None
+
 
 def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, addDefaultArgs=True):
     return run(java().format_cmd(args, addDefaultArgs), nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd)
@@ -1349,9 +1380,9 @@
 A JavaConfig object encapsulates info on how Java commands are run.
 """
 class JavaConfig:
-    def __init__(self, opts):
-        self.jdk = opts.java_home
-        self.debug_port = opts.java_dbg_port
+    def __init__(self, java_home, java_dbg_port):
+        self.jdk = java_home
+        self.debug_port = java_dbg_port
         self.jar = exe_suffix(join(self.jdk, 'bin', 'jar'))
         self.java = exe_suffix(join(self.jdk, 'bin', 'java'))
         self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
@@ -1360,7 +1391,7 @@
         self._bootclasspath = None
 
         if not exists(self.java):
-            abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java)
+            abort('Java launcher does not exist: ' + self.java)
 
         def delAtAndSplit(s):
             return shlex.split(s.lstrip('@'))
@@ -1388,6 +1419,14 @@
         if self.debug_port is not None:
             self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)]
 
+    def __hash__(self):
+        return hash(self.jdk)
+
+    def __cmp__(self, other):
+        if isinstance(other, JavaConfig):
+            return cmp(self.javaCompliance, other.javaCompliance)
+        raise TypeError()
+
     def format_cmd(self, args, addDefaultArgs):
         if addDefaultArgs:
             return [self.java] + self.processArgs(args)
@@ -1498,6 +1537,7 @@
             _kill_process_group(p.pid, sig=signal.SIGQUIT)
         time.sleep(0.1)
 
+
 def abort(codeOrMessage):
     """
     Aborts the program with a SystemExit exception.
@@ -1623,14 +1663,12 @@
     if not suppliedParser:
         parser = ArgumentParser(prog='mx build')
 
-    javaCompliance = java().javaCompliance
-
     defaultEcjPath = get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar'))
 
     parser = parser if parser is not None else ArgumentParser(prog='mx build')
     parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
     parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
-    parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one', default=str(javaCompliance))
+    parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one')
     parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs')
     parser.add_argument('--projects', action='store', help='comma separated projects to build (omit to build all projects)')
     parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)')
@@ -1709,9 +1747,12 @@
                 continue
 
         # skip building this Java project if its Java compliance level is "higher" than the configured JDK
-        if javaCompliance < p.javaCompliance:
-            log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
+        requiredCompliance = p.javaCompliance if p.javaCompliance else JavaCompliance(args.compliance) if args.compliance else None
+        jdk = java(requiredCompliance)
+        if not jdk:
+            log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, requiredCompliance))
             continue
+        compliance = str(jdk.javaCompliance)
 
         outputDir = prepareOutputDirs(p, args.clean)
 
@@ -1816,14 +1857,11 @@
 
         toBeDeleted = [argfileName]
         try:
-            compliance = str(p.javaCompliance) if p.javaCompliance is not None else args.compliance
             if jdtJar is None:
                 log('Compiling Java sources for {0} with javac...'.format(p.name))
-
-
-                javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir]
-                if java().debug_port is not None:
-                    javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)]
+                javacCmd = [jdk.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir]
+                if jdk.debug_port is not None:
+                    javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
                 javacCmd += processorArgs
                 javacCmd += ['@' + argfile.name]
 
@@ -1833,9 +1871,9 @@
             else:
                 log('Compiling Java sources for {0} with JDT...'.format(p.name))
 
-                jdtArgs = [java().java, '-Xmx1g']
-                if java().debug_port is not None:
-                    jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)]
+                jdtArgs = [jdk.java, '-Xmx1g']
+                if jdk.debug_port is not None:
+                    jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
 
                 jdtArgs += ['-jar', jdtJar,
                          '-' + compliance,
@@ -1911,13 +1949,19 @@
         projects = [project(name) for name in args.projects.split(',')]
 
     class Batch:
-        def __init__(self, settingsFile):
-            self.path = settingsFile
+        def __init__(self, settingsDir, javaCompliance):
+            self.path = join(settingsDir, 'org.eclipse.jdt.core.prefs')
+            self.javaCompliance = javaCompliance
             self.javafiles = list()
+            with open(join(settingsDir, 'org.eclipse.jdt.ui.prefs')) as fp:
+                jdtUiPrefs = fp.read()
+            self.removeTrailingWhitespace = 'sp_cleanup.remove_trailing_whitespaces_all=true' in jdtUiPrefs
+            if self.removeTrailingWhitespace:
+                assert 'sp_cleanup.remove_trailing_whitespaces=true' in jdtUiPrefs and 'sp_cleanup.remove_trailing_whitespaces_ignore_empty=false' in jdtUiPrefs
 
         def settings(self):
             with open(self.path) as fp:
-                return fp.read()
+                return fp.read() + java(self.javaCompliance).java + str(self.removeTrailingWhitespace)
 
     class FileInfo:
         def __init__(self, path):
@@ -1926,12 +1970,25 @@
                 self.content = fp.read()
             self.times = (os.path.getatime(path), os.path.getmtime(path))
 
-        def update(self):
+        def update(self, removeTrailingWhitespace):
             with open(self.path) as fp:
                 content = fp.read()
+
+            if self.content != content:
+                # Only apply *after* formatting to match the order in which the IDE does it
+                if removeTrailingWhitespace:
+                    content, n = re.subn(r'[ \t]+$', '', content, flags=re.MULTILINE)
+                    if n != 0 and self.content == content:
+                        # undo on-disk changes made by the Eclipse formatter
+                        with open(self.path, 'w') as fp:
+                            fp.write(content)
+
                 if self.content != content:
+                    self.diff = difflib.unified_diff(self.content.splitlines(1), content.splitlines(1))
                     self.content = content
                     return True
+
+            # reset access and modification time of file
             os.utime(self.path, self.times)
 
     modified = list()
@@ -1941,7 +1998,7 @@
             continue
         sourceDirs = p.source_dirs()
 
-        batch = Batch(join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs'))
+        batch = Batch(join(p.dir, '.settings'), p.javaCompliance)
 
         if not exists(batch.path):
             if _opts.verbose:
@@ -1960,13 +2017,21 @@
         if res is not batch:
             res.javafiles = res.javafiles + batch.javafiles
 
+    print "we have: " + str(len(batches)) + " batches"
     for batch in batches.itervalues():
-        run([args.eclipse_exe, '-nosplash', '-application', 'org.eclipse.jdt.core.JavaCodeFormatter', '-config', batch.path] + [f.path for f in batch.javafiles])
+        run([args.eclipse_exe,
+            '-nosplash',
+            '-application',
+            'org.eclipse.jdt.core.JavaCodeFormatter',
+            '-vm', java(batch.javaCompliance).java,
+            '-config', batch.path]
+            + [f.path for f in batch.javafiles])
         for fi in batch.javafiles:
-            if fi.update():
+            if fi.update(batch.removeTrailingWhitespace):
                 modified.append(fi)
 
     log('{0} files were modified'.format(len(modified)))
+
     if len(modified) != 0:
         arcbase = _primary_suite.dir
         if args.backup:
@@ -1975,6 +2040,8 @@
         for fi in modified:
             name = os.path.relpath(fi.path, arcbase)
             log(' - {0}'.format(name))
+            log('Changes:')
+            log(''.join(fi.diff))
             if args.backup:
                 arcname = name.replace(os.sep, '/')
                 zf.writestr(arcname, fi.content)
@@ -2090,7 +2157,7 @@
 
             try:
                 zf = zipfile.ZipFile(tmp, 'w')
-                for dep in sorted_deps(d.deps, includeLibs=True):
+                for dep in d.sorted_deps(includeLibs=True):
                     if dep.isLibrary():
                         l = dep
                         # merge library jar into distribution jar
@@ -2110,7 +2177,8 @@
                     else:
                         p = dep
                         # skip a  Java project if its Java compliance level is "higher" than the configured JDK
-                        if java().javaCompliance < p.javaCompliance:
+                        jdk = java(p.javaCompliance)
+                        if not jdk:
                             log('Excluding {0} from {2} (Java compliance level {1} required)'.format(p.name, p.javaCompliance, d.path))
                             continue
 
@@ -2291,7 +2359,8 @@
             abort('ERROR: .checkstyle for Project {0} is missing'.format(p.name))
 
         # skip checking this Java project if its Java compliance level is "higher" than the configured JDK
-        if java().javaCompliance < p.javaCompliance:
+        jdk = java(p.javaCompliance)
+        if not jdk:
             log('Excluding {0} from checking (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
             continue
 
@@ -2707,7 +2776,7 @@
 
     projToDist = dict()
     for dist in _dists.values():
-        distDeps = sorted_deps(dist.deps)
+        distDeps = dist.sorted_deps()
         for p in distDeps:
             projToDist[p.name] = (dist, [dep.name for dep in distDeps])
 
@@ -2715,6 +2784,10 @@
         if p.native:
             continue
 
+        if not java(p.javaCompliance):
+            log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
+            continue
+
         if not exists(p.dir):
             os.makedirs(p.dir)
 
@@ -2862,20 +2935,41 @@
         if not exists(settingsDir):
             os.mkdir(settingsDir)
 
+        # collect the defaults from mxtool
+        defaultEclipseSettingsDir = join(dirname(__file__), 'eclipse-settings')
+        esdict = {}
+        if exists(defaultEclipseSettingsDir):
+            for name in os.listdir(defaultEclipseSettingsDir):
+                if isfile(join(defaultEclipseSettingsDir, name)):
+                    esdict[name] = os.path.abspath(join(defaultEclipseSettingsDir, name))
+
+        # check for suite overrides
         eclipseSettingsDir = join(p.suite.mxDir, 'eclipse-settings')
         if exists(eclipseSettingsDir):
             for name in os.listdir(eclipseSettingsDir):
-                if name == "org.eclipse.jdt.apt.core.prefs" and not len(p.annotation_processors()) > 0:
-                    continue
-                path = join(eclipseSettingsDir, name)
-                if isfile(path):
-                    with open(join(eclipseSettingsDir, name)) as f:
-                        content = f.read()
-                    content = content.replace('${javaCompliance}', str(p.javaCompliance))
-                    if len(p.annotation_processors()) > 0:
-                        content = content.replace('org.eclipse.jdt.core.compiler.processAnnotations=disabled', 'org.eclipse.jdt.core.compiler.processAnnotations=enabled')
-                    update_file(join(settingsDir, name), content)
-                    files.append(join(settingsDir, name))
+                if isfile(join(eclipseSettingsDir, name)):
+                    esdict[name] = os.path.abspath(join(eclipseSettingsDir, name))
+
+        # check for project overrides
+        projectSettingsDir = join(p.dir, 'eclipse-settings')
+        if exists(projectSettingsDir):
+            for name in os.listdir(projectSettingsDir):
+                if isfile(join(projectSettingsDir, name)):
+                    esdict[name] = os.path.abspath(join(projectSettingsDir, name))
+
+        # copy a possibly modified file to the project's .settings directory
+        for name, path in esdict.iteritems():
+            # ignore this file altogether if this project has no annotation processors
+            if name == "org.eclipse.jdt.apt.core.prefs" and not len(p.annotation_processors()) > 0:
+                continue
+
+            with open(path) as f:
+                content = f.read()
+            content = content.replace('${javaCompliance}', str(p.javaCompliance))
+            if len(p.annotation_processors()) > 0:
+                content = content.replace('org.eclipse.jdt.core.compiler.processAnnotations=disabled', 'org.eclipse.jdt.core.compiler.processAnnotations=enabled')
+            update_file(join(settingsDir, name), content)
+            files.append(join(settingsDir, name))
 
         if len(p.annotation_processors()) > 0:
             out = XMLDoc()
@@ -2938,7 +3032,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' : java().jdk})
+    launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java(p.javaCompliance).jdk})
+    launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' : _opts.extra_java_homes})
     launchOut.close('mapAttribute')
 
     if refresh:
@@ -3185,6 +3280,7 @@
     updated = False
     files = []
     libFiles = []
+    jdks = set()
     for p in suite.projects:
         if p.native:
             continue
@@ -3195,13 +3291,21 @@
         if not exists(join(p.dir, 'nbproject')):
             os.makedirs(join(p.dir, 'nbproject'))
 
+        jdk = java(p.javaCompliance)
+
+        if not jdk:
+            log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
+            continue
+
+        jdks.add(jdk)
+
         out = XMLDoc()
         out.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'})
         out.element('description', data='Builds, tests, and runs the project ' + p.name + '.')
         out.element('import', {'file' : 'nbproject/build-impl.xml'})
         out.open('target', {'name' : '-post-compile'})
         out.open('exec', {'executable' : sys.executable})
-        out.element('env', {'key' : 'JAVA_HOME', 'value' : java().jdk})
+        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'})
@@ -3256,7 +3360,7 @@
         files.append(join(p.dir, 'nbproject', 'project.xml'))
 
         out = StringIO.StringIO()
-        jdkPlatform = 'JDK_' + str(java().version)
+        jdkPlatform = 'JDK_' + str(jdk.version)
 
         annotationProcessorEnabled = "false"
         annotationProcessorReferences = ""
@@ -3319,7 +3423,7 @@
 manifest.file=manifest.mf
 meta.inf.dir=${src.dir}/META-INF
 mkdist.disabled=false
-platforms.""" + jdkPlatform + """.home=""" + java().jdk + """
+platforms.""" + jdkPlatform + """.home=""" + jdk.jdk + """
 platform.active=""" + jdkPlatform + """
 run.classpath=\\
     ${javac.classpath}:\\
@@ -3399,7 +3503,9 @@
 
     if updated:
         log('If using NetBeans:')
-        log('  1. Ensure that a platform named "JDK_' + str(java().version) + '" is defined (Tools -> Java Platforms)')
+        log('  1. Ensure that the following platform(s) are defined (Tools -> Java Platforms):')
+        for jdk in jdks:
+            log('        JDK_' + str(jdk.version))
         log('  2. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)')
 
     _zip_files(files, suite.dir, configZip.path)
@@ -3570,7 +3676,7 @@
                 windowTitle = ['-windowtitle', p.name + ' javadoc']
             try:
                 log('Generating {2} for {0} in {1}'.format(p.name, out, docDir))
-                run([java().javadoc, memory,
+                run([java(p.javaCompliance).javadoc, memory,
                      '-XDignore.symbol.file',
                      '-classpath', cp,
                      '-quiet',
@@ -3599,7 +3705,7 @@
             sp += p.source_dirs()
             names.append(p.name)
 
-        links = ['-link', 'http://docs.oracle.com/javase/' + str(_java.javaCompliance.value) + '/docs/api/']
+        links = ['-link', 'http://docs.oracle.com/javase/' + str(java().javaCompliance.value) + '/docs/api/']
         out = join(_primary_suite.dir, docDir)
         if args.base is not None:
             out = join(args.base, docDir)
@@ -4079,9 +4185,16 @@
 
     opts, commandAndArgs = _argParser._parse_cmd_line()
 
-    global _opts, _java
+    global _opts, _java_homes
     _opts = opts
-    _java = JavaConfig(opts)
+    defaultJdk = JavaConfig(opts.java_home, opts.java_dbg_port)
+    _java_homes = [defaultJdk]
+    if opts.extra_java_homes:
+        for java_home in opts.extra_java_homes.split(os.pathsep):
+            extraJdk = JavaConfig(java_home, opts.java_dbg_port)
+            if extraJdk > defaultJdk:
+                abort('Secondary JDK ' + extraJdk.jdk + ' has higher compliance level than default JDK ' + defaultJdk.jdk)
+            _java_homes.append(extraJdk)
 
     for s in suites():
         s._post_init(opts)
--- a/src/cpu/sparc/vm/graalGlobals_sparc.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/cpu/sparc/vm/graalGlobals_sparc.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -45,7 +45,7 @@
 define_pd_global(intx, NewSizeThreadIncrease,        4*K  );
 define_pd_global(uintx,MetaspaceSize,                12*M );
 define_pd_global(bool, NeverActAsServerClassMachine, false);
-define_pd_global(uint64_t,MaxRAM,                    1ULL*G);
+define_pd_global(uint64_t,MaxRAM,                    128ULL*G);
 define_pd_global(bool, CICompileOSR,                 true );
 define_pd_global(bool, ProfileTraps,                 true );
 define_pd_global(bool, UseOnStackReplacement,        true );
@@ -57,7 +57,7 @@
 define_pd_global(uintx,CodeCacheMinBlockLength,      4);
 define_pd_global(uintx, CodeCacheMinimumUseSpace,    400*K);
 define_pd_global(intx, TypeProfileWidth,             8);
-define_pd_global(intx, MethodProfileWidth,           4);
+define_pd_global(intx, MethodProfileWidth,           0);
 #endif // COMPILERGRAAL
 
 #endif // CPU_SPARC_VM_GRAALGLOBALS_SPARC_HPP
--- a/src/cpu/x86/vm/graalGlobals_x86.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/cpu/x86/vm/graalGlobals_x86.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -45,7 +45,7 @@
 define_pd_global(intx, NewSizeThreadIncrease,        4*K  );
 define_pd_global(uintx,MetaspaceSize,                12*M );
 define_pd_global(bool, NeverActAsServerClassMachine, false);
-define_pd_global(uint64_t,MaxRAM,                    1ULL*G);
+define_pd_global(uint64_t,MaxRAM,                    128ULL*G);
 define_pd_global(bool, CICompileOSR,                 true );
 define_pd_global(bool, ProfileTraps,                 true );
 define_pd_global(bool, UseOnStackReplacement,        true );
@@ -57,7 +57,7 @@
 define_pd_global(uintx,CodeCacheMinBlockLength,      4);
 define_pd_global(uintx, CodeCacheMinimumUseSpace,    400*K);
 define_pd_global(intx, TypeProfileWidth,             8);
-define_pd_global(intx, MethodProfileWidth,           4);
+define_pd_global(intx, MethodProfileWidth,           0);
 #endif // COMPILERGRAAL
 
 #endif // CPU_X86_VM_GRAALGLOBALS_X86_HPP
--- a/src/gpu/hsail/vm/gpu_hsail.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/gpu/hsail/vm/gpu_hsail.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -25,15 +25,22 @@
 #include "precompiled.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/gpu.hpp"
+#include "runtime/deoptimization.hpp"
+#include "gpu_hsail.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/exceptions.hpp"
 #include "hsail/vm/gpu_hsail.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/ostream.hpp"
-#include "memory/allocation.hpp"
-#include "memory/allocation.inline.hpp"
 #include "graal/graalEnv.hpp"
 #include "graal/graalCompiler.hpp"
 #include "graal/graalJavaAccess.hpp"
 #include "hsailKernelArguments.hpp"
+#include "hsailJavaCallArguments.hpp"
+#include "code/pcDesc.hpp"
+#include "code/scopeDesc.hpp"
+#include "graal/graalVMToCompiler.hpp"
+#include "gpu_hsail_Frame.hpp"
 
 // Entry to GPU native method implementation that transitions current thread to '_thread_in_vm'.
 #define GPU_VMENTRY(result_type, name, signature) \
@@ -53,13 +60,15 @@
 #define OBJECT                "Ljava/lang/Object;"
 #define STRING                "Ljava/lang/String;"
 #define HS_INSTALLED_CODE     "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;"
+#define HS_COMPILED_NMETHOD   "Lcom/oracle/graal/hotspot/HotSpotCompiledNmethod;"
+#define HS_NMETHOD            "Lcom/oracle/graal/hotspot/meta/HotSpotNmethod;"
 
 //  public native void executeKernel(HotSpotNmethod kernel, int jobSize, int i, int j, Object[] args) throws InvalidInstalledCodeException;
 
 JNINativeMethod Hsail::HSAIL_methods[] = {
   {CC"initialize",       CC"()Z",                               FN_PTR(Hsail::initialize)},
   {CC"generateKernel",   CC"([B" STRING ")J",                   FN_PTR(Hsail::generate_kernel)},
-  {CC"executeKernel0",   CC"("HS_INSTALLED_CODE"I["OBJECT")Z",  FN_PTR(Hsail::execute_kernel_void_1d)},
+  {CC"executeKernel0",   CC"("HS_INSTALLED_CODE"I["OBJECT"["OBJECT")Z",  FN_PTR(Hsail::execute_kernel_void_1d)},
 };
 
 void * Hsail::_device_context = NULL;
@@ -88,7 +97,7 @@
   _okra_register_heap(Universe::heap()->base(), Universe::heap()->capacity());
 }
 
-GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args_handle))
+GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args_handle, jobject oops_save_handle))
 
   ResourceMark rm;
   jlong nmethodValue = HotSpotInstalledCode::codeBlob(kernel_handle);
@@ -104,17 +113,210 @@
     SharedRuntime::throw_and_post_jvmti_exception(JavaThread::current(), vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL);
   }
 
-  objArrayOop args = (objArrayOop) JNIHandles::resolve(args_handle);
+  return execute_kernel_void_1d_internal((address) kernel, dimX, args_handle, mh, nm, oops_save_handle, CHECK_0);
+GPU_END
+
+static void showRanges(jboolean *a, int len) {
+  // show ranges
+  bool lookFor = true;
+  for (int i = 0; i < len; i++) {
+    if ((lookFor == true) && (a[i] != 0)) {
+      tty->print("%d", i);
+      lookFor = false;
+    } else if ((lookFor == false) && (a[i] == 0)) {
+      tty->print_cr("-%d", i-1);
+      lookFor = true;
+    }
+  }
+  if (lookFor == false) {
+    tty->print_cr("-%d", len-1);
+  }
+}
+
+
+// for experimentation
+static bool useDeoptInfo = true;
+
+jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args_handle, methodHandle& mh, nmethod *nm, jobject oops_save_handle, TRAPS) {
+
+  ResourceMark rm(THREAD);
+  objArrayOop argsArray = (objArrayOop) JNIHandles::resolve(args_handle);
 
   // Reset the kernel arguments
   _okra_clearargs(kernel);
 
+  
+  HSAILDeoptimizationInfo* e;
+  if (useDeoptInfo) {
+    e = new (ResourceObj::C_HEAP, mtInternal) HSAILDeoptimizationInfo();
+    e->set_never_ran_array(NEW_C_HEAP_ARRAY(jboolean, dimX, mtInternal));
+    memset(e->never_ran_array(), 0, dimX * sizeof(jboolean));
+  }
+
   // This object sets up the kernel arguments
-  HSAILKernelArguments hka((address) kernel, mh->signature(), args, mh->is_static());
+  HSAILKernelArguments hka((address) kernel, mh->signature(), argsArray, mh->is_static(), e);
+
+  // if any object passed was null, throw an exception here
+  // doing this means the kernel code can avoid null checks on the object parameters.
+  if (hka.getFirstNullParameterIndex() >= 0) {
+    char buf[64];
+    sprintf(buf, "Null Kernel Parameter seen, Parameter Index: %d", hka.getFirstNullParameterIndex());
+    JavaThread* thread = (JavaThread*)THREAD;
+    thread->set_gpu_exception_bci(0);
+    thread->set_gpu_exception_method(mh());
+    THROW_MSG_0(vmSymbols::java_lang_NullPointerException(), buf);
+  }
 
   // Run the kernel
-  return _okra_execute_with_range(kernel, dimX);
-GPU_END
+  bool success = _okra_execute_with_range(kernel, dimX);
+  // check if any workitem requested a deopt
+  // currently we only support at most one such workitem
+
+
+  int deoptcode = e->deopt_occurred();
+  if (useDeoptInfo &&  deoptcode != 0) {
+    if (deoptcode != 1) {
+      // error condition detected in deopt code
+      char msg[200];
+      sprintf(msg, "deopt error detected, slot for workitem %d was not empty", -1*(deoptcode + 1));
+      guarantee(deoptcode == 1, msg);
+    }
+    if (TraceGPUInteraction) {
+      tty->print_cr("deopt happened.");
+      HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[0];
+      tty->print_cr("first deopter was workitem %d", pdeopt->workitem());
+    }
+
+    // Before handling any deopting workitems, save the pointers from
+    // the hsail frames in oops_save so they get adjusted by any
+    // GC. Need to do this before leaving thread_in_vm mode.
+    // resolve handle only needed once here (not exiting vm mode)
+    objArrayOop oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save_handle);
+
+    // since slots are allocated from the beginning, we know how far to look
+    assert(e->num_deopts() < MAX_DEOPT_SAVE_STATES_SIZE, "deopt save state overflow");
+    for (int k = 0; k < e->num_deopts(); k++) {
+      HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[k];
+      jint workitem = pdeopt->workitem();
+      if (workitem != -1) {      
+        // this is a workitem that deopted
+        HSAILFrame *hsailFrame = pdeopt->first_frame();
+        int dregOopMap = hsailFrame->dreg_oops_map();
+        for (int bit = 0; bit < 16; bit++) {
+          if ((dregOopMap & (1 << bit)) != 0) {
+            // the dregister at this bit is an oop, save it in the array
+            int index = k * 16 + bit;
+            void* saved_oop = (void*) hsailFrame->get_d_reg(bit);
+            oopsSaveArray->obj_at_put(index, (oop) saved_oop);
+          }
+        }
+      }
+    }   
+
+    // Handle any deopting workitems. 
+    int count_deoptimized = 0;
+    for (int k = 0; k < e->num_deopts(); k++) {
+      HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[k];
+    
+      jint workitem = pdeopt->workitem();
+      if (workitem != -1) {      
+        int deoptId = pdeopt->pc_offset();
+        HSAILFrame *hsailFrame = pdeopt->first_frame();
+
+        // update the hsailFrame from the oopsSaveArray
+        // re-resolve the handle
+        oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save_handle);
+
+        int dregOopMap = hsailFrame->dreg_oops_map();
+        for (int bit = 0; bit < 16; bit++) {
+          if ((dregOopMap & (1 << bit)) != 0) {
+            // the dregister at this bit is an oop, retrieve it from array and put back in frame
+            int index = k * 16 + bit;
+            void * dregValue = (void *) oopsSaveArray->obj_at(index);
+            void * oldDregValue = (void *) hsailFrame->get_d_reg(bit);
+            assert((oldDregValue != 0 ? dregValue != 0 : dregValue == 0) , "bad dregValue retrieved");
+            if (TraceGPUInteraction) {
+              if (dregValue != oldDregValue) {
+                tty->print_cr("oop moved for $d%d, workitem %d, slot %d, old=%p, new=%p", bit, workitem, k, oldDregValue, dregValue);
+              }
+            }
+            hsailFrame->put_d_reg(bit, (jlong) dregValue);
+          }
+        }
+       
+        JavaValue result(T_VOID);
+        JavaCallArguments javaArgs;
+        javaArgs.set_alternative_target(nm);
+        javaArgs.push_int(deoptId);
+        javaArgs.push_long((jlong) hsailFrame);
+
+        // override the deoptimization action with Action_none until we decide
+        // how to handle the other actions.
+        int myActionReason = Deoptimization::make_trap_request(Deoptimization::trap_request_reason(pdeopt->reason()), Deoptimization::Action_none);
+        javaArgs.push_int(myActionReason);
+        javaArgs.push_oop((oop)NULL);
+        if (TraceGPUInteraction) {
+          int dregOopMap = hsailFrame->dreg_oops_map();
+          tty->print_cr("[HSAIL] Deoptimizing to host for workitem=%d (slot=%d) with deoptId=%d, frame=" INTPTR_FORMAT ", actionAndReason=%d, dregOopMap=%04x", workitem, k, deoptId, hsailFrame, myActionReason, dregOopMap);
+          // show the registers containing references
+          for (int bit = 0; bit < 16; bit++) {
+            if ((dregOopMap & (1 << bit)) != 0) {
+              tty->print_cr("  oop $d%d = %p", bit, hsailFrame->get_d_reg(bit));
+            }
+          }
+        }
+        JavaCalls::call(&result, mh, &javaArgs, THREAD);
+        count_deoptimized++;
+      }
+    }    
+    if (TraceGPUInteraction) {
+      tty->print_cr("[HSAIL] Deoptimizing to host completed for %d workitems", count_deoptimized);
+    }
+
+    // Handle any never_ran workitems if there were any
+    int count_never_ran = 0;
+    bool handleNeverRansHere = true;
+    // turn off verbose trace stuff for javacall arg setup
+    bool savedTraceGPUInteraction = TraceGPUInteraction;
+    TraceGPUInteraction = false;
+    jboolean *never_ran_array = e->never_ran_array();
+    if (handleNeverRansHere) {
+      for (int k = 0; k < dimX; k++) {
+        if (never_ran_array[k]) {
+          // run it as a javaCall
+          KlassHandle methKlass = mh->method_holder();
+          Thread* THREAD = Thread::current();
+          JavaValue result(T_VOID);
+          JavaCallArguments javaArgs;
+          // re-resolve the args_handle here
+          objArrayOop resolvedArgsArray = (objArrayOop) JNIHandles::resolve(args_handle);
+          // This object sets up the javaCall arguments
+          // the way argsArray is set up, this should work for instance methods as well
+          // (the receiver will be the first oop pushed)
+          HSAILJavaCallArguments hjca(&javaArgs, k, mh->signature(), resolvedArgsArray, mh->is_static());
+          if (mh->is_static()) {
+            JavaCalls::call_static(&result, methKlass, mh->name(), mh->signature(), &javaArgs, THREAD);
+          } else {
+            JavaCalls::call_virtual(&result, methKlass, mh->name(), mh->signature(), &javaArgs, THREAD);
+          }
+          count_never_ran++;
+        }
+      }
+      TraceGPUInteraction = savedTraceGPUInteraction;
+      if (TraceGPUInteraction) {
+        tty->print_cr("%d workitems never ran, have been run via JavaCall", count_never_ran);
+        showRanges(never_ran_array, dimX);
+      }
+    } // end of never-ran handling
+
+  }
+
+  if (useDeoptInfo) {
+    FREE_C_HEAP_ARRAY(jboolean, e->never_ran_array(), mtInternal);
+    delete e;
+  }
+  return success;
+}
 
 GPU_ENTRY(jlong, Hsail::generate_kernel, (JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle))
   guarantee(_okra_create_kernel != NULL, "[HSAIL] Okra not linked");
@@ -172,6 +374,7 @@
   if (TraceGPUInteraction) {
       tty->print_cr("[HSAIL] library is %s", okra_library_name);
   }
+
   void *handle = os::dll_load(okra_library_name, ebuf, O_BUFLEN);
   // try alternate location if env variable set
   char *okra_lib_name_from_env_var = getenv("_OKRA_SIM_LIB_PATH_");
@@ -212,6 +415,7 @@
   return true;
 GPU_END
 
+
 bool Hsail::register_natives(JNIEnv* env) {
   jclass klass = env->FindClass("com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend");
   if (klass == NULL) {
--- a/src/gpu/hsail/vm/gpu_hsail.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/gpu/hsail/vm/gpu_hsail.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -25,7 +25,60 @@
 #ifndef GPU_HSAIL_HPP
 #define GPU_HSAIL_HPP
 
+#include "utilities/exceptions.hpp"
+#include "graal/graalEnv.hpp"
+// #include "graal/graalCodeInstaller.hpp"
+#include "gpu_hsail_Frame.hpp"
+
 class Hsail {
+  friend class gpu;
+
+  public:
+  class HSAILKernelDeoptimization {
+    friend class VMStructs;
+   private:
+    // TODO: separate workitemid and actionAndReason out
+    // since they are there only once even if there are multiple frames
+    // for now, though we only ever have one hsail fram
+    jint  _workitemid;
+    jint  _actionAndReason;
+    // the first (innermost) "hsail frame" starts here
+    HSAILFrame _first_frame;
+
+   public:
+    inline jint workitem() { return _workitemid; }
+    inline jint reason() { return _actionAndReason; }
+    inline jint pc_offset() { return _first_frame.pc_offset(); }
+    inline HSAILFrame *first_frame() { return &_first_frame; }
+  };
+
+// 8 compute units * 40 waves per cu * wavesize 64
+#define MAX_DEOPT_SAVE_STATES_SIZE    (8 * 40 * 64)
+
+  class HSAILDeoptimizationInfo : public ResourceObj {
+    friend class VMStructs;
+   private:
+    jint _deopt_occurred;
+    jint _deopt_next_index;
+    jboolean * _never_ran_array;
+
+   public:
+    HSAILKernelDeoptimization _deopt_save_states[MAX_DEOPT_SAVE_STATES_SIZE];
+
+    inline HSAILDeoptimizationInfo() {
+      _deopt_occurred = 0;
+      _deopt_next_index = 0;
+    }
+
+    inline jint deopt_occurred() {
+      // Check that hsail did not write in the wrong place
+      return _deopt_occurred;
+    }
+    inline jint num_deopts() { return _deopt_next_index; }
+    inline jboolean *never_ran_array() { return _never_ran_array; }
+    inline void  set_never_ran_array(jboolean *p) { _never_ran_array = p; }
+  };
+
 
 private:
 
@@ -38,10 +91,18 @@
   JNIEXPORT static jlong generate_kernel(JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle);
 
   // static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args);
-  JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv *env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args);
+  JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv *env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args, jobject oopsSave);
+
+  // static native void setSimulatorSingleThreaded0();
+  JNIEXPORT static void setSimulatorSingleThreaded0(JNIEnv *env, jclass);
+
+
+  static jboolean execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oopsSave, TRAPS);
 
   static void register_heap();
 
+  static GraalEnv::CodeInstallResult install_code(Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations);
+
 public:
 
   // Registers the implementations for the native methods in HSAILHotSpotBackend
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/gpu_hsail_Frame.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,44 @@
+#ifndef GPU_HSAIL_FRAME_HPP
+#define GPU_HSAIL_FRAME_HPP
+
+#include "graal/graalEnv.hpp"
+#include "code/debugInfo.hpp"
+#include "code/location.hpp"
+
+// maximum registers that could be saved for now
+#define MAX_SREGS 32
+#define MAX_DREGS 16
+
+class HSAILFrame {
+  friend class VMStructs;
+private:
+  jint  _pc_offset;  // The HSAIL "pc_offset" where the exception happens
+  jbyte _num_s_regs;
+  jbyte _num_d_regs;
+  jshort _dreg_oops_map;  // bits = 1 if that dreg is an oop
+  jlong  _save_area[MAX_SREGS/2 + MAX_DREGS];  
+
+public:
+  // Accessors
+  jint pc_offset() { return _pc_offset; }
+  jint num_s_regs() {return _num_s_regs; }
+  jint num_d_regs() {return _num_d_regs; }
+  jint dreg_oops_map() {return _dreg_oops_map; }
+  jlong get_d_reg(int idx) {
+    char *p = (char *) _save_area;
+    int ofst = num_s_regs() * 4 + idx * 8;
+    return(*(jlong *) (p + ofst));
+  }
+  jint get_s_reg(int idx) {
+    char *p = (char *) _save_area;
+    int ofst = idx * 4;
+    return(*(jint *) (p + ofst));
+  }
+  void put_d_reg(int idx, jlong val) {
+    char *p = (char *) _save_area;
+    int ofst = num_s_regs() * 4 + idx * 8;
+    (*(jlong *) (p + ofst)) = val;
+  }
+};
+  
+#endif // GPU_HSAIL_FRAME_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/hsailArgumentsBase.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "hsailArgumentsBase.hpp"
+#include "runtime/javaCalls.hpp"
+
+
+// Get next java argument
+oop HSAILArgumentsBase::next_arg(BasicType expectedType) {
+  assert(_index < _args->length(), "out of bounds");
+
+  oop arg = ((objArrayOop) (_args))->obj_at(_index++);
+  assert(expectedType == T_OBJECT ||
+         java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch");
+
+  return arg;
+}
+
+void HSAILArgumentsBase::do_bool() {
+  // Get the boxed value
+  oop arg = _args->obj_at(_index++);
+  assert(java_lang_boxing_object::is_instance(arg, T_BOOLEAN), "arg type mismatch");
+  
+  jvalue jValue;
+  java_lang_boxing_object::get_value(arg, &jValue);
+  
+  pushBool(jValue.z);
+}
+
+void HSAILArgumentsBase::do_byte() {
+  // Get the boxed value
+  oop arg = _args->obj_at(_index++);
+  assert(java_lang_boxing_object::is_instance(arg, T_BYTE), "arg type mismatch");
+  
+  jvalue jValue;
+  java_lang_boxing_object::get_value(arg, &jValue);
+
+  pushByte(jValue.b);
+}
+
+void HSAILArgumentsBase::do_double() {
+  // Get the boxed value
+  oop arg = _args->obj_at(_index++);
+  assert(java_lang_boxing_object::is_instance(arg, T_DOUBLE), "arg type mismatch");
+  
+  jvalue jValue;
+  java_lang_boxing_object::get_value(arg, &jValue);
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::do_double, _index=%d, value = %e", argsBuilderName(), _index - 1, jValue.d);
+  }  
+  pushDouble(jValue.d);
+}
+
+void HSAILArgumentsBase::do_float() {
+  // Get the boxed value
+  oop arg = _args->obj_at(_index++);
+  assert(java_lang_boxing_object::is_instance(arg, T_FLOAT), "arg type mismatch");
+  
+  jvalue jValue;
+  java_lang_boxing_object::get_value(arg, &jValue);
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::do_float, _index=%d, value = %f", argsBuilderName(), _index - 1, jValue.f);
+  }  
+  pushFloat(jValue.f);
+}
+
+void HSAILArgumentsBase::do_int() {
+  // If the last parameter is an int, it is handled in a special way
+  // For kernel arguments we don't pass it since we use the HSAIL workitemid in place of that int value
+  // For javaCall arguments we pass the actual workitemid
+  if (isLastParameter()) {
+    handleFinalIntParameter();
+    return;
+  }
+
+  // not the final int parameter, Get the boxed int
+  oop arg = _args->obj_at(_index++);
+  assert(java_lang_boxing_object::is_instance(arg, T_INT), "arg type mismatch");
+  
+  jvalue jValue;
+  java_lang_boxing_object::get_value(arg, &jValue);
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::do_int, _index=%d, value = %d", argsBuilderName(), _index - 1, jValue.i);
+  }    
+  
+  pushInt(jValue.i);
+}
+
+void HSAILArgumentsBase::do_long() {
+  // Get the boxed value
+  oop arg = _args->obj_at(_index++);
+  assert(java_lang_boxing_object::is_instance(arg, T_LONG), "arg type mismatch");
+  
+  jvalue jValue;
+  java_lang_boxing_object::get_value(arg, &jValue);
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::do_long, _index=%d, value = %d", argsBuilderName(), _index - 1, jValue.j);
+  }    
+
+  pushLong(jValue.j);
+}
+
+void HSAILArgumentsBase::do_array(int begin, int end) {
+  oop arg = _args->obj_at(_index++);
+  if (arg == NULL) {
+      recordNullObjectParameter();
+  } else {
+      assert(arg->is_array(), "arg type mismatch");
+  }
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::do_array, _index=%d, 0x%08x, is a %s", argsBuilderName(), _index - 1, (address) arg,
+                  arg == NULL ? "null" : arg->klass()->external_name());
+  }
+    
+  pushObject(arg);
+}
+
+void HSAILArgumentsBase::do_object() {
+  bool isLastParam = isLastParameter();  // determine this before incrementing _index
+
+  oop arg = _args->obj_at(_index++);
+  if (TraceGPUInteraction) {
+    tty->print_cr("[HSAIL] %s::do_object, _index=%d, 0x%08x is a %s", argsBuilderName(), _index - 1, (address) arg,
+                  arg == NULL ? "null" : arg->klass()->external_name());
+  }
+  if (arg == NULL) {
+      recordNullObjectParameter();
+  }
+
+  // check if this is last arg in signature
+  // an object as last parameter requires special handling
+  if (isLastParam) {
+    if (TraceGPUInteraction) {
+      tty->print_cr("[HSAIL] %s, trailing object ref should be object source array ref", argsBuilderName());
+    }
+    assert(arg->is_objArray(), "arg type mismatch");
+    handleFinalObjParameter(arg);
+  } else {
+    // not the final parameter, just push
+    pushObject(arg);
+  }
+}
+
+void HSAILArgumentsBase::do_object(int begin, int end) {
+  do_object();
+}
+
+void HSAILArgumentsBase::do_void() {
+    return;
+}
+
+// TODO implement other do_*
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/hsailArgumentsBase.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef BASE_ARGUMENTS_HSAIL_HPP
+#define BASE_ARGUMENTS_HSAIL_HPP
+
+#include "runtime/signature.hpp"
+
+
+/***
+ * Base class which iterates thru a signature and pulls from a
+ * objArrayOop of boxed values.  Used as base for HSAILKernelArguments
+ * and HSAILJavaCallArguments The derived classes specify how to push
+ * args onto their data structure
+ ***/
+
+class HSAILArgumentsBase : public SignatureIterator {
+
+public:
+
+private:
+  // Array of java argument oops
+  objArrayOop _args;
+  // Length of args array
+  int   _length;
+  // Current index into _args
+  int _index;
+  // number of parameters in the signature
+  int _parameter_count;
+
+  Symbol * _signature;
+  bool _is_static;
+
+  // records first null parameter seen
+  int _first_null_parameter_index;
+  
+  // Get next java argument
+  oop next_arg(BasicType expectedType);
+
+    virtual char *argsBuilderName() = 0;
+    virtual void pushObject(void * obj) = 0;
+    virtual void pushBool(jboolean z) = 0;
+    virtual void pushByte(jbyte b) = 0;
+    virtual void pushDouble(jdouble d) = 0;
+    virtual void pushFloat(jfloat f) = 0;
+    virtual void pushInt(jint i) = 0;
+    virtual void pushLong(jlong j) = 0;
+    virtual void handleFinalIntParameter() = 0;
+    virtual void handleFinalObjParameter(void *obj) = 0;
+    virtual void pushTrailingArgs() = 0;
+
+    void recordNullObjectParameter() {
+        if (_first_null_parameter_index == -1) _first_null_parameter_index = _parameter_index;
+    }
+
+ public:
+  HSAILArgumentsBase(Symbol* signature, objArrayOop args, bool is_static) : SignatureIterator(signature) {
+    this->_return_type = T_ILLEGAL;
+    _index = 0;
+    _args = args;
+    _is_static = is_static;
+    _signature = signature;
+
+    _length = args->length();
+    _parameter_count = ArgumentCount(signature).size();
+
+    _first_null_parameter_index = -1;
+
+  }
+
+  int getFirstNullParameterIndex() {
+    return _first_null_parameter_index;
+  }
+
+  void collectArgs() {
+    if (TraceGPUInteraction) {
+      tty->print_cr("[HSAIL] %s::collectArgs, sig:%s  args length=%d", argsBuilderName(), _signature->as_C_string(), _length);
+    }    
+    if (!_is_static) {      
+      // First object in args should be 'this'
+      oop arg = _args->obj_at(_index++);
+      assert(arg->is_instance() && (! arg->is_array()), "First arg should be 'this'");
+      if (TraceGPUInteraction) {
+        tty->print_cr("[HSAIL] %s, instance method, this " PTR_FORMAT ", is a %s", argsBuilderName(), (address) arg, arg->klass()->external_name());
+      }
+      pushObject(arg);
+    } else {
+      if (TraceGPUInteraction) {
+          tty->print_cr("[HSAIL] %s, static method", argsBuilderName());
+      }
+    }
+    // Iterate over the entire signature
+    iterate();
+    
+    pushTrailingArgs();
+  }
+
+  void do_bool();
+  void do_byte();
+  void do_double();
+  void do_float();
+  void do_int();
+  void do_long();
+  void do_array(int begin, int end);
+  void do_object();
+  void do_object(int begin, int end);
+
+  void do_void();
+
+  inline void do_char()   {
+    /* TODO : To be implemented */
+    guarantee(false, "do_char:NYI");
+  }
+  inline void do_short()  {
+    /* TODO : To be implemented */
+    guarantee(false, "do_short:NYI");
+  }
+
+  bool isLastParameter() {
+      return  (_index == (_is_static ?  _parameter_count - 1 : _parameter_count));
+  }
+
+};
+
+#endif  // BASE_ARGUMENTS_HSAIL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/hsailJavaCallArguments.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef JAVACALL_ARGUMENTS_HSAIL_HPP
+#define JAVACALL_ARGUMENTS_HSAIL_HPP
+
+#include "hsailArgumentsBase.hpp"
+#include "runtime/javaCalls.hpp"
+
+class HSAILJavaCallArguments : public HSAILArgumentsBase {
+
+public:
+
+private:
+  // JavaCall Args to push into
+  JavaCallArguments *_javaArgs;
+  int _workitemid;
+ public:
+    HSAILJavaCallArguments(JavaCallArguments *javaArgs, int workitemid, Symbol* signature, objArrayOop args, bool is_static) : HSAILArgumentsBase(signature, args, is_static) {
+        _javaArgs = javaArgs;
+        _workitemid = workitemid;
+        collectArgs();
+    }
+    virtual char *argsBuilderName() {return (char *)"HSAILJavaCallArguments";}
+    virtual void pushObject(void *obj) { _javaArgs->push_oop((oop) obj);  }
+    virtual void pushBool(jboolean z) { pushInt(z); }
+    virtual void pushByte(jbyte b) { pushInt(b); }
+    virtual void pushDouble(jdouble d) { _javaArgs->push_double(d); }
+    virtual void pushFloat(jfloat f) { _javaArgs->push_float(f); }
+    virtual void pushInt(jint i) { _javaArgs->push_int(i); }
+    virtual void pushLong(jlong j) { _javaArgs->push_long(j); }
+    virtual void pushTrailingArgs() {  }
+
+    // For javaCall the final int parameter gets replaced with the workitemid
+    // which was passed back in the deopt info
+    virtual void handleFinalIntParameter() {
+      if (TraceGPUInteraction) {
+        tty->print_cr("[HSAIL] HSAILJavaCallArguments, passing workitemid %d as trailing int parameter", _workitemid);
+      }
+      pushInt(_workitemid);
+    }
+    // for kernel arguments, final obj parameter should be an object
+    // stream source array (already checked in the base class) so for
+    // a javacall we need to extract the correct obj from it based on
+    // the workitemid
+    virtual void handleFinalObjParameter(void *arg) {
+      objArrayOop objArrayArg = (objArrayOop) arg;
+      oop extractedObj = objArrayArg->obj_at(_workitemid);
+      if (TraceGPUInteraction) {
+        tty->print_cr("[HSAIL] HSAILJavaCallArguments, extracted obj #%d from array, 0x%08x is a %s",
+                      _workitemid, (address) extractedObj,
+                      (extractedObj == NULL ? "null" : extractedObj->klass()->external_name()));
+      }
+      pushObject(extractedObj);
+    }
+
+};
+
+#endif  // JAVACALL_ARGUMENTS_HSAIL_HPP
+
--- a/src/gpu/hsail/vm/hsailKernelArguments.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "hsailKernelArguments.hpp"
-#include "runtime/javaCalls.hpp"
-
-
-// Get next java argument
-oop HSAILKernelArguments::next_arg(BasicType expectedType) {
-  assert(_index < _args->length(), "out of bounds");
-
-  oop arg = ((objArrayOop) (_args))->obj_at(_index++);
-  assert(expectedType == T_OBJECT ||
-         java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch");
-
-  return arg;
-}
-
-void HSAILKernelArguments::do_bool() {
-  // Get the boxed value
-  oop arg = _args->obj_at(_index++);
-  assert(java_lang_boxing_object::is_instance(arg, T_BOOLEAN), "arg type mismatch");
-  
-  jvalue jValue;
-  java_lang_boxing_object::get_value(arg, &jValue);
-  
-  bool pushed = Hsail::_okra_push_boolean(_kernel, jValue.z);
-  assert(pushed == true, "arg push failed");
-}
-
-void HSAILKernelArguments::do_byte() {
-  // Get the boxed value
-  oop arg = _args->obj_at(_index++);
-  assert(java_lang_boxing_object::is_instance(arg, T_BYTE), "arg type mismatch");
-  
-  jvalue jValue;
-  java_lang_boxing_object::get_value(arg, &jValue);
-  
-  bool pushed = Hsail::_okra_push_byte(_kernel, jValue.b);
-  assert(pushed == true, "arg push failed");
-}
-
-void HSAILKernelArguments::do_double() {
-  // Get the boxed value
-  oop arg = _args->obj_at(_index++);
-  assert(java_lang_boxing_object::is_instance(arg, T_DOUBLE), "arg type mismatch");
-  
-  jvalue jValue;
-  java_lang_boxing_object::get_value(arg, &jValue);
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_double, _index=%d, value = %e", _index - 1, jValue.d);
-  }  
-  bool pushed = Hsail::_okra_push_double(_kernel, jValue.d);
-  assert(pushed == true, "arg push failed");
-}
-
-void HSAILKernelArguments::do_float() {
-  // Get the boxed value
-  oop arg = _args->obj_at(_index++);
-  assert(java_lang_boxing_object::is_instance(arg, T_FLOAT), "arg type mismatch");
-  
-  jvalue jValue;
-  java_lang_boxing_object::get_value(arg, &jValue);
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_float, _index=%d, value = %f", _index - 1, jValue.f);
-  }    
-  bool pushed = Hsail::_okra_push_float(_kernel, jValue.f);
-  assert(pushed == true, "float push failed");
-}
-
-void HSAILKernelArguments::do_int() {
-  // The last int is the iteration variable in an IntStream, but we don't pass it
-  // since we use the HSAIL workitemid in place of that int value
-  if (isLastParameter()) {
-    if (TraceGPUInteraction) {
-      tty->print_cr("[HSAIL] HSAILKernelArguments::not pushing trailing int");
-    }
-    return;
-  }
-
-  // Get the boxed int
-  oop arg = _args->obj_at(_index++);
-  assert(java_lang_boxing_object::is_instance(arg, T_INT), "arg type mismatch");
-  
-  jvalue jValue;
-  java_lang_boxing_object::get_value(arg, &jValue);
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_int, _index=%d, value = %d", _index - 1, jValue.i);
-  }    
-  
-  bool pushed = Hsail::_okra_push_int(_kernel, jValue.i);
-  assert(pushed == true, "arg push failed");
-}
-
-void HSAILKernelArguments::do_long() {
-  // Get the boxed value
-  oop arg = _args->obj_at(_index++);
-  assert(java_lang_boxing_object::is_instance(arg, T_LONG), "arg type mismatch");
-  
-  jvalue jValue;
-  java_lang_boxing_object::get_value(arg, &jValue);
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_long, _index=%d, value = %d", _index - 1, jValue.j);
-  }    
-  
-  bool pushed = Hsail::_okra_push_long(_kernel, jValue.j);
-  assert(pushed == true, "arg push failed");  
-}
-
-void HSAILKernelArguments::do_array(int begin, int end) {
-  oop arg = _args->obj_at(_index++);
-  assert(arg->is_array(), "arg type mismatch");
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_array, _index=%d, 0x%08x, is a %s", _index - 1, (address) arg, arg->klass()->external_name());
-  }
-    
-  bool pushed = Hsail::_okra_push_object(_kernel, arg);
-  assert(pushed == true, "arg push failed");  
-}
-
-void HSAILKernelArguments::do_object() {
-  
-  bool isLastParam = isLastParameter();  // determine this before incrementing _index
-
-  oop arg = _args->obj_at(_index++);
-
-  // check if this is last arg in signature
-  // an object as last parameter requires an object stream source array to be passed
-  if (isLastParam) {
-    if (TraceGPUInteraction) {
-      tty->print_cr("[HSAIL] HSAILKernelArguments::trailing object ref should be object source array ref");
-    }
-    assert(arg->is_objArray(), "arg type mismatch");
-  }
-
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, _index=%d, 0x%08x is a %s", _index - 1, (address) arg, arg->klass()->external_name());
-  }
-    
-  bool pushed = Hsail::_okra_push_object(_kernel, arg);
-  assert(pushed == true, "arg push failed");  
-}
-
-void HSAILKernelArguments::do_object(int begin, int end) {
-  if (TraceGPUInteraction) {
-      tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int begin, int end), begin=%d, end=%d.", begin, end);
-  }
-  do_object();
-}
-
-void HSAILKernelArguments::do_void() {
-    return;
-}
-
-// TODO implement other do_*
--- a/src/gpu/hsail/vm/hsailKernelArguments.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -25,90 +25,80 @@
 #ifndef KERNEL_ARGUMENTS_HSAIL_HPP
 #define KERNEL_ARGUMENTS_HSAIL_HPP
 
-#include "runtime/gpu.hpp"
-#include "hsail/vm/gpu_hsail.hpp"
+#include "gpu_hsail.hpp"
 #include "runtime/signature.hpp"
+#include "hsailArgumentsBase.hpp"
 
-class HSAILKernelArguments : public SignatureIterator {
+class HSAILKernelArguments : public HSAILArgumentsBase {
   friend class Hsail;
 
 public:
 
 private:
-  // Array of java argument oops
-  objArrayOop _args;
-  // Length of args array
-  int   _length;
-  // Current index into _args
-  int _index;
   // Kernel to push into
   address _kernel;
-  // number of parameters in the signature
-  int _parameter_count;
-
-  bool _is_static;
-  
-  // Get next java argument
-  oop next_arg(BasicType expectedType);
+  void * _exceptionHolder;
 
  public:
-  HSAILKernelArguments(address kernel, Symbol* signature, objArrayOop args, bool is_static) : SignatureIterator(signature) {
-    this->_return_type = T_ILLEGAL;
-    _index = 0;
-    _args = args;
-    _kernel = kernel;
-    _is_static = is_static;
+    HSAILKernelArguments(address kernel, Symbol* signature, objArrayOop args, bool is_static, void* exceptionHolder) : HSAILArgumentsBase(signature, args, is_static) {
+        _kernel = kernel;
+        _exceptionHolder = exceptionHolder;
+        collectArgs();
+    }
+    virtual char *argsBuilderName() {return (char *)"HSAILKernelArguments";}
+    virtual void pushObject(void *obj) {
+        bool pushed = Hsail::_okra_push_object(_kernel, obj);
+        assert(pushed == true, "arg push failed");
+    }
+    virtual void pushBool(jboolean z) {
+        bool pushed = Hsail::_okra_push_boolean(_kernel, z);
+        assert(pushed == true, "arg push failed");
+    }
+    virtual void pushByte(jbyte b) {
+        bool pushed = Hsail::_okra_push_byte(_kernel, b);
+        assert(pushed == true, "arg push failed");
+    }
 
-    _length = args->length();
-    _parameter_count = ArgumentCount(signature).size();
+    virtual void pushDouble(jdouble d) {
+        bool pushed = Hsail::_okra_push_double(_kernel, d);
+        assert(pushed == true, "arg push failed");
+    }
 
-    if (TraceGPUInteraction) {
-      char buf[O_BUFLEN];
-      tty->print_cr("[HSAIL] sig:%s  args length=%d, _parameter_count=%d", signature->as_C_string(buf, O_BUFLEN), _length, _parameter_count);
-    }    
-    if (!_is_static) {      
-      // First object in args should be 'this'
-      oop arg = args->obj_at(_index++);
-      assert(arg->is_instance() && (! arg->is_array()), "First arg should be 'this'");
+    virtual void pushFloat(jfloat f) {
+        bool pushed = Hsail::_okra_push_float(_kernel, f);
+        assert(pushed == true, "arg push failed");
+    }
+
+    virtual void pushInt(jint i) {
+        bool pushed = Hsail::_okra_push_int(_kernel, i);
+        assert(pushed == true, "arg push failed");
+    }
+
+    virtual void pushLong(jlong j) {
+        bool pushed = Hsail::_okra_push_long(_kernel, j);
+        assert(pushed == true, "arg push failed");
+    }
+    virtual void pushTrailingArgs() {
+        // Last argument is the exception info block
+        if (TraceGPUInteraction) {
+            tty->print_cr("[HSAIL] exception block=" PTR_FORMAT, _exceptionHolder);
+        }
+        pushObject(_exceptionHolder);
+    }
+
+    // For kernel arguments we don't pass the final int parameter
+    // since we use the HSAIL workitemid instruction in place of that int value
+    virtual void handleFinalIntParameter() {
       if (TraceGPUInteraction) {
-        tty->print_cr("[HSAIL] instance method, this 0x%08x, is a %s", (address) arg, arg->klass()->external_name());
-      }
-      bool pushed = Hsail::_okra_push_object(kernel, arg);
-      assert(pushed == true, "'this' push failed");
-    } else {
-      if (TraceGPUInteraction) {
-        tty->print_cr("[HSAIL] static method");
+        tty->print_cr("[HSAIL] HSAILKernelArguments, not pushing trailing int");
       }
     }
-    // Iterate over the entire signature
-    iterate();
-  }
 
-  void do_bool();
-  void do_byte();
-  void do_double();
-  void do_float();
-  void do_int();
-  void do_long();
-  void do_array(int begin, int end);
-  void do_object();
-  void do_object(int begin, int end);
-
-  void do_void();
-
-  inline void do_char()   {
-    /* TODO : To be implemented */
-    guarantee(false, "do_char:NYI");
-  }
-  inline void do_short()  {
-    /* TODO : To be implemented */
-    guarantee(false, "do_short:NYI");
-  }
-
-  bool isLastParameter() {
-      return  (_index == (_is_static ?  _parameter_count - 1 : _parameter_count));
-  }
-
+    // for kernel arguments, final obj parameter should be an object
+    // stream source array (already checked in the base class) so here we just pass it
+    virtual void handleFinalObjParameter(void *arg) {
+      pushObject(arg);
+    }
 };
 
-#endif  // KERNEL_ARGUMENTS_HPP
+#endif  // KERNEL_ARGUMENTS_HSAIL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/hsail/vm/vmStructs_hsail.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP
+#define GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP
+
+#include "gpu_hsail.hpp"
+#include "gpu_hsail_Frame.hpp"
+
+// These are the CPU-specific fields, types and integer
+// constants required by the Serviceability Agent. This file is
+// referenced by vmStructs.cpp.
+
+#define VM_STRUCTS_GPU_HSAIL(nonstatic_field)                                                                                                    \
+  nonstatic_field(HSAILFrame, _pc_offset,                                                  jint)                                      \
+  nonstatic_field(HSAILFrame, _num_s_regs,                                                 jbyte)                                     \
+  nonstatic_field(HSAILFrame, _save_area[0],                                               jlong)                                     \
+                                                                                                                                                                                                                                                                                      \
+  nonstatic_field(Hsail::HSAILKernelDeoptimization, _workitemid,                                jint)                                 \
+  nonstatic_field(Hsail::HSAILKernelDeoptimization, _actionAndReason,                           jint)                                 \
+  nonstatic_field(Hsail::HSAILKernelDeoptimization, _first_frame,                               HSAILFrame)                      \
+                                                                                                                                           \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_occurred,                         jint)                                      \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_next_index,                       jint)                                      \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _never_ran_array,                        jboolean *)                                \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_save_states[0],                   Hsail::HSAILKernelDeoptimization)          \
+  nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_save_states[1],                   Hsail::HSAILKernelDeoptimization)
+
+#define VM_TYPES_GPU_HSAIL(declare_type, declare_toplevel_type)                 \
+  declare_toplevel_type(HSAILFrame)                                  \
+  declare_toplevel_type(HSAILFrame*)                                 \
+  declare_toplevel_type(Hsail::HSAILKernelDeoptimization)            \
+  declare_toplevel_type(Hsail::HSAILDeoptimizationInfo)
+
+#endif // GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java	Sun Mar 30 16:08:33 2014 +0200
@@ -29,11 +29,12 @@
 import com.sun.hotspot.igv.graph.Diagram;
 import com.sun.hotspot.igv.graph.Figure;
 import com.sun.hotspot.igv.graph.InputSlot;
+import com.sun.hotspot.igv.graph.OutputSlot;
 import java.util.HashSet;
 import java.util.Set;
 
 public class GraalCFGFilter extends AbstractFilter {
-    
+
     @Override
     public String getName() {
         return "Graal CFG Filter";
@@ -41,16 +42,8 @@
 
     @Override
     public void apply(Diagram d) {
-        Set<Figure> figuresToRemove = new HashSet<>();
         Set<Connection> connectionsToRemove = new HashSet<>();
-        for (Figure f : d.getFigures()) {
-            final String prop = f.getProperties().get("probability");
-            if (prop == null) {
-                figuresToRemove.add(f);
-            }
-        }
-        d.removeAllFigures(figuresToRemove);
-        
+
         for (Figure f : d.getFigures()) {
             Properties p = f.getProperties();
             int predCount;
@@ -72,10 +65,25 @@
                 }
             }
         }
-        
+
         for (Connection c : connectionsToRemove) {
             c.remove();
-            System.out.println("rm " + c);
         }
+
+        Set<Figure> figuresToRemove = new HashSet<>();
+        next: for (Figure f : d.getFigures()) {
+            for (InputSlot is : f.getInputSlots()) {
+                if (!is.getConnections().isEmpty()) {
+                    continue next;
+                }
+            }
+            for (OutputSlot os : f.getOutputSlots()) {
+                if (!os.getConnections().isEmpty()) {
+                    continue next;
+                }
+            }
+            figuresToRemove.add(f);
+        }
+        d.removeAllFigures(figuresToRemove);
     }
 }
--- a/src/share/vm/classfile/javaClasses.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/classfile/javaClasses.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -1530,6 +1530,16 @@
     }
     return;
   }
+  
+  // Check for gpu exception to add as top frame
+  Method* gpu_method = thread->get_gpu_exception_method();
+  if (gpu_method != NULL) {
+    jint gpu_bci = thread->get_gpu_exception_bci();
+    bt.push(gpu_method, gpu_bci, CHECK);
+    // Clear the gpu exception state, it is not used after here
+    thread->set_gpu_exception_bci(0);
+    thread->set_gpu_exception_method(NULL);  
+  }
 
   // Instead of using vframe directly, this version of fill_in_stack_trace
   // basically handles everything by hand. This significantly improved the
--- a/src/share/vm/classfile/systemDictionary.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -184,6 +184,7 @@
   do_klass(Long_klass,                                  java_lang_Long,                            Pre                 ) \
                                                                                                                          \
   /* Support for Graal */                                                                                                \
+  do_klass(CompilerThread_klass,                  com_oracle_graal_compiler_CompilerThread,                     Opt) \
   do_klass(BitSet_klass,                          java_util_BitSet,                                             Opt) \
   /* graal.hotspot */                                                                                                \
   do_klass(HotSpotCompiledCode_klass,             com_oracle_graal_hotspot_HotSpotCompiledCode,                 Opt) \
@@ -203,7 +204,6 @@
   do_klass(HotSpotResolvedJavaMethod_klass,       com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod,      Opt) \
   do_klass(HotSpotResolvedObjectType_klass,       com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,      Opt) \
   do_klass(HotSpotMonitorValue_klass,             com_oracle_graal_hotspot_meta_HotSpotMonitorValue,            Opt) \
-  do_klass(CompilerThread_klass,                  com_oracle_graal_hotspot_CompilerThread,                      Opt) \
   /* graal.api.code */                                                                                               \
   do_klass(Assumptions_klass,                     com_oracle_graal_api_code_Assumptions,                        Opt) \
   do_klass(Assumptions_ConcreteMethod_klass,      com_oracle_graal_api_code_Assumptions_ConcreteMethod,         Opt) \
@@ -222,7 +222,7 @@
   do_klass(CompilationResult_Mark_klass,          com_oracle_graal_api_code_CompilationResult_Mark,             Opt) \
   do_klass(CompilationResult_Infopoint_klass,     com_oracle_graal_api_code_CompilationResult_Infopoint,        Opt) \
   do_klass(CompilationResult_Site_klass,          com_oracle_graal_api_code_CompilationResult_Site,             Opt) \
-  do_klass(ExternalCompilationResult_klass,       com_oracle_graal_api_code_ExternalCompilationResult,          Opt) \
+  do_klass(ExternalCompilationResult_klass,       com_oracle_graal_gpu_ExternalCompilationResult,               Opt) \
   do_klass(InfopointReason_klass,                 com_oracle_graal_api_code_InfopointReason,                    Opt) \
   do_klass(code_Register_klass,                   com_oracle_graal_api_code_Register,                           Opt) \
   do_klass(RegisterValue_klass,                   com_oracle_graal_api_code_RegisterValue,                      Opt) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -288,10 +288,11 @@
   NOT_LP64(  do_alias(intptr_signature,               int_signature)  )                           \
   LP64_ONLY( do_alias(intptr_signature,               long_signature) )                           \
   template(selectAlternative_signature, "(ZLjava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;") \
-                                                                                                                                       \
-  /* Support for Graal */                                                                                                              \
-  template(java_util_BitSet,	                                       "java/util/BitSet")                                               \
-  /* graal.hotspot */                                                                                                                  \
+                                                                                                                                      \
+  /* Support for Graal */                                                                                                             \
+  template(com_oracle_graal_compiler_CompilerThread,                 "com/oracle/graal/compiler/CompilerThread")                      \
+  template(java_util_BitSet,	                                       "java/util/BitSet")                                              \
+  /* graal.hotspot */                                                                                                                 \
   template(com_oracle_graal_hotspot_HotSpotGraalRuntime,             "com/oracle/graal/hotspot/HotSpotGraalRuntime")                  \
   template(com_oracle_graal_hotspot_HotSpotKlassOop,                 "com/oracle/graal/hotspot/HotSpotKlassOop")                      \
   template(com_oracle_graal_hotspot_HotSpotOptions,                  "com/oracle/graal/hotspot/HotSpotOptions")                       \
@@ -314,7 +315,6 @@
   template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod,  "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod")       \
   template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,  "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType")       \
   template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue,        "com/oracle/graal/hotspot/meta/HotSpotMonitorValue")             \
-  template(com_oracle_graal_hotspot_CompilerThread,                  "com/oracle/graal/hotspot/CompilerThread")                       \
   /* graal.api.meta */                                                                                                                \
   template(com_oracle_graal_api_meta_Constant,                       "com/oracle/graal/api/meta/Constant")                            \
   template(com_oracle_graal_api_meta_ConstantPool,                   "com/oracle/graal/api/meta/ConstantPool")                        \
@@ -338,7 +338,6 @@
   template(com_oracle_graal_api_code_CompilationResult_Mark,         "com/oracle/graal/api/code/CompilationResult$Mark")              \
   template(com_oracle_graal_api_code_CompilationResult_Infopoint,    "com/oracle/graal/api/code/CompilationResult$Infopoint")         \
   template(com_oracle_graal_api_code_CompilationResult_Site,         "com/oracle/graal/api/code/CompilationResult$Site")              \
-  template(com_oracle_graal_api_code_ExternalCompilationResult,      "com/oracle/graal/api/code/ExternalCompilationResult")           \
   template(com_oracle_graal_api_code_InfopointReason,                "com/oracle/graal/api/code/InfopointReason")                     \
   template(com_oracle_graal_api_code_BytecodeFrame,                  "com/oracle/graal/api/code/BytecodeFrame")                       \
   template(com_oracle_graal_api_code_BytecodePosition,               "com/oracle/graal/api/code/BytecodePosition")                    \
@@ -350,6 +349,8 @@
   template(com_oracle_graal_api_code_RegisterSaveLayout,             "com/oracle/graal/api/code/RegisterSaveLayout")                  \
   template(com_oracle_graal_api_code_InvalidInstalledCodeException,  "com/oracle/graal/api/code/InvalidInstalledCodeException")       \
   template(com_oracle_graal_api_code_SpeculationLog,                 "com/oracle/graal/api/code/SpeculationLog")                      \
+  /* graal.gpu */                                                                                                                     \
+  template(com_oracle_graal_gpu_ExternalCompilationResult,           "com/oracle/graal/gpu/ExternalCompilationResult")                \
   /* graal.truffle */                                                                                                                 \
   template(com_oracle_graal_truffle_GraalTruffleRuntime,             "com/oracle/graal/truffle/GraalTruffleRuntime")                  \
   template(startCompiler_name,                    "startCompiler")                                                                    \
--- a/src/share/vm/code/nmethod.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/code/nmethod.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -105,7 +105,6 @@
 //   PrintC1Statistics, PrintOptoStatistics, LogVMOutput, and LogCompilation.
 // (In the latter two cases, they like other stats are printed to the log only.)
 
-#ifndef PRODUCT
 // These variables are put into one block to reduce relocations
 // and make it simpler to print from the debugger.
 struct java_nmethod_stats_struct {
@@ -233,7 +232,6 @@
     unknown_java_nmethod_stats.note_nmethod(nm);
   }
 }
-#endif
 
 //---------------------------------------------------------------------------------
 
@@ -536,7 +534,7 @@
                                             code_buffer, frame_size,
                                             basic_lock_owner_sp_offset,
                                             basic_lock_sp_offset, oop_maps);
-    NOT_PRODUCT(if (nm != NULL)  note_java_nmethod(nm));
+    if (nm != NULL)  note_java_nmethod(nm);
     if (PrintAssembly && nm != NULL) {
       Disassembler::decode(nm);
     }
@@ -572,7 +570,7 @@
     nm = new (nmethod_size) nmethod(method(), nmethod_size,
                                     &offsets, code_buffer, frame_size);
 
-    NOT_PRODUCT(if (nm != NULL)  note_java_nmethod(nm));
+    if (nm != NULL)  note_java_nmethod(nm);
     if (PrintAssembly && nm != NULL) {
       Disassembler::decode(nm);
     }
@@ -652,7 +650,7 @@
         // record this nmethod as dependent on this klass
         InstanceKlass::cast(klass)->add_dependent_nmethod(nm);
       }
-      NOT_PRODUCT(if (nm != NULL)  note_java_nmethod(nm));
+      if (nm != NULL)  note_java_nmethod(nm);
       if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) {
         Disassembler::decode(nm);
       }
@@ -3058,6 +3056,7 @@
 void nmethod::print_nul_chk_table() {
   ImplicitExceptionTable(this).print(code_begin());
 }
+#endif // PRODUCT
 
 void nmethod::print_statistics() {
   ttyLocker ttyl;
@@ -3078,4 +3077,3 @@
   Dependencies::print_statistics();
   if (xtty != NULL)  xtty->tail("statistics");
 }
-#endif // PRODUCT
--- a/src/share/vm/code/nmethod.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/code/nmethod.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -694,7 +694,7 @@
 
   // Prints a comment for one native instruction (reloc info, pc desc)
   void print_code_comment_on(outputStream* st, int column, address begin, address end);
-  static void print_statistics()                  PRODUCT_RETURN;
+  static void print_statistics();
 
   // Compiler task identification.  Note that all OSR methods
   // are numbered in an independent sequence if CICountOSR is true,
--- a/src/share/vm/compiler/disassembler.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/compiler/disassembler.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -159,397 +159,397 @@
   nmethod*      _nm;
   CodeBlob*     _code;
   CodeStrings   _strings;
-  outputStream* _output;
-  address       _start, _end;
-
-  char          _option_buf[512];
-  char          _print_raw;
-  bool          _print_pc;
-  bool          _print_bytes;
-  address       _cur_insn;
-  int           _total_ticks;
-  int           _bytes_per_line; // arch-specific formatting option
-
-  static bool match(const char* event, const char* tag) {
-    size_t taglen = strlen(tag);
-    if (strncmp(event, tag, taglen) != 0)
-      return false;
-    char delim = event[taglen];
-    return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
-  }
-
-  void collect_options(const char* p) {
-    if (p == NULL || p[0] == '\0')  return;
-    size_t opt_so_far = strlen(_option_buf);
-    if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf))  return;
-    char* fillp = &_option_buf[opt_so_far];
-    if (opt_so_far > 0) *fillp++ = ',';
-    strcat(fillp, p);
-    // replace white space by commas:
-    char* q = fillp;
-    while ((q = strpbrk(q, " \t\n")) != NULL)
-      *q++ = ',';
-    // Note that multiple PrintAssemblyOptions flags accumulate with \n,
-    // which we want to be changed to a comma...
-  }
-
-  void print_insn_labels();
-  void print_insn_bytes(address pc0, address pc);
-  void print_address(address value);
-
- public:
+  outputStream* _output;
+  address       _start, _end;
+
+  char          _option_buf[512];
+  char          _print_raw;
+  bool          _print_pc;
+  bool          _print_bytes;
+  address       _cur_insn;
+  int           _total_ticks;
+  int           _bytes_per_line; // arch-specific formatting option
+
+  static bool match(const char* event, const char* tag) {
+    size_t taglen = strlen(tag);
+    if (strncmp(event, tag, taglen) != 0)
+      return false;
+    char delim = event[taglen];
+    return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
+  }
+
+  void collect_options(const char* p) {
+    if (p == NULL || p[0] == '\0')  return;
+    size_t opt_so_far = strlen(_option_buf);
+    if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf))  return;
+    char* fillp = &_option_buf[opt_so_far];
+    if (opt_so_far > 0) *fillp++ = ',';
+    strcat(fillp, p);
+    // replace white space by commas:
+    char* q = fillp;
+    while ((q = strpbrk(q, " \t\n")) != NULL)
+      *q++ = ',';
+    // Note that multiple PrintAssemblyOptions flags accumulate with \n,
+    // which we want to be changed to a comma...
+  }
+
+  void print_insn_labels();
+  void print_insn_bytes(address pc0, address pc);
+  void print_address(address value);
+
+ public:
   decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings());
-
-  address decode_instructions(address start, address end);
-
-  void start_insn(address pc) {
-    _cur_insn = pc;
-    output()->bol();
-    print_insn_labels();
-  }
-
-  void end_insn(address pc) {
-    address pc0 = cur_insn();
-    outputStream* st = output();
-    if (_print_bytes && pc > pc0)
-      print_insn_bytes(pc0, pc);
-    if (_nm != NULL) {
-      _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
-      // this calls reloc_string_for which calls oop::print_value_on
-    }
-
-    // Output pc bucket ticks if we have any
-    if (total_ticks() != 0) {
-      address bucket_pc = FlatProfiler::bucket_start_for(pc);
-      if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
-        int bucket_count = FlatProfiler::bucket_count_for(pc0);
-        if (bucket_count != 0) {
-          st->bol();
-          st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
-        }
-      }
-    }
-    // follow each complete insn by a nice newline
-    st->cr();
-  }
-
-  address handle_event(const char* event, address arg);
-
-  outputStream* output() { return _output; }
-  address cur_insn() { return _cur_insn; }
-  int total_ticks() { return _total_ticks; }
-  void set_total_ticks(int n) { _total_ticks = n; }
-  const char* options() { return _option_buf; }
-};
-
+
+  address decode_instructions(address start, address end);
+
+  void start_insn(address pc) {
+    _cur_insn = pc;
+    output()->bol();
+    print_insn_labels();
+  }
+
+  void end_insn(address pc) {
+    address pc0 = cur_insn();
+    outputStream* st = output();
+    if (_print_bytes && pc > pc0)
+      print_insn_bytes(pc0, pc);
+    if (_nm != NULL) {
+      _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
+      // this calls reloc_string_for which calls oop::print_value_on
+    }
+
+    // Output pc bucket ticks if we have any
+    if (total_ticks() != 0) {
+      address bucket_pc = FlatProfiler::bucket_start_for(pc);
+      if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
+        int bucket_count = FlatProfiler::bucket_count_for(pc0);
+        if (bucket_count != 0) {
+          st->bol();
+          st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
+        }
+      }
+    }
+    // follow each complete insn by a nice newline
+    st->cr();
+  }
+
+  address handle_event(const char* event, address arg);
+
+  outputStream* output() { return _output; }
+  address cur_insn() { return _cur_insn; }
+  int total_ticks() { return _total_ticks; }
+  void set_total_ticks(int n) { _total_ticks = n; }
+  const char* options() { return _option_buf; }
+};
+
 decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) {
-  memset(this, 0, sizeof(*this));
-  _output = output ? output : tty;
-  _code = code;
-  if (code != NULL && code->is_nmethod())
-    _nm = (nmethod*) code;
+  memset(this, 0, sizeof(*this));
+  _output = output ? output : tty;
+  _code = code;
+  if (code != NULL && code->is_nmethod())
+    _nm = (nmethod*) code;
   _strings.assign(c);
-
-  // by default, output pc but not bytes:
-  _print_pc       = true;
-  _print_bytes    = false;
-  _bytes_per_line = Disassembler::pd_instruction_alignment();
-
-  // parse the global option string:
-  collect_options(Disassembler::pd_cpu_opts());
-  collect_options(PrintAssemblyOptions);
-
-  if (strstr(options(), "hsdis-")) {
-    if (strstr(options(), "hsdis-print-raw"))
-      _print_raw = (strstr(options(), "xml") ? 2 : 1);
-    if (strstr(options(), "hsdis-print-pc"))
-      _print_pc = !_print_pc;
-    if (strstr(options(), "hsdis-print-bytes"))
-      _print_bytes = !_print_bytes;
-  }
-  if (strstr(options(), "help")) {
-    tty->print_cr("PrintAssemblyOptions help:");
-    tty->print_cr("  hsdis-print-raw       test plugin by requesting raw output");
-    tty->print_cr("  hsdis-print-raw-xml   test plugin by requesting raw xml");
-    tty->print_cr("  hsdis-print-pc        turn off PC printing (on by default)");
-    tty->print_cr("  hsdis-print-bytes     turn on instruction byte output");
-    tty->print_cr("combined options: %s", options());
-  }
-}
-
-address decode_env::handle_event(const char* event, address arg) {
-  if (match(event, "insn")) {
-    start_insn(arg);
-  } else if (match(event, "/insn")) {
-    end_insn(arg);
-  } else if (match(event, "addr")) {
-    if (arg != NULL) {
-      print_address(arg);
-      return arg;
-    }
-  } else if (match(event, "mach")) {
-    static char buffer[32] = { 0, };
-    if (strcmp(buffer, (const char*)arg) != 0 ||
-        strlen((const char*)arg) > sizeof(buffer) - 1) {
-      // Only print this when the mach changes
-      strncpy(buffer, (const char*)arg, sizeof(buffer) - 1);
-      output()->print_cr("[Disassembling for mach='%s']", arg);
-    }
-  } else if (match(event, "format bytes-per-line")) {
-    _bytes_per_line = (int) (intptr_t) arg;
-  } else {
-    // ignore unrecognized markup
-  }
-  return NULL;
-}
-
-// called by the disassembler to print out jump targets and data addresses
-void decode_env::print_address(address adr) {
-  outputStream* st = _output;
-
-  if (adr == NULL) {
-    st->print("NULL");
-    return;
-  }
-
-  int small_num = (int)(intptr_t)adr;
-  if ((intptr_t)adr == (intptr_t)small_num
-      && -1 <= small_num && small_num <= 9) {
-    st->print("%d", small_num);
-    return;
-  }
-
-  if (Universe::is_fully_initialized()) {
-    if (StubRoutines::contains(adr)) {
-      StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
-      if (desc == NULL)
-        desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
-      if (desc != NULL) {
-        st->print("Stub::%s", desc->name());
-        if (desc->begin() != adr)
-          st->print("%+d 0x%p",adr - desc->begin(), adr);
-        else if (WizardMode) st->print(" " PTR_FORMAT, adr);
-        return;
-      }
-      st->print("Stub::<unknown> " PTR_FORMAT, adr);
-      return;
-    }
-
-    BarrierSet* bs = Universe::heap()->barrier_set();
-    if (bs->kind() == BarrierSet::CardTableModRef &&
-        adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
-      st->print("word_map_base");
-      if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
-      return;
-    }
-
-    oop obj;
-    if (_nm != NULL
-        && (obj = _nm->embeddedOop_at(cur_insn())) != NULL
-        && (address) obj == adr
-        && Universe::heap()->is_in(obj)
-        && Universe::heap()->is_in(obj->klass())) {
-      julong c = st->count();
-      obj->print_value_on(st);
-      if (st->count() == c) {
-        // No output.  (Can happen in product builds.)
-        st->print("(a %s)", obj->klass()->external_name());
-      }
-      return;
-    }
-  }
-
-  // Fall through to a simple (hexadecimal) numeral.
-  st->print(PTR_FORMAT, adr);
-}
-
-void decode_env::print_insn_labels() {
-  address p = cur_insn();
-  outputStream* st = output();
-  CodeBlob* cb = _code;
-  if (cb != NULL) {
-    cb->print_block_comment(st, p);
-  }
+
+  // by default, output pc but not bytes:
+  _print_pc       = true;
+  _print_bytes    = false;
+  _bytes_per_line = Disassembler::pd_instruction_alignment();
+
+  // parse the global option string:
+  collect_options(Disassembler::pd_cpu_opts());
+  collect_options(PrintAssemblyOptions);
+
+  if (strstr(options(), "hsdis-")) {
+    if (strstr(options(), "hsdis-print-raw"))
+      _print_raw = (strstr(options(), "xml") ? 2 : 1);
+    if (strstr(options(), "hsdis-print-pc"))
+      _print_pc = !_print_pc;
+    if (strstr(options(), "hsdis-print-bytes"))
+      _print_bytes = !_print_bytes;
+  }
+  if (strstr(options(), "help")) {
+    tty->print_cr("PrintAssemblyOptions help:");
+    tty->print_cr("  hsdis-print-raw       test plugin by requesting raw output");
+    tty->print_cr("  hsdis-print-raw-xml   test plugin by requesting raw xml");
+    tty->print_cr("  hsdis-print-pc        turn off PC printing (on by default)");
+    tty->print_cr("  hsdis-print-bytes     turn on instruction byte output");
+    tty->print_cr("combined options: %s", options());
+  }
+}
+
+address decode_env::handle_event(const char* event, address arg) {
+  if (match(event, "insn")) {
+    start_insn(arg);
+  } else if (match(event, "/insn")) {
+    end_insn(arg);
+  } else if (match(event, "addr")) {
+    if (arg != NULL) {
+      print_address(arg);
+      return arg;
+    }
+  } else if (match(event, "mach")) {
+    static char buffer[32] = { 0, };
+    if (strcmp(buffer, (const char*)arg) != 0 ||
+        strlen((const char*)arg) > sizeof(buffer) - 1) {
+      // Only print this when the mach changes
+      strncpy(buffer, (const char*)arg, sizeof(buffer) - 1);
+      output()->print_cr("[Disassembling for mach='%s']", arg);
+    }
+  } else if (match(event, "format bytes-per-line")) {
+    _bytes_per_line = (int) (intptr_t) arg;
+  } else {
+    // ignore unrecognized markup
+  }
+  return NULL;
+}
+
+// called by the disassembler to print out jump targets and data addresses
+void decode_env::print_address(address adr) {
+  outputStream* st = _output;
+
+  if (adr == NULL) {
+    st->print("NULL");
+    return;
+  }
+
+  int small_num = (int)(intptr_t)adr;
+  if ((intptr_t)adr == (intptr_t)small_num
+      && -1 <= small_num && small_num <= 9) {
+    st->print("%d", small_num);
+    return;
+  }
+
+  if (Universe::is_fully_initialized()) {
+    if (StubRoutines::contains(adr)) {
+      StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
+      if (desc == NULL)
+        desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
+      if (desc != NULL) {
+        st->print("Stub::%s", desc->name());
+        if (desc->begin() != adr)
+          st->print("%+d 0x%p",adr - desc->begin(), adr);
+        else if (WizardMode) st->print(" " PTR_FORMAT, adr);
+        return;
+      }
+      st->print("Stub::<unknown> " PTR_FORMAT, adr);
+      return;
+    }
+
+    BarrierSet* bs = Universe::heap()->barrier_set();
+    if (bs->kind() == BarrierSet::CardTableModRef &&
+        adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
+      st->print("word_map_base");
+      if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
+      return;
+    }
+
+    oop obj;
+    if (_nm != NULL
+        && (obj = _nm->embeddedOop_at(cur_insn())) != NULL
+        && (address) obj == adr
+        && Universe::heap()->is_in(obj)
+        && Universe::heap()->is_in(obj->klass())) {
+      julong c = st->count();
+      obj->print_value_on(st);
+      if (st->count() == c) {
+        // No output.  (Can happen in product builds.)
+        st->print("(a %s)", obj->klass()->external_name());
+      }
+      return;
+    }
+  }
+
+  // Fall through to a simple (hexadecimal) numeral.
+  st->print(PTR_FORMAT, adr);
+}
+
+void decode_env::print_insn_labels() {
+  address p = cur_insn();
+  outputStream* st = output();
+  CodeBlob* cb = _code;
+  if (cb != NULL) {
+    cb->print_block_comment(st, p);
+  }
   _strings.print_block_comment(st, (intptr_t)(p - _start));
-  if (_print_pc) {
-    st->print("  " PTR_FORMAT ": ", p);
-  }
-}
-
-void decode_env::print_insn_bytes(address pc, address pc_limit) {
-  outputStream* st = output();
-  size_t incr = 1;
-  size_t perline = _bytes_per_line;
-  if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
-      && !((uintptr_t)pc % sizeof(int))
-      && !((uintptr_t)pc_limit % sizeof(int))) {
-    incr = sizeof(int);
-    if (perline % incr)  perline += incr - (perline % incr);
-  }
-  while (pc < pc_limit) {
-    // tab to the desired column:
-    st->move_to(COMMENT_COLUMN);
-    address pc0 = pc;
-    address pc1 = pc + perline;
-    if (pc1 > pc_limit)  pc1 = pc_limit;
-    for (; pc < pc1; pc += incr) {
-      if (pc == pc0)
-        st->print(BYTES_COMMENT);
-      else if ((uint)(pc - pc0) % sizeof(int) == 0)
-        st->print(" ");         // put out a space on word boundaries
-      if (incr == sizeof(int))
-            st->print("%08lx", *(int*)pc);
-      else  st->print("%02x",   (*pc)&0xFF);
-    }
-    st->cr();
-  }
-}
-
-
-static void* event_to_env(void* env_pv, const char* event, void* arg) {
-  decode_env* env = (decode_env*) env_pv;
-  return env->handle_event(event, (address) arg);
-}
-
-static int printf_to_env(void* env_pv, const char* format, ...) {
-  decode_env* env = (decode_env*) env_pv;
-  outputStream* st = env->output();
-  size_t flen = strlen(format);
-  const char* raw = NULL;
-  if (flen == 0)  return 0;
-  if (flen == 1 && format[0] == '\n') { st->bol(); return 1; }
-  if (flen < 2 ||
-      strchr(format, '%') == NULL) {
-    raw = format;
-  } else if (format[0] == '%' && format[1] == '%' &&
-             strchr(format+2, '%') == NULL) {
-    // happens a lot on machines with names like %foo
-    flen--;
-    raw = format+1;
-  }
-  if (raw != NULL) {
-    st->print_raw(raw, (int) flen);
-    return (int) flen;
-  }
-  va_list ap;
-  va_start(ap, format);
-  julong cnt0 = st->count();
-  st->vprint(format, ap);
-  julong cnt1 = st->count();
-  va_end(ap);
-  return (int)(cnt1 - cnt0);
-}
-
-address decode_env::decode_instructions(address start, address end) {
-  _start = start; _end = end;
-
-  assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr");
-
-  const int show_bytes = false; // for disassembler debugging
-
-  //_version = Disassembler::pd_cpu_version();
-
-  if (!Disassembler::can_decode()) {
-    return NULL;
-  }
-
-  // decode a series of instructions and return the end of the last instruction
-
-  if (_print_raw) {
-    // Print whatever the library wants to print, w/o fancy callbacks.
-    // This is mainly for debugging the library itself.
-    FILE* out = stdout;
-    FILE* xmlout = (_print_raw > 1 ? out : NULL);
-    return use_new_version ?
-      (address)
-      (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end,
-                                                    start, end - start,
-                                                    NULL, (void*) xmlout,
-                                                    NULL, (void*) out,
-                                                    options(), 0/*nice new line*/)
-      :
-      (address)
-      (*Disassembler::_decode_instructions)(start, end,
-                                            NULL, (void*) xmlout,
-                                            NULL, (void*) out,
-                                            options());
-  }
-
-  return use_new_version ?
-    (address)
-    (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end,
-                                                  start, end - start,
-                                                  &event_to_env,  (void*) this,
-                                                  &printf_to_env, (void*) this,
-                                                  options(), 0/*nice new line*/)
-    :
-    (address)
-    (*Disassembler::_decode_instructions)(start, end,
-                                          &event_to_env,  (void*) this,
-                                          &printf_to_env, (void*) this,
-                                          options());
-}
-
-
-void Disassembler::decode(CodeBlob* cb, outputStream* st) {
-  if (!load_library())  return;
-  decode_env env(cb, st);
-  env.output()->print_cr("----------------------------------------------------------------------");
-  env.output()->print_cr("%s at  [" PTR_FORMAT ", " PTR_FORMAT "]  %d bytes", cb->name(), cb->code_begin(), cb->code_end(), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*));
-  env.decode_instructions(cb->code_begin(), cb->code_end());
-}
-
-void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) {
-  if (!load_library())  return;
-  decode_env env(CodeCache::find_blob_unsafe(start), st, c);
-  env.decode_instructions(start, end);
-}
-
-void Disassembler::decode(nmethod* nm, outputStream* st) {
-  if (!load_library())  return;
-  decode_env env(nm, st);
-  env.output()->print_cr("----------------------------------------------------------------------");
-
-#ifdef SHARK
-  SharkEntry* entry = (SharkEntry *) nm->code_begin();
-  unsigned char* p   = entry->code_start();
-  unsigned char* end = entry->code_limit();
-#else
-  unsigned char* p   = nm->code_begin();
-  unsigned char* end = nm->code_end();
-#endif // SHARK
-
-  nm->method()->method_holder()->name()->print_symbol_on(env.output());
-  env.output()->print(".");
-  nm->method()->name()->print_symbol_on(env.output());
-  env.output()->print_cr("  [" PTR_FORMAT ", " PTR_FORMAT "]  %d bytes", p, end, ((jlong)(end - p)) * sizeof(unsigned char*));
-
-  // If there has been profiling, print the buckets.
-  if (FlatProfiler::bucket_start_for(p) != NULL) {
-    unsigned char* p1 = p;
-    int total_bucket_count = 0;
-    while (p1 < end) {
-      unsigned char* p0 = p1;
-      p1 += pd_instruction_alignment();
-      address bucket_pc = FlatProfiler::bucket_start_for(p1);
-      if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
-        total_bucket_count += FlatProfiler::bucket_count_for(p0);
-    }
-    env.set_total_ticks(total_bucket_count);
-  }
-
-  // Print constant table.
-  if (nm->consts_size() > 0) {
-    nm->print_nmethod_labels(env.output(), nm->consts_begin());
-    int offset = 0;
-    for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
-      if ((offset % 8) == 0) {
-        env.output()->print_cr("  " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT "   " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p));
-      } else {
-        env.output()->print_cr("  " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT,                    p, offset, *((int32_t*) p));
-      }
-    }
-  }
-
-  env.decode_instructions(p, end);
-}
+  if (_print_pc) {
+    st->print("  " PTR_FORMAT ": ", p);
+  }
+}
+
+void decode_env::print_insn_bytes(address pc, address pc_limit) {
+  outputStream* st = output();
+  size_t incr = 1;
+  size_t perline = _bytes_per_line;
+  if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
+      && !((uintptr_t)pc % sizeof(int))
+      && !((uintptr_t)pc_limit % sizeof(int))) {
+    incr = sizeof(int);
+    if (perline % incr)  perline += incr - (perline % incr);
+  }
+  while (pc < pc_limit) {
+    // tab to the desired column:
+    st->move_to(COMMENT_COLUMN);
+    address pc0 = pc;
+    address pc1 = pc + perline;
+    if (pc1 > pc_limit)  pc1 = pc_limit;
+    for (; pc < pc1; pc += incr) {
+      if (pc == pc0)
+        st->print(BYTES_COMMENT);
+      else if ((uint)(pc - pc0) % sizeof(int) == 0)
+        st->print(" ");         // put out a space on word boundaries
+      if (incr == sizeof(int))
+            st->print("%08lx", *(int*)pc);
+      else  st->print("%02x",   (*pc)&0xFF);
+    }
+    st->cr();
+  }
+}
+
+
+static void* event_to_env(void* env_pv, const char* event, void* arg) {
+  decode_env* env = (decode_env*) env_pv;
+  return env->handle_event(event, (address) arg);
+}
+
+static int printf_to_env(void* env_pv, const char* format, ...) {
+  decode_env* env = (decode_env*) env_pv;
+  outputStream* st = env->output();
+  size_t flen = strlen(format);
+  const char* raw = NULL;
+  if (flen == 0)  return 0;
+  if (flen == 1 && format[0] == '\n') { st->bol(); return 1; }
+  if (flen < 2 ||
+      strchr(format, '%') == NULL) {
+    raw = format;
+  } else if (format[0] == '%' && format[1] == '%' &&
+             strchr(format+2, '%') == NULL) {
+    // happens a lot on machines with names like %foo
+    flen--;
+    raw = format+1;
+  }
+  if (raw != NULL) {
+    st->print_raw(raw, (int) flen);
+    return (int) flen;
+  }
+  va_list ap;
+  va_start(ap, format);
+  julong cnt0 = st->count();
+  st->vprint(format, ap);
+  julong cnt1 = st->count();
+  va_end(ap);
+  return (int)(cnt1 - cnt0);
+}
+
+address decode_env::decode_instructions(address start, address end) {
+  _start = start; _end = end;
+
+  assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr");
+
+  const int show_bytes = false; // for disassembler debugging
+
+  //_version = Disassembler::pd_cpu_version();
+
+  if (!Disassembler::can_decode()) {
+    return NULL;
+  }
+
+  // decode a series of instructions and return the end of the last instruction
+
+  if (_print_raw) {
+    // Print whatever the library wants to print, w/o fancy callbacks.
+    // This is mainly for debugging the library itself.
+    FILE* out = stdout;
+    FILE* xmlout = (_print_raw > 1 ? out : NULL);
+    return use_new_version ?
+      (address)
+      (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end,
+                                                    start, end - start,
+                                                    NULL, (void*) xmlout,
+                                                    NULL, (void*) out,
+                                                    options(), 0/*nice new line*/)
+      :
+      (address)
+      (*Disassembler::_decode_instructions)(start, end,
+                                            NULL, (void*) xmlout,
+                                            NULL, (void*) out,
+                                            options());
+  }
+
+  return use_new_version ?
+    (address)
+    (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end,
+                                                  start, end - start,
+                                                  &event_to_env,  (void*) this,
+                                                  &printf_to_env, (void*) this,
+                                                  options(), 0/*nice new line*/)
+    :
+    (address)
+    (*Disassembler::_decode_instructions)(start, end,
+                                          &event_to_env,  (void*) this,
+                                          &printf_to_env, (void*) this,
+                                          options());
+}
+
+
+void Disassembler::decode(CodeBlob* cb, outputStream* st) {
+  if (!load_library())  return;
+  decode_env env(cb, st);
+  env.output()->print_cr("----------------------------------------------------------------------");
+  env.output()->print_cr("%s at  [" PTR_FORMAT ", " PTR_FORMAT "]  %d bytes", cb->name(), cb->code_begin(), cb->code_end(), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*));
+  env.decode_instructions(cb->code_begin(), cb->code_end());
+}
+
+void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) {
+  if (!load_library())  return;
+  decode_env env(CodeCache::find_blob_unsafe(start), st, c);
+  env.decode_instructions(start, end);
+}
+
+void Disassembler::decode(nmethod* nm, outputStream* st) {
+  if (!load_library())  return;
+  decode_env env(nm, st);
+  env.output()->print_cr("----------------------------------------------------------------------");
+
+#ifdef SHARK
+  SharkEntry* entry = (SharkEntry *) nm->code_begin();
+  unsigned char* p   = entry->code_start();
+  unsigned char* end = entry->code_limit();
+#else
+  unsigned char* p   = nm->code_begin();
+  unsigned char* end = nm->code_end();
+#endif // SHARK
+
+  nm->method()->method_holder()->name()->print_symbol_on(env.output());
+  env.output()->print(".");
+  nm->method()->name()->print_symbol_on(env.output());
+  env.output()->print_cr("  [" PTR_FORMAT ", " PTR_FORMAT "]  %d bytes", p, end, ((jlong)(end - p)) * sizeof(unsigned char*));
+
+  // If there has been profiling, print the buckets.
+  if (FlatProfiler::bucket_start_for(p) != NULL) {
+    unsigned char* p1 = p;
+    int total_bucket_count = 0;
+    while (p1 < end) {
+      unsigned char* p0 = p1;
+      p1 += pd_instruction_alignment();
+      address bucket_pc = FlatProfiler::bucket_start_for(p1);
+      if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
+        total_bucket_count += FlatProfiler::bucket_count_for(p0);
+    }
+    env.set_total_ticks(total_bucket_count);
+  }
+
+  // Print constant table.
+  if (nm->consts_size() > 0) {
+    nm->print_nmethod_labels(env.output(), nm->consts_begin());
+    int offset = 0;
+    for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
+      if ((offset % 8) == 0) {
+        env.output()->print_cr("  " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT "   " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p));
+      } else {
+        env.output()->print_cr("  " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT,                    p, offset, *((int32_t*) p));
+      }
+    }
+  }
+
+  env.decode_instructions(p, end);
+}
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -513,6 +513,8 @@
       address dest = _constants->start() + CompilationResult_Site::pcOffset(patch);
       assert(!OopData::compressed(data), err_msg("unexpected compressed oop in data section"));
       _constants->relocate(dest, oop_Relocation::spec(oop_index));
+    } else {
+      ShouldNotReachHere();
     }
   }
 
--- a/src/share/vm/graal/graalCompiler.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -32,6 +32,7 @@
 #include "graal/graalRuntime.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/compilationPolicy.hpp"
+#include "runtime/globals_extension.hpp"
 
 GraalCompiler* GraalCompiler::_instance = NULL;
 
@@ -97,7 +98,12 @@
     VMToCompiler::finalizeOptions(CITime || CITimeEach);
 
     if (UseCompiler) {
-      bool bootstrap = COMPILERGRAAL_PRESENT(BootstrapGraal) NOT_COMPILERGRAAL(false);
+      _external_deopt_i2c_entry = create_external_deopt_i2c();
+#ifdef COMPILERGRAAL
+      bool bootstrap = FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal;
+#else
+      bool bootstrap = false;
+#endif
       VMToCompiler::startCompiler(bootstrap);
       _initialized = true;
       CompilationPolicy::completed_vm_startup();
@@ -126,6 +132,34 @@
   }
 }
 
+address GraalCompiler::create_external_deopt_i2c() {
+  ResourceMark rm;
+  BufferBlob* buffer = BufferBlob::create("externalDeopt", 1*K);
+  CodeBuffer cb(buffer);
+  short buffer_locs[20];
+  cb.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo));
+  MacroAssembler masm(&cb);
+
+  int total_args_passed = 5;
+
+  BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
+  VMRegPair* regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
+  int i = 0;
+  sig_bt[i++] = T_INT;
+  sig_bt[i++] = T_LONG;
+  sig_bt[i++] = T_VOID; // long stakes 2 slots
+  sig_bt[i++] = T_INT;
+  sig_bt[i++] = T_OBJECT;
+
+  int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
+
+  SharedRuntime::gen_i2c_adapter(&masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
+  masm.flush();
+
+  return AdapterBlob::create(&cb)->content_begin();
+}
+
+
 BufferBlob* GraalCompiler::initialize_buffer_blob() {
   JavaThread* THREAD = JavaThread::current();
   BufferBlob* buffer_blob = THREAD->get_buffer_blob();
--- a/src/share/vm/graal/graalCompiler.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/graal/graalCompiler.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -35,7 +35,7 @@
   bool                  _initialized;
 
   static GraalCompiler* _instance;
-
+  address               _external_deopt_i2c_entry;
 public:
 
   GraalCompiler();
@@ -67,9 +67,13 @@
 
   void exit();
 
+  address get_external_deopt_i2c_entry() {return _external_deopt_i2c_entry;}
+
   static BasicType kindToBasicType(jchar ch);
 
   static BufferBlob* initialize_buffer_blob();
+
+  static address create_external_deopt_i2c();
 };
 
 // Tracing macros
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -329,13 +329,9 @@
   return (jlong) (address) klass->implementor();
 C2V_END
 
-C2V_VMENTRY(void, initializeMethod,(JNIEnv *, jobject, jlong metaspace_method, jobject hotspot_method))
+C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, jlong metaspace_method))
   methodHandle method = asMethod(metaspace_method);
-  InstanceKlass::cast(HotSpotResolvedJavaMethod::klass())->initialize(CHECK);
-  HotSpotResolvedJavaMethod::set_callerSensitive(hotspot_method, method->caller_sensitive());
-  HotSpotResolvedJavaMethod::set_forceInline(hotspot_method, method->force_inline());
-  HotSpotResolvedJavaMethod::set_dontInline(hotspot_method, method->dont_inline());
-  HotSpotResolvedJavaMethod::set_ignoredBySecurityStackWalk(hotspot_method, method->is_ignored_by_security_stack_walk());
+  return method->is_ignored_by_security_stack_walk();
 C2V_END
 
 C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jlong metaspace_method))
@@ -805,7 +801,7 @@
   {CC"findUniqueConcreteMethod",                     CC"("METASPACE_METHOD")"METASPACE_METHOD,                         FN_PTR(findUniqueConcreteMethod)},
   {CC"getKlassImplementor",                          CC"("METASPACE_KLASS")"METASPACE_KLASS,                           FN_PTR(getKlassImplementor)},
   {CC"getStackTraceElement",                         CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT,                     FN_PTR(getStackTraceElement)},
-  {CC"initializeMethod",                             CC"("METASPACE_METHOD HS_RESOLVED_METHOD")V",                     FN_PTR(initializeMethod)},
+  {CC"methodIsIgnoredBySecurityStackWalk",           CC"("METASPACE_METHOD")Z",                                        FN_PTR(methodIsIgnoredBySecurityStackWalk)},
   {CC"doNotInlineOrCompile",                         CC"("METASPACE_METHOD")V",                                        FN_PTR(doNotInlineOrCompile)},
   {CC"canInlineMethod",                              CC"("METASPACE_METHOD")Z",                                        FN_PTR(canInlineMethod)},
   {CC"shouldInlineMethod",                           CC"("METASPACE_METHOD")Z",                                        FN_PTR(shouldInlineMethod)},
--- a/src/share/vm/graal/graalJavaAccess.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -55,10 +55,6 @@
     oop_field(HotSpotResolvedJavaMethod, name, "Ljava/lang/String;")                                                                                           \
     oop_field(HotSpotResolvedJavaMethod, holder, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;")                                                  \
     long_field(HotSpotResolvedJavaMethod, metaspaceMethod)                                                                                                     \
-    boolean_field(HotSpotResolvedJavaMethod, callerSensitive)                                                                                                  \
-    boolean_field(HotSpotResolvedJavaMethod, forceInline)                                                                                                      \
-    boolean_field(HotSpotResolvedJavaMethod, dontInline)                                                                                                       \
-    boolean_field(HotSpotResolvedJavaMethod, ignoredBySecurityStackWalk)                                                                                       \
   end_class                                                                                                                                                    \
   start_class(HotSpotJavaType)                                                                                                                                 \
     oop_field(HotSpotJavaType, name, "Ljava/lang/String;")                                                                                                     \
--- a/src/share/vm/graal/graalRuntime.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/graal/graalRuntime.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -438,13 +438,12 @@
   return (jint)ret;
 JRT_END
 
-JRT_ENTRY(void, GraalRuntime::vm_error(JavaThread* thread, oopDesc* where, oopDesc* format, jlong value))
+JRT_ENTRY(void, GraalRuntime::vm_error(JavaThread* thread, jlong where, jlong format, jlong value))
   ResourceMark rm;
-  assert(where == NULL || java_lang_String::is_instance(where), "must be");
-  const char *error_msg = where == NULL ? "<internal Graal error>" : java_lang_String::as_utf8_string(where);
+  const char *error_msg = where == 0L ? "<internal Graal error>" : (char*) (address) where;
   char *detail_msg = NULL;
-  if (format != NULL) {
-    const char* buf = java_lang_String::as_utf8_string(format);
+  if (format != 0L) {
+    const char* buf = (char*) (address) format;
     size_t detail_msg_length = strlen(buf) * 2;
     detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length);
     jio_snprintf(detail_msg, detail_msg_length, buf, value);
--- a/src/share/vm/graal/graalRuntime.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/graal/graalRuntime.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -43,7 +43,7 @@
   static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock);
   static void create_null_exception(JavaThread* thread);
   static void create_out_of_bounds_exception(JavaThread* thread, jint index);
-  static void vm_error(JavaThread* thread, oopDesc* where, oopDesc* format, jlong value);
+  static void vm_error(JavaThread* thread, jlong where, jlong format, jlong value);
   static oopDesc* load_and_clear_exception(JavaThread* thread);
   static void log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3);
   static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline);
--- a/src/share/vm/oops/instanceKlass.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/oops/instanceKlass.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -3411,6 +3411,10 @@
               ("purge: %s(%s): prev method @%d in version @%d is alive",
               method->name()->as_C_string(),
               method->signature()->as_C_string(), j, i));
+            if (method->method_data() != NULL) {
+              // Clean out any weak method links
+              method->method_data()->clean_weak_method_links();
+            }
           }
         }
       }
@@ -3420,6 +3424,14 @@
       ("purge: previous version stats: live=%d, deleted=%d", live_count,
       deleted_count));
   }
+
+  Array<Method*>* methods = ik->methods();
+  int num_methods = methods->length();
+  for (int index2 = 0; index2 < num_methods; ++index2) {
+    if (methods->at(index2)->method_data() != NULL) {
+      methods->at(index2)->method_data()->clean_weak_method_links();
+    }
+  }
 }
 
 // External interface for use during class unloading.
--- a/src/share/vm/oops/method.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/oops/method.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -108,12 +108,15 @@
 #endif
   u2                _method_size;                // size of this object
   u1                _intrinsic_id;               // vmSymbols::intrinsic_id (0 == _none)
-  u1                _jfr_towrite      : 1,       // Flags
-                    _caller_sensitive : 1,
-                    _force_inline     : 1,
-                    _hidden           : 1,
-                    _dont_inline      : 1,
-                                      : 3;
+  // Flags
+  enum Flags {
+    _jfr_towrite      = 1 << 0,
+    _caller_sensitive = 1 << 1,
+    _force_inline     = 1 << 2,
+    _dont_inline      = 1 << 3,
+    _hidden           = 1 << 4
+  };
+  u1 _flags;
 
 #ifndef PRODUCT
   int               _compiled_invocation_count;  // Number of nmethod invocations so far (for perf. debugging)
@@ -759,16 +762,41 @@
   void init_intrinsic_id();     // updates from _none if a match
   static vmSymbols::SID klass_id_for_intrinsics(Klass* holder);
 
-  bool     jfr_towrite()            { return _jfr_towrite;          }
-  void set_jfr_towrite(bool x)      {        _jfr_towrite = x;      }
-  bool     caller_sensitive()       { return _caller_sensitive;     }
-  void set_caller_sensitive(bool x) {        _caller_sensitive = x; }
-  bool     force_inline()           { return _force_inline;         }
-  void set_force_inline(bool x)     {        _force_inline = x;     }
-  bool     dont_inline()            { return _dont_inline;          }
-  void set_dont_inline(bool x)      {        _dont_inline = x;      }
-  bool  is_hidden()                 { return _hidden;               }
-  void set_hidden(bool x)           {        _hidden = x;           }
+  bool jfr_towrite() {
+    return (_flags & _jfr_towrite) != 0;
+  }
+  void set_jfr_towrite(bool x) {
+    _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite);
+  }
+
+  bool caller_sensitive() {
+    return (_flags & _caller_sensitive) != 0;
+  }
+  void set_caller_sensitive(bool x) {
+    _flags = x ? (_flags | _caller_sensitive) : (_flags & ~_caller_sensitive);
+  }
+
+  bool force_inline() {
+    return (_flags & _force_inline) != 0;
+  }
+  void set_force_inline(bool x) {
+    _flags = x ? (_flags | _force_inline) : (_flags & ~_force_inline);
+  }
+
+  bool dont_inline() {
+    return (_flags & _dont_inline) != 0;
+  }
+  void set_dont_inline(bool x) {
+    _flags = x ? (_flags | _dont_inline) : (_flags & ~_dont_inline);
+  }
+
+  bool is_hidden() {
+    return (_flags & _hidden) != 0;
+  }
+  void set_hidden(bool x) {
+    _flags = x ? (_flags | _hidden) : (_flags & ~_hidden);
+  }
+
   ConstMethod::MethodType method_type() const {
       return _constMethod->method_type();
   }
--- a/src/share/vm/oops/methodData.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/oops/methodData.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -426,6 +426,16 @@
     }
   }
 }
+
+void VirtualCallData::clean_weak_method_links() {
+  ReceiverTypeData::clean_weak_method_links();
+  for (uint row = 0; row < method_row_limit(); row++) {
+    Method* p = method(row);
+    if (p != NULL && !p->on_stack()) {
+      clear_method_row(row);
+    }
+  }
+}
 #endif // GRAAL
 
 #ifndef PRODUCT
@@ -1693,3 +1703,85 @@
   clean_extra_data(is_alive);
   verify_extra_data_clean(is_alive);
 }
+
+// Remove SpeculativeTrapData entries that reference a redefined
+// method
+void MethodData::clean_weak_method_extra_data() {
+  DataLayout* dp  = extra_data_base();
+  DataLayout* end = extra_data_limit();
+
+  int shift = 0;
+  for (; dp < end; dp = next_extra(dp)) {
+    switch(dp->tag()) {
+    case DataLayout::speculative_trap_data_tag: {
+      SpeculativeTrapData* data = new SpeculativeTrapData(dp);
+      Method* m = data->method();
+      assert(m != NULL, "should have a method");
+      if (!m->on_stack()) {
+        // "shift" accumulates the number of cells for dead
+        // SpeculativeTrapData entries that have been seen so
+        // far. Following entries must be shifted left by that many
+        // cells to remove the dead SpeculativeTrapData entries.
+        shift += (int)((intptr_t*)next_extra(dp) - (intptr_t*)dp);
+      } else {
+        // Shift this entry left if it follows dead
+        // SpeculativeTrapData entries
+        clean_extra_data_helper(dp, shift);
+      }
+      break;
+    }
+    case DataLayout::bit_data_tag:
+      // Shift this entry left if it follows dead SpeculativeTrapData
+      // entries
+      clean_extra_data_helper(dp, shift);
+      continue;
+    case DataLayout::no_tag:
+    case DataLayout::arg_info_data_tag:
+      // We are at end of the live trap entries. The previous "shift"
+      // cells contain entries that are either dead or were shifted
+      // left. They need to be reset to no_tag
+      clean_extra_data_helper(dp, shift, true);
+      return;
+    default:
+      fatal(err_msg("unexpected tag %d", dp->tag()));
+    }
+  }
+}
+
+// Verify there's no redefined method referenced by a
+// SpeculativeTrapData entry
+void MethodData::verify_weak_method_extra_data_clean() {
+#ifdef ASSERT
+  DataLayout* dp  = extra_data_base();
+  DataLayout* end = extra_data_limit();
+
+  for (; dp < end; dp = next_extra(dp)) {
+    switch(dp->tag()) {
+    case DataLayout::speculative_trap_data_tag: {
+      SpeculativeTrapData* data = new SpeculativeTrapData(dp);
+      Method* m = data->method();
+      assert(m != NULL && m->on_stack(), "Method should exist");
+      break;
+    }
+    case DataLayout::bit_data_tag:
+      continue;
+    case DataLayout::no_tag:
+    case DataLayout::arg_info_data_tag:
+      return;
+    default:
+      fatal(err_msg("unexpected tag %d", dp->tag()));
+    }
+  }
+#endif
+}
+
+void MethodData::clean_weak_method_links() {
+  for (ProfileData* data = first_data();
+       is_valid(data);
+       data = next_data(data)) {
+    data->clean_weak_method_links();
+  }
+
+  clean_weak_method_extra_data();
+  verify_weak_method_extra_data_clean();
+}
--- a/src/share/vm/oops/methodData.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/oops/methodData.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -257,6 +257,9 @@
 
   // GC support
   void clean_weak_klass_links(BoolObjectClosure* cl);
+
+  // Redefinition support
+  void clean_weak_method_links();
 };
 
 
@@ -514,6 +517,9 @@
   // GC support
   virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {}
 
+  // Redefinition support
+  virtual void clean_weak_method_links() {}
+
   // CI translation: ProfileData can represent both MethodDataOop data
   // as well as CIMethodData data. This function is provided for translating
   // an oop in a ProfileData to the ci equivalent. Generally speaking,
@@ -1429,6 +1435,9 @@
 
   // GC support
   virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
+
+  // Redefinition support
+  virtual void clean_weak_method_links();
 #endif
 
 #ifndef PRODUCT
@@ -2294,6 +2303,10 @@
   void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false);
   void verify_extra_data_clean(BoolObjectClosure* is_alive);
 
+  // Redefinition support
+  void clean_weak_method_extra_data();
+  void verify_weak_method_extra_data_clean();
+
 public:
   static int header_size() {
     return sizeof(MethodData)/wordSize;
@@ -2572,6 +2585,8 @@
   static bool profile_return_jsr292_only();
 
   void clean_method_data(BoolObjectClosure* is_alive);
+
+  void clean_weak_method_links();
 };
 
 #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
--- a/src/share/vm/opto/node.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/opto/node.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -476,6 +476,7 @@
 #pragma clang diagnostic pop
 #endif
 
+
 //------------------------------clone------------------------------------------
 // Clone a Node.
 Node *Node::clone() const {
--- a/src/share/vm/opto/runtime.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/opto/runtime.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -1,6 +1,5 @@
 /*
  * Copyright (c) 1998, 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
--- a/src/share/vm/runtime/globals_extension.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/globals_extension.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -86,6 +86,9 @@
 #ifdef COMPILER1
  C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_DIAGNOSTIC_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER)
 #endif
+#ifdef GRAAL
+ GRAAL_FLAGS(GRAAL_DEVELOP_FLAG_MEMBER, GRAAL_PD_DEVELOP_FLAG_MEMBER, GRAAL_PRODUCT_FLAG_MEMBER, GRAAL_PD_PRODUCT_FLAG_MEMBER, GRAAL_NOTPRODUCT_FLAG_MEMBER)
+#endif
 #ifdef COMPILER2
  C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_EXPERIMENTAL_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER)
 #endif
--- a/src/share/vm/runtime/javaCalls.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/javaCalls.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -40,11 +40,13 @@
 #include "runtime/signature.hpp"
 #include "runtime/stubRoutines.hpp"
 #include "runtime/thread.inline.hpp"
+#include "graal/graalJavaAccess.hpp"
+#include "graal/graalCompiler.hpp"
 
 // -----------------------------------------------------
 // Implementation of JavaCallWrapper
 
-JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, Handle receiver, JavaValue* result, TRAPS) {
+JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, JavaValue* result, TRAPS) {
   JavaThread* thread = (JavaThread *)THREAD;
   bool clear_pending_exception = true;
 
@@ -75,10 +77,9 @@
   // Make sure to set the oop's after the thread transition - since we can block there. No one is GC'ing
   // the JavaCallWrapper before the entry frame is on the stack.
   _callee_method = callee_method();
-  _receiver = receiver();
 
 #ifdef CHECK_UNHANDLED_OOPS
-  THREAD->allow_unhandled_oop(&_receiver);
+  // THREAD->allow_unhandled_oop(&_receiver);
 #endif // CHECK_UNHANDLED_OOPS
 
   _thread       = (JavaThread *)thread;
@@ -142,7 +143,6 @@
 
 
 void JavaCallWrapper::oops_do(OopClosure* f) {
-  f->do_oop((oop*)&_receiver);
   handles()->oops_do(f);
 }
 
@@ -335,14 +335,19 @@
 
   CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)
 
+#ifdef GRAAL
+  nmethod* nm = args->alternative_target();
+  if (nm == NULL) {
+#endif
   // Verify the arguments
 
   if (CheckJNICalls)  {
     args->verify(method, result->get_type(), thread);
   }
   else debug_only(args->verify(method, result->get_type(), thread));
-
-#ifndef GRAAL
+#ifdef GRAAL
+  }
+#else
   // Ignore call if method is empty
   if (method->is_empty_method()) {
     assert(result->get_type() == T_VOID, "an empty method must return a void value");
@@ -385,9 +390,6 @@
   // the call to call_stub, the optimizer produces wrong code.
   intptr_t* result_val_address = (intptr_t*)(result->get_value_addr());
 
-  // Find receiver
-  Handle receiver = (!method->is_static()) ? args->receiver() : Handle();
-
   // When we reenter Java, we need to reenable the yellow zone which
   // might already be disabled when we are in VM.
   if (thread->stack_yellow_zone_disabled()) {
@@ -406,11 +408,15 @@
   }
 
 #ifdef GRAAL
-  nmethod* nm = args->alternative_target();
   if (nm != NULL) {
     if (nm->is_alive()) {
       ((JavaThread*) THREAD)->set_graal_alternate_call_target(nm->verified_entry_point());
+      oop graalInstalledCode = nm->graal_installed_code();
+      if (graalInstalledCode != NULL && HotSpotNmethod::isExternal(graalInstalledCode)) {
+        entry_point = GraalCompiler::instance()->get_external_deopt_i2c_entry();
+      } else {
       entry_point = method->adapter()->get_i2c_entry();
+      }
     } else {
       THROW(vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException());
     }
@@ -418,7 +424,7 @@
 #endif
   
   // do call
-  { JavaCallWrapper link(method, receiver, result, CHECK);
+  { JavaCallWrapper link(method, result, CHECK);
     { HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner
 
       StubRoutines::call_stub()(
--- a/src/share/vm/runtime/javaCalls.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/javaCalls.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -57,7 +57,6 @@
   JavaThread*      _thread;                 // the thread to which this call belongs
   JNIHandleBlock*  _handles;                // the saved handle block
   Method*          _callee_method;          // to be able to collect arguments if entry frame is top frame
-  oop              _receiver;               // the receiver of the call (if a non-static call)
 
   JavaFrameAnchor  _anchor;                 // last thread anchor state that we must restore
 
@@ -65,7 +64,7 @@
 
  public:
   // Construction/destruction
-   JavaCallWrapper(methodHandle callee_method, Handle receiver, JavaValue* result, TRAPS);
+   JavaCallWrapper(methodHandle callee_method, JavaValue* result, TRAPS);
   ~JavaCallWrapper();
 
   // Accessors
@@ -77,7 +76,6 @@
   JavaValue*       result() const           { return _result; }
   // GC support
   Method*          callee_method()          { return _callee_method; }
-  oop              receiver()               { return _receiver; }
   void             oops_do(OopClosure* f);
 
   bool             is_first_frame() const   { return _anchor.last_Java_sp() == NULL; }
--- a/src/share/vm/runtime/mutexLocker.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/mutexLocker.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -133,10 +133,6 @@
 Mutex*   JfrThreadGroups_lock         = NULL;
 #endif
 
-#ifdef GRAAL
-Mutex*   GraalDeoptLeafGraphIds_lock  = NULL;
-#endif // GRAAL
-
 #define MAX_NUM_MUTEX 128
 static Monitor * _mutex_array[MAX_NUM_MUTEX];
 static int _num_mutex;
@@ -284,10 +280,6 @@
   def(JfrStream_lock               , Mutex,   nonleaf+2,   true);
   def(JfrStacktrace_lock           , Mutex,   special,     true );
 #endif
-
-#ifdef GRAAL
-  def(GraalDeoptLeafGraphIds_lock  , Mutex,   special,     true);
-#endif // GRAAL
 }
 
 GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/share/vm/runtime/mutexLocker.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/mutexLocker.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -149,10 +149,6 @@
 extern Mutex*   JfrThreadGroups_lock;            // protects JFR access to Thread Groups
 #endif
 
-#ifdef GRAAL
-extern Mutex*   GraalDeoptLeafGraphIds_lock;     // protects access to the global array of deopt'ed leaf graphs
-#endif // GRAAL
-
 // A MutexLocker provides mutual exclusion with respect to a given mutex
 // for the scope which contains the locker.  The lock is an OS lock, not
 // an object lock, and the two do not interoperate.  Do not use Mutex-based
--- a/src/share/vm/runtime/sharedRuntime.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -886,7 +886,10 @@
           _implicit_null_throws++;
 #endif
 #ifdef GRAAL
-          if (nm->is_compiled_by_graal()) {
+          if (nm->is_compiled_by_graal() && nm->pc_desc_at(pc) != NULL) {
+            // If there's no PcDesc then we'll die way down inside of
+            // deopt instead of just getting normal error reporting,
+            // so only go there if it will succeed.
             target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check);
           } else {
 #endif
@@ -1168,7 +1171,6 @@
     assert(fr.is_entry_frame(), "must be");
     // fr is now pointing to the entry frame.
     callee_method = methodHandle(THREAD, fr.entry_frame_call_wrapper()->callee_method());
-    assert(fr.entry_frame_call_wrapper()->receiver() == NULL || !callee_method->is_static(), "non-null receiver for static call??");
   } else {
     Bytecodes::Code bc;
     CallInfo callinfo;
--- a/src/share/vm/runtime/thread.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/thread.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -1445,6 +1445,8 @@
   clear_must_deopt_id();
   set_monitor_chunks(NULL);
   set_next(NULL);
+  set_gpu_exception_bci(0);
+  set_gpu_exception_method(NULL);  
   set_thread_state(_thread_new);
 #if INCLUDE_NMT
   set_recorder(NULL);
--- a/src/share/vm/runtime/thread.hpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/thread.hpp	Sun Mar 30 16:08:33 2014 +0200
@@ -946,6 +946,17 @@
   volatile address _exception_handler_pc;        // PC for handler of exception
   volatile int     _is_method_handle_return;     // true (== 1) if the current exception PC is a MethodHandle call site.
 
+  // Record the method and bci from a gpu kernel exception so
+  // it can be added into the exception stack trace
+  jint    _gpu_exception_bci;
+  Method* _gpu_exception_method;
+ public:
+  void set_gpu_exception_bci(jint bci)           { _gpu_exception_bci = bci; } 
+  jint get_gpu_exception_bci()                   { return _gpu_exception_bci; }
+  void set_gpu_exception_method(Method* method)  { _gpu_exception_method = method; }
+  Method* get_gpu_exception_method()             { return _gpu_exception_method; }
+  
+ private:  
   // support for JNI critical regions
   jint    _jni_active_critical;                  // count of entries into JNI critical region
 
--- a/src/share/vm/runtime/vmStructs.cpp	Wed Mar 19 11:43:57 2014 +0100
+++ b/src/share/vm/runtime/vmStructs.cpp	Sun Mar 30 16:08:33 2014 +0200
@@ -90,6 +90,7 @@
 #include "runtime/deoptimization.hpp"
 #include "runtime/vframeArray.hpp"
 #include "runtime/globals.hpp"
+#include "runtime/gpu.hpp"
 #include "runtime/java.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/perfMemory.hpp"
@@ -154,6 +155,9 @@
 #ifdef TARGET_OS_ARCH_bsd_zero
 # include "vmStructs_bsd_zero.hpp"
 #endif
+
+#include "hsail/vm/vmStructs_hsail.hpp"
+
 #if INCLUDE_ALL_GCS
 #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp"
 #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp"
@@ -374,6 +378,7 @@
   nonstatic_field(Method,               _vtable_index,                                 int)                                   \
   nonstatic_field(Method,               _method_size,                                  u2)                                    \
   nonstatic_field(Method,               _intrinsic_id,                                 u1)                                    \
+  nonstatic_field(Method,               _flags,                                        u1)                                    \
   nonproduct_nonstatic_field(Method,    _compiled_invocation_count,                    int)                                   \
   volatile_nonstatic_field(Method,      _code,                                         nmethod*)                              \
   nonstatic_field(Method,               _i2i_entry,                                    address)                               \
@@ -2410,6 +2415,12 @@
   /* ConstMethod anon-enum */                                             \
   /********************************/                                      \
                                                                           \
+  declare_constant(Method::_jfr_towrite)                                  \
+  declare_constant(Method::_caller_sensitive)                             \
+  declare_constant(Method::_force_inline)                                 \
+  declare_constant(Method::_dont_inline)                                  \
+  declare_constant(Method::_hidden)                                       \
+                                                                          \
   declare_constant(ConstMethod::_has_linenumber_table)                    \
   declare_constant(ConstMethod::_has_checked_exceptions)                  \
   declare_constant(ConstMethod::_has_localvariable_table)                 \
@@ -2439,6 +2450,7 @@
   declare_constant(DataLayout::call_type_data_tag)                        \
   declare_constant(DataLayout::virtual_call_type_data_tag)                \
   declare_constant(DataLayout::parameters_type_data_tag)                  \
+  declare_constant(DataLayout::speculative_trap_data_tag)                 \
                                                                           \
   /*************************************/                                 \
   /* InstanceKlass enum                */                                 \
@@ -3027,6 +3039,8 @@
                  GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY,
                  GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY)
 
+  VM_STRUCTS_GPU_HSAIL(GENERATE_NONSTATIC_VM_STRUCT_ENTRY)
+          
   VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
                     GENERATE_STATIC_VM_STRUCT_ENTRY,
                     GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY,
@@ -3077,6 +3091,9 @@
                GENERATE_C2_VM_TYPE_ENTRY,
                GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY)
 
+  VM_TYPES_GPU_HSAIL(GENERATE_VM_TYPE_ENTRY,
+               GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
+
   VM_TYPES_OS_CPU(GENERATE_VM_TYPE_ENTRY,
                   GENERATE_TOPLEVEL_VM_TYPE_ENTRY,
                   GENERATE_OOP_VM_TYPE_ENTRY,
@@ -3181,6 +3198,8 @@
                  CHECK_NO_OP,
                  CHECK_NO_OP);
 
+  VM_STRUCTS_GPU_HSAIL(CHECK_NONSTATIC_VM_STRUCT_ENTRY);
+
   VM_STRUCTS_OS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
                     CHECK_STATIC_VM_STRUCT_ENTRY,
                     CHECK_NO_OP,
@@ -3221,6 +3240,9 @@
                CHECK_C2_VM_TYPE_ENTRY,
                CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY);
 
+  VM_TYPES_GPU_HSAIL(CHECK_VM_TYPE_ENTRY,
+               CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
+
   VM_TYPES_OS_CPU(CHECK_VM_TYPE_ENTRY,
                   CHECK_SINGLE_ARG_VM_TYPE_NO_OP,
                   CHECK_SINGLE_ARG_VM_TYPE_NO_OP,