changeset 16313:151fe6b1e511

Merge
author Stefan Anzinger <stefan.anzinger@gmail.com>
date Fri, 30 May 2014 15:09:09 +0200
parents b5f89908b9ba (current diff) 73a0c8e14cd1 (diff)
children f57cf459f5d3
files graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRFrameStateBuilder.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRLoop.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/UnsafeAccess.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/LIRTypeTool.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampProvider.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResult.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResultBase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FieldIntrospection.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/nodes/AtomicGetAndAddNode.java graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/nodes/LoweredAtomicGetAndAddNode.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSymbol.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConstant.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMField.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMType.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConstant.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMField.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMFlag.java graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMType.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlocksToDoubles.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/FloatStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IllegalStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/PrimitiveStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampProvider.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/VoidStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ASTPrinter.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugContext.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugManager.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DefaultDebugManager.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/KillException.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/QuitException.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/DefaultNodeInstrumenter.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeEvents.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProxyNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/NodeInstrumenter.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/NodePhylum.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/PhylumMarked.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java mx/JUnitWrapper.java mx/mx_graal.py mx/projects src/share/vm/graal/graalCompilerToVM.cpp test/baseline_whitelist.txt test/whitelist_baseline.txt
diffstat 1073 files changed, 41688 insertions(+), 20237 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri May 30 13:23:53 2014 +0200
+++ b/.hgignore	Fri May 30 15:09:09 2014 +0200
@@ -87,3 +87,4 @@
 agent/build/*
 agent/make/filelist
 agent/make/sa17.tar.gz
+export.json
--- a/.hgtags	Fri May 30 13:23:53 2014 +0200
+++ b/.hgtags	Fri May 30 15:09:09 2014 +0200
@@ -405,3 +405,4 @@
 41f4cad94c581034d4c427d2aaabcc20f26342d0 hs25-b63
 b124e22eb772806c13d942cc110de38da0108147 graal-0.1
 483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2
+9535eccd2a115f6c6f0b15efb508b11ff74cc0d3 graal-0.3
--- a/CHANGELOG.md	Fri May 30 13:23:53 2014 +0200
+++ b/CHANGELOG.md	Fri May 30 15:09:09 2014 +0200
@@ -2,23 +2,36 @@
 
 ## `tip`
 ### Graal
+* Made initialization of Graal runtime lazy in hosted mode.
+* Added supported for new 'jrelibrary' dependency type in mx/projects.
+* Java projects with compliance level higher than the JDKs specified by JAVA_HOME and EXTRA_JAVA_HOMES are ignored once mx/projects has been processed.
+* ResolvedJavaType.resolveMethod now takes a context type used to perform access checks. It now works correctly regarding default methods.
+
+### Truffle
+* `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`)
+* ...
+
+## Version 0.3
+9-May-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.3)
+
+### Graal
 * Explicit support for oop compression/uncompression in high level graph.
 * LIRGenerator refactoring.
 * Explicit types for inputs (InputType enum).
 * Added graal.version system property to Graal enabled VM builds.
 * Transitioned to JDK 8 as minimum JDK level for Graal.
 * Added support for stack introspection.
-* ...
+* New MatchRule facility to convert multiple HIR nodes into specialized LIR
 
 ### Truffle
-* The method CallTarget#call takes now a variable number of Object arguments.
-* Support for collecting stack traces and for accessing the current frame in slow paths.
-* Renamed CallNode to DirectCallNode.
-* Renamed TruffleRuntime#createCallNode to TruffleRuntime#createDirectCallNode.
-* Added IndirectCallNode for calls with a changing CallTarget. 
-* Added TruffleRuntime#createIndirectCallNode to create an IndirectCallNode.
-* DirectCallNode#inline was renamed to DirectCallNode#forceInlining().
-* ...
+* The method `CallTarget#call` takes now a variable number of Object arguments.
+* Support for collecting stack traces and for accessing the current frame in slow paths (see `TruffleRuntime#getStackTrace`).
+* Renamed `CallNode` to `DirectCallNode`.
+* Renamed `TruffleRuntime#createCallNode` to `TruffleRuntime#createDirectCallNode`.
+* Added `IndirectCallNode` for calls with a changing `CallTarget`.
+* Added `TruffleRuntime#createIndirectCallNode` to create an `IndirectCallNode`.
+* `DirectCallNode#inline` was renamed to `DirectCallNode#forceInlining()`.
+* Removed deprecated `Node#adoptChild`.
 
 ## Version 0.2
 25-Mar-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.2)
@@ -44,7 +57,7 @@
 * 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
+* Deprecated `Node#adoptChild` and `Node#adoptChildren`, 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
@@ -65,4 +78,3 @@
 
 * Initial version of a multi-language framework on top of Graal.
 * Update of the [Truffle Inlining API](http://mail.openjdk.java.net/pipermail/graal-dev/2014-January/001516.html).
-
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,6 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.nodes.cfg.*;
 
 /**
  * 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, BlocksToDoubles blockProbabilities) {
+    public static <T extends AbstractBlock<T>> List<T> computeLinearScanOrder(int blockCount, T startBlock) {
         List<T> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
-        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities);
-        computeLinearScanOrder(order, worklist, visitedBlocks, blockProbabilities);
+        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
+        computeLinearScanOrder(order, worklist, visitedBlocks);
         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, BlocksToDoubles blockProbabilities) {
+    public static <T extends AbstractBlock<T>> List<T> computeCodeEmittingOrder(int blockCount, T startBlock) {
         List<T> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
-        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities);
-        computeCodeEmittingOrder(order, worklist, visitedBlocks, blockProbabilities);
+        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
+        computeCodeEmittingOrder(order, worklist, visitedBlocks);
         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, BlocksToDoubles blockProbabilities) {
+    private static <T extends AbstractBlock<T>> void computeCodeEmittingOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         while (!worklist.isEmpty()) {
             T nextImportantPath = worklist.poll();
-            addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities);
+            addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks);
         }
     }
 
     /**
      * 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, BlocksToDoubles blockProbabilities) {
+    private static <T extends AbstractBlock<T>> void computeLinearScanOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         while (!worklist.isEmpty()) {
             T nextImportantPath = worklist.poll();
-            addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities);
+            addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks);
         }
     }
 
     /**
      * 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, BlocksToDoubles blockProbabilities) {
-        PriorityQueue<T> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<T>(blockProbabilities));
+    private static <T extends AbstractBlock<T>> PriorityQueue<T> initializeWorklist(T startBlock, BitSet visitedBlocks) {
+        PriorityQueue<T> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<>());
         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, BlocksToDoubles blockProbabilities) {
+    private static <T extends AbstractBlock<T>> void addPathToLinearScanOrder(T block, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         block.setLinearScanNumber(order.size());
         order.add(block);
-        T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities);
+        T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
         enqueueSuccessors(block, worklist, visitedBlocks);
         if (mostLikelySuccessor != null) {
             if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) {
@@ -135,24 +134,24 @@
                 double unscheduledSum = 0.0;
                 for (T pred : mostLikelySuccessor.getPredecessors()) {
                     if (pred.getLinearScanNumber() == -1) {
-                        unscheduledSum += blockProbabilities.get(pred);
+                        unscheduledSum += pred.probability();
                     }
                 }
 
-                if (unscheduledSum > blockProbabilities.get(block) / PENALTY_VERSUS_UNSCHEDULED) {
+                if (unscheduledSum > block.probability() / 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, blockProbabilities);
+            addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks);
         }
     }
 
     /**
      * Add a linear path to the code emission order greedily following the most likely successor.
      */
-    private static <T extends AbstractBlock<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+    private static <T extends AbstractBlock<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         T block = initialBlock;
         while (block != null) {
             // Skip loop headers if there is only a single loop end block to
@@ -167,23 +166,23 @@
             }
 
             Loop<T> loop = block.getLoop();
-            if (block.isLoopEnd() && skipLoopHeader(loop.header)) {
+            if (block.isLoopEnd() && skipLoopHeader(loop.getHeader())) {
 
                 // This is the only loop end of a skipped loop header.
                 // Add the header immediately afterwards.
-                addBlock(loop.header, order);
+                addBlock(loop.getHeader(), order);
 
                 // Make sure the loop successors of the loop header are aligned
                 // as they are the target
                 // of the backward jump.
-                for (T successor : loop.header.getSuccessors()) {
+                for (T successor : loop.getHeader().getSuccessors()) {
                     if (successor.getLoopDepth() == block.getLoopDepth()) {
                         successor.setAlign(true);
                     }
                 }
             }
 
-            T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities);
+            T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
             enqueueSuccessors(block, worklist, visitedBlocks);
             block = mostLikelySuccessor;
         }
@@ -200,11 +199,11 @@
     /**
      * Find the highest likely unvisited successor block of a given block.
      */
-    private static <T extends AbstractBlock<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+    private static <T extends AbstractBlock<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) {
         T result = null;
         for (T successor : block.getSuccessors()) {
-            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))) {
+            assert successor.probability() >= 0.0 : "Probabilities must be positive";
+            if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.probability() >= result.probability())) {
                 result = successor;
             }
         }
@@ -247,12 +246,6 @@
      */
     private static class BlockOrderComparator<T extends AbstractBlock<T>> implements Comparator<T> {
 
-        private final BlocksToDoubles probabilities;
-
-        public BlockOrderComparator(BlocksToDoubles probabilities) {
-            this.probabilities = probabilities;
-        }
-
         @Override
         public int compare(T a, T b) {
             // Loop blocks before any loop exit block.
@@ -262,7 +255,7 @@
             }
 
             // Blocks with high probability before blocks with low probability.
-            if (probabilities.get(a) > probabilities.get(b)) {
+            if (a.probability() > b.probability()) {
                 return -1;
             } else {
                 return 1;
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Fri May 30 15:09:09 2014 +0200
@@ -96,7 +96,8 @@
         public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) {
             this.context = context;
             this.subtype = subtype;
-            assert !subtype.isInterface() : subtype.toString() + " : " + context.toString();
+            assert !subtype.isAbstract() : subtype.toString() + " : " + context.toString();
+            assert !subtype.isArray() || getElementalType(subtype).isFinal() : subtype.toString() + " : " + context.toString();
         }
 
         @Override
@@ -264,7 +265,7 @@
 
     /**
      * Returns whether any assumptions have been registered.
-     * 
+     *
      * @return {@code true} if at least one assumption has been registered, {@code false} otherwise.
      */
     public boolean isEmpty() {
@@ -303,7 +304,7 @@
 
     /**
      * Records an assumption that the specified type has no finalizable subclasses.
-     * 
+     *
      * @param receiverType the type that is assumed to have no finalizable subclasses
      */
     public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) {
@@ -314,7 +315,7 @@
     /**
      * Records that {@code subtype} is the only concrete subtype in the class hierarchy below
      * {@code context}.
-     * 
+     *
      * @param context the root of the subtree of the class hierarchy that this assumptions is about
      * @param subtype the one concrete subtype
      */
@@ -326,7 +327,7 @@
     /**
      * Records that {@code impl} is the only possible concrete target for a virtual call to
      * {@code method} with a receiver of type {@code context}.
-     * 
+     *
      * @param method a method that is the target of a virtual call
      * @param context the receiver type of a call to {@code method}
      * @param impl the concrete method that is the only possible target for the virtual call
@@ -338,7 +339,7 @@
 
     /**
      * Records that {@code method} was used during the compilation.
-     * 
+     *
      * @param method a method whose contents were used
      */
     public void recordMethodContents(ResolvedJavaMethod method) {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Fri May 30 15:09:09 2014 +0200
@@ -94,6 +94,43 @@
     public final boolean duringCall;
 
     /**
+     * This BCI should be used for frame states that are built for code with no meaningful BCI.
+     */
+    public static final int UNKNOWN_BCI = -5;
+
+    /**
+     * The BCI for exception unwind. This is synthetic code and has no representation in bytecode.
+     * In contrast with {@link #AFTER_EXCEPTION_BCI}, at this point, if the method is synchronized,
+     * the monitor is still held.
+     */
+    public static final int UNWIND_BCI = -1;
+
+    /**
+     * The BCI for the state before starting to execute a method. Note that if the method is
+     * synchronized, the monitor is not yet held.
+     */
+    public static final int BEFORE_BCI = -2;
+
+    /**
+     * The BCI for the state after finishing the execution of a method and returning normally. Note
+     * that if the method was synchronized the monitor is already released.
+     */
+    public static final int AFTER_BCI = -3;
+
+    /**
+     * The BCI for exception unwind. This is synthetic code and has no representation in bytecode.
+     * In contrast with {@link #UNWIND_BCI}, at this point, if the method is synchronized, the
+     * monitor is already released.
+     */
+    public static final int AFTER_EXCEPTION_BCI = -4;
+
+    /**
+     * This BCI should be used for states that cannot be the target of a deoptimization, like
+     * snippet frame states.
+     */
+    public static final int INVALID_FRAMESTATE_BCI = -6;
+
+    /**
      * Creates a new frame object.
      *
      * @param caller the caller frame (which may be {@code null})
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,4 +93,9 @@
      * Gets a description of the target architecture.
      */
     TargetDescription getTarget();
+
+    /**
+     * Create a new speculation log for the target runtime.
+     */
+    SpeculationLog createSpeculationLog();
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.code;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -342,7 +341,7 @@
         int sigCount = sig.getParameterCount(false);
         JavaType[] argTypes;
         int argIndex = 0;
-        if (!Modifier.isStatic(method.getModifiers())) {
+        if (!method.isStatic()) {
             argTypes = new JavaType[sigCount + 1];
             argTypes[argIndex++] = method.getDeclaringClass();
         } else {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Fri May 30 15:09:09 2014 +0200
@@ -432,22 +432,20 @@
 
         private static final long serialVersionUID = 3612943150662354844L;
         public final Object id;
-        public final Mark[] references;
 
-        public Mark(int pcOffset, Object id, Mark[] references) {
+        public Mark(int pcOffset, Object id) {
             super(pcOffset);
             this.id = id;
-            this.references = references;
         }
 
         @Override
         public String toString() {
             if (id == null) {
-                return String.format("%d[<mark with %d references>]", pcOffset, references.length);
+                return String.format("%d[<mar>]", pcOffset);
             } else if (id instanceof Integer) {
-                return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, Integer.toHexString((Integer) id));
+                return String.format("%d[<mark with id %s>]", pcOffset, Integer.toHexString((Integer) id));
             } else {
-                return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, id.toString());
+                return String.format("%d[<mark with id %s>]", pcOffset, id.toString());
             }
         }
     }
@@ -462,7 +460,6 @@
 
     private int totalFrameSize = -1;
     private int customStackAreaOffset = -1;
-    private int registerRestoreEpilogueOffset = -1;
 
     private final String name;
 
@@ -635,35 +632,14 @@
      *
      * @param codePos the position in the code that is covered by the handler
      * @param markId the identifier for this mark
-     * @param references an array of other marks that this mark references
      */
-    public Mark recordMark(int codePos, Object markId, Mark[] references) {
-        Mark mark = new Mark(codePos, markId, references);
+    public Mark recordMark(int codePos, Object markId) {
+        Mark mark = new Mark(codePos, markId);
         marks.add(mark);
         return mark;
     }
 
     /**
-     * Allows a method to specify the offset of the epilogue that restores the callee saved
-     * registers. Must be called iff the method is a callee saved method and stores callee registers
-     * on the stack.
-     *
-     * @param registerRestoreEpilogueOffset the offset in the machine code where the epilogue begins
-     */
-    public void setRegisterRestoreEpilogueOffset(int registerRestoreEpilogueOffset) {
-        assert this.registerRestoreEpilogueOffset == -1;
-        this.registerRestoreEpilogueOffset = registerRestoreEpilogueOffset;
-    }
-
-    /**
-     * @return the code offset of the start of the epilogue that restores all callee saved
-     *         registers, or -1 if this is not a callee saved method
-     */
-    public int getRegisterRestoreEpilogueOffset() {
-        return registerRestoreEpilogueOffset;
-    }
-
-    /**
      * Offset in bytes for the custom stack area (relative to sp).
      *
      * @return the offset in bytes
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Fri May 30 15:09:09 2014 +0200
@@ -29,8 +29,6 @@
 
     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/RegisterSaveLayout.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,16 +33,16 @@
     /**
      * Keys.
      */
-    private Register[] registers;
+    private final Register[] registers;
 
     /**
      * Slot indexes relative to stack pointer.
      */
-    private int[] slots;
+    private final int[] slots;
 
     /**
      * Creates a map from registers to frame slots.
-     * 
+     *
      * @param registers the keys in the map
      * @param slots frame slot index for each register in {@code registers}
      */
@@ -55,6 +55,21 @@
     }
 
     /**
+     * Gets the frame slot index for a given register.
+     *
+     * @param register register to get the frame slot index for
+     * @return frame slot index
+     */
+    public int registerToSlot(Register register) {
+        for (int i = 0; i < registers.length; i++) {
+            if (register.equals(registers[i])) {
+                return slots[i];
+            }
+        }
+        throw new IllegalArgumentException(register + " not saved by this layout: " + this);
+    }
+
+    /**
      * Gets this layout information as a {@link Map} from registers to slots.
      */
     public Map<Register, Integer> registersToSlots(boolean sorted) {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,6 @@
 package com.oracle.graal.api.code;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -83,7 +81,7 @@
 
     /**
      * Derives hint information for use when generating the code for a type check instruction.
-     * 
+     *
      * @param targetType the target type of the type check
      * @param profile the profiling information available for the instruction (if any)
      * @param assumptions the object in which speculations are recorded. This is null if
@@ -151,10 +149,10 @@
     /**
      * Determines if a given type can have subtypes other than itself. This analysis is purely
      * static; no assumptions are made.
-     * 
+     *
      * @return true if {@code type} can have subtypes
      */
     public static boolean canHaveSubtype(ResolvedJavaType type) {
-        return !isFinal(getElementalType(type).getModifiers());
+        return !getElementalType(type).isFinal();
     }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Fri May 30 15:09:09 2014 +0200
@@ -27,7 +27,7 @@
 public interface StackIntrospection {
 
     /**
-     * Accesses the current stack, returning a collection of {@long InspectedFrame}s that can be
+     * Accesses the current stack, returning a collection of {@link InspectedFrame}s that can be
      * used to inspect the stack frames' contents.
      *
      * @param initialMethods if this is non-{@code null}, then the stack trace will start at these
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.collections/src/com/oracle/graal/api/collections/CollectionsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.collections;
+
+import java.util.*;
+
+/**
+ * A factory for creating collections.
+ */
+public interface CollectionsProvider {
+
+    /**
+     * Creates a set that uses reference-equality in place of object-equality when comparing
+     * entries.
+     */
+    <E> Set<E> newIdentitySet();
+
+    /**
+     * Creates a map that uses reference-equality in place of object-equality when comparing keys.
+     */
+    <K, V> Map<K, V> newIdentityMap();
+
+    /**
+     * Creates a map that uses reference-equality in place of object-equality when comparing keys.
+     *
+     * @param expectedMaxSize the expected maximum size of the map
+     */
+    <K, V> Map<K, V> newIdentityMap(int expectedMaxSize);
+
+    /**
+     * Creates a map that uses reference-equality in place of object-equality when comparing keys.
+     *
+     * @param initFrom the returned map is populated with the entries in this map
+     */
+    <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.collections/src/com/oracle/graal/api/collections/DefaultCollectionsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.collections;
+
+import java.util.*;
+
+/**
+ * A default implementation of {@link CollectionsProvider} that creates standard JDK collection
+ * class objects.
+ */
+public class DefaultCollectionsProvider implements CollectionsProvider {
+
+    public <E> Set<E> newIdentitySet() {
+        return Collections.newSetFromMap(newIdentityMap());
+    }
+
+    public <K, V> Map<K, V> newIdentityMap() {
+        return new IdentityHashMap<>();
+    }
+
+    public <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
+        return new IdentityHashMap<>(expectedMaxSize);
+    }
+
+    public <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom) {
+        return new IdentityHashMap<>(initFrom);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/ResolvedJavaTypeResolveMethodTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.runtime.*;
+
+public class ResolvedJavaTypeResolveMethodTest {
+    public final MetaAccessProvider metaAccess;
+
+    public ResolvedJavaTypeResolveMethodTest() {
+        Providers providers = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders();
+        metaAccess = providers.getMetaAccess();
+    }
+
+    protected static abstract class A {
+        @SuppressWarnings("unused")
+        private void priv() {
+        }
+
+        public void v1() {
+        }
+
+        public void v2() {
+        }
+
+        public abstract void abs();
+    }
+
+    protected static class B extends A implements I {
+        public void i() {
+        }
+
+        @Override
+        public void v2() {
+        }
+
+        @Override
+        public void abs() {
+
+        }
+    }
+
+    protected static class C extends B {
+        public void d() {
+        }
+    }
+
+    protected static abstract class D extends A {
+
+    }
+
+    protected static class E extends D {
+        @Override
+        public void abs() {
+        }
+    }
+
+    protected interface I {
+        void i();
+
+        default void d() {
+        }
+    }
+
+    @Test
+    public void testDefaultMethod() {
+        ResolvedJavaType i = getType(I.class);
+        ResolvedJavaType b = getType(B.class);
+        ResolvedJavaType c = getType(C.class);
+        ResolvedJavaMethod di = getMethod(i, "d");
+        ResolvedJavaMethod dc = getMethod(c, "d");
+
+        assertEquals(di, i.resolveMethod(di, c));
+        assertEquals(di, b.resolveMethod(di, c));
+        assertEquals(dc, c.resolveMethod(di, c));
+    }
+
+    @Test
+    public void testPrivateMethod() {
+        ResolvedJavaType a = getType(A.class);
+        ResolvedJavaType b = getType(B.class);
+        ResolvedJavaType c = getType(C.class);
+        ResolvedJavaMethod priv = getMethod(a, "priv");
+
+        assertNull(a.resolveMethod(priv, c));
+        assertNull(b.resolveMethod(priv, c));
+    }
+
+    @Test
+    public void testAbstractMethod() {
+        ResolvedJavaType a = getType(A.class);
+        ResolvedJavaType b = getType(B.class);
+        ResolvedJavaType c = getType(C.class);
+        ResolvedJavaType d = getType(D.class);
+        ResolvedJavaType e = getType(E.class);
+        ResolvedJavaMethod absa = getMethod(a, "abs");
+        ResolvedJavaMethod absb = getMethod(b, "abs");
+        ResolvedJavaMethod abse = getMethod(e, "abs");
+
+        assertNull(a.resolveMethod(absa, c));
+        assertNull(d.resolveMethod(absa, c));
+
+        assertEquals(absb, b.resolveMethod(absa, c));
+        assertEquals(absb, b.resolveMethod(absb, c));
+        assertEquals(absb, c.resolveMethod(absa, c));
+        assertEquals(absb, c.resolveMethod(absb, c));
+        assertEquals(abse, e.resolveMethod(absa, c));
+        assertNull(e.resolveMethod(absb, c));
+        assertEquals(abse, e.resolveMethod(abse, c));
+    }
+
+    @Test
+    public void testVirtualMethod() {
+        ResolvedJavaType a = getType(A.class);
+        ResolvedJavaType b = getType(B.class);
+        ResolvedJavaType c = getType(C.class);
+        ResolvedJavaMethod v1a = getMethod(a, "v1");
+        ResolvedJavaMethod v2a = getMethod(a, "v2");
+        ResolvedJavaMethod v2b = getMethod(b, "v2");
+
+        assertEquals(v1a, a.resolveMethod(v1a, c));
+        assertEquals(v1a, b.resolveMethod(v1a, c));
+        assertEquals(v1a, c.resolveMethod(v1a, c));
+        assertEquals(v2a, a.resolveMethod(v2a, c));
+        assertEquals(v2b, b.resolveMethod(v2a, c));
+        assertEquals(v2b, b.resolveMethod(v2b, c));
+        assertEquals(v2b, c.resolveMethod(v2a, c));
+        assertEquals(v2b, c.resolveMethod(v2b, c));
+
+    }
+
+    private static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) {
+        for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
+            if (method.getName().equals(methodName)) {
+                return method;
+            }
+        }
+        throw new IllegalArgumentException();
+    }
+
+    protected ResolvedJavaType getType(Class<?> clazz) {
+        ResolvedJavaType type = metaAccess.lookupJavaType(clazz);
+        type.initialize();
+        return type;
+    }
+}
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java	Fri May 30 15:09:09 2014 +0200
@@ -164,6 +164,9 @@
     public void testCoverage() {
         Set<String> known = new HashSet<>(Arrays.asList(untestedApiMethods));
         for (Method m : ResolvedJavaField.class.getDeclaredMethods()) {
+            if (m.isSynthetic()) {
+                continue;
+            }
             if (findTestMethod(m) == null) {
                 assertTrue("test missing for " + m, known.contains(m.getName()));
             } else {
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.api.meta.test;
 
-import static java.lang.reflect.Modifier.*;
 import static org.junit.Assert.*;
 
 import java.lang.annotation.*;
@@ -52,9 +51,9 @@
             if (code == null) {
                 assertTrue(m.getCodeSize() == 0);
             } else {
-                if (isAbstract(m.getModifiers())) {
+                if (m.isAbstract()) {
                     assertTrue(code.length == 0);
-                } else if (!isNative(m.getModifiers())) {
+                } else if (!m.isNative()) {
                     assertTrue(code.length > 0);
                 }
             }
@@ -69,9 +68,9 @@
         for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
             ResolvedJavaMethod m = e.getValue();
             int codeSize = m.getCodeSize();
-            if (isAbstract(m.getModifiers())) {
+            if (m.isAbstract()) {
                 assertTrue(codeSize == 0);
-            } else if (!isNative(m.getModifiers())) {
+            } else if (!m.isNative()) {
                 assertTrue(codeSize > 0);
             }
         }
@@ -128,6 +127,18 @@
     }
 
     @Test
+    public void isSynchronizedTest() {
+        for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized());
+        }
+        for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized());
+        }
+    }
+
+    @Test
     public void canBeStaticallyBoundTest() {
         for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
             ResolvedJavaMethod m = e.getValue();
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Fri May 30 15:09:09 2014 +0200
@@ -265,10 +265,13 @@
     static class Concrete3 extends Concrete2 {
     }
 
+    static final class Final1 extends Abstract1 {
+    }
+
     abstract static class Abstract4 extends Concrete3 {
     }
 
-    void checkConcreteSubtype(ResolvedJavaType type, Class<?> expected) {
+    void checkConcreteSubtype(ResolvedJavaType type, ResolvedJavaType expected) {
         ResolvedJavaType subtype = type.findUniqueConcreteSubtype();
         if (subtype == null) {
             // findUniqueConcreteSubtype() is conservative
@@ -276,7 +279,7 @@
             if (expected == null) {
                 assertNull(subtype);
             } else {
-                assertTrue(subtype.equals(metaAccess.lookupJavaType(expected)));
+                assertTrue(subtype.equals(expected));
             }
         }
 
@@ -294,31 +297,44 @@
     @Test
     public void findUniqueConcreteSubtypeTest() {
         ResolvedJavaType base = metaAccess.lookupJavaType(Base.class);
-        checkConcreteSubtype(base, Base.class);
+        checkConcreteSubtype(base, base);
 
         ResolvedJavaType a1 = metaAccess.lookupJavaType(Abstract1.class);
         ResolvedJavaType c1 = metaAccess.lookupJavaType(Concrete1.class);
 
         checkConcreteSubtype(base, null);
-        checkConcreteSubtype(a1, Concrete1.class);
-        checkConcreteSubtype(c1, Concrete1.class);
+        checkConcreteSubtype(a1, c1);
+        checkConcreteSubtype(c1, c1);
 
         ResolvedJavaType i1 = metaAccess.lookupJavaType(Interface1.class);
         ResolvedJavaType c2 = metaAccess.lookupJavaType(Concrete2.class);
 
         checkConcreteSubtype(base, null);
         checkConcreteSubtype(a1, null);
-        checkConcreteSubtype(c1, Concrete1.class);
-        checkConcreteSubtype(i1, Concrete2.class);
-        checkConcreteSubtype(c2, Concrete2.class);
+        checkConcreteSubtype(c1, c1);
+        checkConcreteSubtype(i1, c2);
+        checkConcreteSubtype(c2, c2);
 
         ResolvedJavaType c3 = metaAccess.lookupJavaType(Concrete3.class);
         checkConcreteSubtype(c2, null);
-        checkConcreteSubtype(c3, Concrete3.class);
+        checkConcreteSubtype(c3, c3);
 
         ResolvedJavaType a4 = metaAccess.lookupJavaType(Abstract4.class);
         checkConcreteSubtype(c3, null);
         checkConcreteSubtype(a4, null);
+
+        ResolvedJavaType a1a = metaAccess.lookupJavaType(Abstract1[].class);
+        checkConcreteSubtype(a1a, null);
+        ResolvedJavaType c1a = metaAccess.lookupJavaType(Concrete1[].class);
+        checkConcreteSubtype(c1a, null);
+        ResolvedJavaType f1a = metaAccess.lookupJavaType(Final1[].class);
+        checkConcreteSubtype(f1a, f1a);
+
+        ResolvedJavaType obja = metaAccess.lookupJavaType(Object[].class);
+        checkConcreteSubtype(obja, null);
+
+        ResolvedJavaType inta = metaAccess.lookupJavaType(int[].class);
+        checkConcreteSubtype(inta, inta);
     }
 
     @Test
@@ -431,20 +447,21 @@
         return declarations;
     }
 
-    private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaMethod decl, ResolvedJavaMethod expected) {
-        ResolvedJavaMethod impl = type.resolveMethod(decl);
+    private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaType context, ResolvedJavaMethod decl, ResolvedJavaMethod expected) {
+        ResolvedJavaMethod impl = type.resolveMethod(decl, context);
         assertEquals(expected, impl);
     }
 
     @Test
     public void resolveMethodTest() {
+        ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class);
         for (Class<?> c : classes) {
             if (c.isInterface() || c.isPrimitive()) {
                 ResolvedJavaType type = metaAccess.lookupJavaType(c);
                 for (Method m : c.getDeclaredMethods()) {
                     if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) {
                         ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m);
-                        ResolvedJavaMethod impl = type.resolveMethod(resolved);
+                        ResolvedJavaMethod impl = type.resolveMethod(resolved, context);
                         ResolvedJavaMethod expected = resolved.isDefault() ? resolved : null;
                         assertEquals(m.toString(), expected, impl);
                     } else {
@@ -458,12 +475,14 @@
                     Set<Method> decls = findDeclarations(impl, c);
                     for (Method decl : decls) {
                         ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
-                        ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
-                        checkResolveMethod(type, m, i);
+                        if (m.isPublic()) {
+                            ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
+                            checkResolveMethod(type, context, m, i);
+                        }
                     }
                 }
                 for (Method m : c.getDeclaredMethods()) {
-                    ResolvedJavaMethod impl = type.resolveMethod(metaAccess.lookupJavaMethod(m));
+                    ResolvedJavaMethod impl = type.resolveMethod(metaAccess.lookupJavaMethod(m), context);
                     ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl;
                     assertEquals(type + " " + m.toString(), expected, impl);
                 }
@@ -494,6 +513,16 @@
         return result;
     }
 
+    public static Set<Field> getStaticFields(Class<?> c) {
+        Set<Field> result = new HashSet<>();
+        for (Field f : c.getDeclaredFields()) {
+            if (Modifier.isStatic(f.getModifiers())) {
+                result.add(f);
+            }
+        }
+        return result;
+    }
+
     public boolean fieldsEqual(Field f, ResolvedJavaField rjf) {
         return rjf.getDeclaringClass().equals(metaAccess.lookupJavaType(f.getDeclaringClass())) && rjf.getName().equals(f.getName()) &&
                         rjf.getType().resolve(rjf.getDeclaringClass()).equals(metaAccess.lookupJavaType(f.getType()));
@@ -551,6 +580,27 @@
     }
 
     @Test
+    public void getStaticFieldsTest() {
+        for (Class<?> c : classes) {
+            ResolvedJavaType type = metaAccess.lookupJavaType(c);
+            Set<Field> expected = getStaticFields(c);
+            ResolvedJavaField[] actual = type.getStaticFields();
+            for (Field f : expected) {
+                assertNotNull(lookupField(actual, f));
+            }
+            for (ResolvedJavaField rf : actual) {
+                if (!isHiddenFromReflection(rf)) {
+                    assertEquals(lookupField(expected, rf) != null, !rf.isInternal());
+                }
+            }
+
+            // Test stability of getStaticFields
+            ResolvedJavaField[] actual2 = type.getStaticFields();
+            assertArrayEquals(actual, actual2);
+        }
+    }
+
+    @Test
     public void getDeclaredMethodsTest() {
         for (Class<?> c : classes) {
             ResolvedJavaType type = metaAccess.lookupJavaType(c);
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Fri May 30 15:09:09 2014 +0200
@@ -63,7 +63,7 @@
         assert NULL_OBJECT.isNull();
     }
 
-    protected Constant(Kind kind) {
+    protected Constant(PlatformKind kind) {
         super(kind);
     }
 
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.api.meta;
 
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
@@ -111,14 +109,20 @@
             if (result.size() == 0) {
                 return new JavaTypeProfile(newNullSeen, 1.0, EMPTY_ARRAY);
             }
-            double probabilitySum = 0.0;
-            for (int i = 0; i < result.size(); i++) {
-                probabilitySum += result.get(i).getProbability();
+            double factor;
+            if (result.size() == this.getItems().length) {
+                /* List of types did not change, no need to recompute probabilities. */
+                factor = 1.0;
+            } else {
+                double probabilitySum = 0.0;
+                for (int i = 0; i < result.size(); i++) {
+                    probabilitySum += result.get(i).getProbability();
+                }
+                probabilitySum += newNotRecorded;
+
+                factor = 1.0 / probabilitySum; // Normalize to 1.0
+                assert factor >= 1.0;
             }
-            probabilitySum += newNotRecorded;
-
-            double factor = 1.0 / probabilitySum; // Normalize to 1.0
-            assert factor >= 1.0;
             ProfiledType[] newResult = new ProfiledType[result.size()];
             for (int i = 0; i < newResult.length; ++i) {
                 ProfiledType curType = result.get(i);
@@ -146,7 +150,7 @@
 
         public ProfiledType(ResolvedJavaType type, double probability) {
             super(type, probability);
-            assert type.isArray() || !isAbstract(type.getModifiers()) : type;
+            assert type.isArray() || !type.isAbstract() : type;
         }
 
         /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.api.meta;
 
-import static java.lang.reflect.Modifier.*;
-
 import java.io.*;
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -378,7 +376,7 @@
                         break;
                     }
                     case 'f': {
-                        sb.append(!(method instanceof ResolvedJavaMethod) ? "unresolved" : isStatic(((ResolvedJavaMethod) method).getModifiers()) ? "static" : "virtual");
+                        sb.append(!(method instanceof ResolvedJavaMethod) ? "unresolved" : ((ResolvedJavaMethod) method).isStatic() ? "static" : "virtual");
                         break;
                     }
                     case '%': {
@@ -452,7 +450,7 @@
                         break;
                     }
                     case 'f': {
-                        sb.append(!(field instanceof ResolvedJavaField) ? "unresolved" : isStatic(((ResolvedJavaField) field).getModifiers()) ? "static" : "instance");
+                        sb.append(!(field instanceof ResolvedJavaField) ? "unresolved" : ((ResolvedJavaField) field).isStatic() ? "static" : "instance");
                         break;
                     }
                     case '%': {
@@ -561,7 +559,7 @@
     }
 
     public static JavaType[] signatureToTypes(ResolvedJavaMethod method) {
-        JavaType receiver = isStatic(method.getModifiers()) ? null : method.getDeclaringClass();
+        JavaType receiver = method.isStatic() ? null : method.getDeclaringClass();
         return signatureToTypes(method.getSignature(), receiver);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ModifiersProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import static java.lang.reflect.Modifier.*;
+
+import java.lang.reflect.*;
+
+/**
+ * A Java element (i.e., a class, interface, field or method) that is described by a set of Java
+ * language {@linkplain #getModifiers() modifiers}.
+ */
+public interface ModifiersProvider {
+
+    /**
+     * Returns the Java language modifiers for this element.
+     */
+    int getModifiers();
+
+    /**
+     * see {@link Modifier#isInterface(int)}
+     */
+    default boolean isInterface() {
+        return Modifier.isInterface(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isSynchronized(int)}
+     */
+    default boolean isSynchronized() {
+        return Modifier.isSynchronized(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isStatic(int)}
+     */
+    default boolean isStatic() {
+        return Modifier.isStatic(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isFinal(int)}
+     */
+    default boolean isFinal() {
+        return Modifier.isFinal(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isPublic(int)}
+     */
+    default boolean isPublic() {
+        return Modifier.isPublic(getModifiers());
+    }
+
+    /**
+     * Determines if this element is neither {@linkplain #isPublic() public},
+     * {@linkplain #isProtected() protected} nor {@linkplain #isPrivate() private}.
+     */
+    default boolean isPackagePrivate() {
+        return ((PUBLIC | PROTECTED | PRIVATE) & getModifiers()) == 0;
+    }
+
+    /**
+     * see {@link Modifier#isPrivate(int)}
+     */
+    default boolean isPrivate() {
+        return Modifier.isPrivate(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isProtected(int)}
+     */
+    default boolean isProtected() {
+        return Modifier.isProtected(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isTransient(int)}
+     */
+    default boolean isTransient() {
+        return Modifier.isTransient(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isStrict(int)}
+     */
+    default boolean isStrict() {
+        return Modifier.isStrict(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isVolatile(int)}
+     */
+    default boolean isVolatile() {
+        return Modifier.isVolatile(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isNative(int)}
+     */
+    default boolean isNative() {
+        return Modifier.isNative(getModifiers());
+    }
+
+    /**
+     * see {@link Modifier#isAbstract(int)}
+     */
+    default boolean isAbstract() {
+        return Modifier.isAbstract(getModifiers());
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Fri May 30 15:09:09 2014 +0200
@@ -29,12 +29,13 @@
  * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved
  * through {@link ConstantPool constant pools}.
  */
-public interface ResolvedJavaField extends JavaField, LocationIdentity {
+public interface ResolvedJavaField extends JavaField, LocationIdentity, ModifiersProvider {
 
     /**
-     * Returns the Java language modifiers for this field, as an integer. The {@link Modifier} class
-     * should be used to decode the modifiers. Only the {@linkplain Modifier#fieldModifiers() field
-     * flags} specified in the JVM specification will be included in the returned mask.
+     * {@inheritDoc}
+     * <p>
+     * Only the {@linkplain Modifier#fieldModifiers() field flags} specified in the JVM
+     * specification will be included in the returned mask.
      */
     int getModifiers();
 
@@ -53,7 +54,7 @@
      * Gets the constant value of this field. Note that a {@code static final} field may not be
      * considered constant if its declaring class is not yet initialized or if it is a well known
      * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}).
-     * 
+     *
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
      * @return the constant value of this field or {@code null} if this field is not considered
@@ -65,7 +66,7 @@
      * Gets the current value of this field for a given object, if available. There is no guarantee
      * that the same value will be returned by this method for a field unless the field is
      * considered to be {@linkplain #readConstantValue(Constant) constant} by the runtime.
-     * 
+     *
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
      * @return the value of this field or {@code null} if the value is not available (e.g., because
@@ -82,7 +83,7 @@
     /**
      * Returns the annotation for the specified type of this field, if such an annotation is
      * present.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @return this element's annotation for the specified annotation type if present on this field,
      *         else {@code null}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,7 @@
  * Represents a resolved Java method. Methods, like fields and types, are resolved through
  * {@link ConstantPool constant pools}.
  */
-public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget {
+public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider {
 
     /**
      * Returns the bytecode of this method, if the method has code. The returned byte array does not
@@ -69,10 +69,10 @@
     int getMaxStackSize();
 
     /**
-     * Returns the Java language modifiers for this method, as an integer. The {@link Modifier}
-     * class should be used to decode the modifiers. Only the
-     * {@linkplain Modifier#methodModifiers() method flags} specified in the JVM specification will
-     * be included in the returned mask.
+     * {@inheritDoc}
+     * <p>
+     * Only the {@linkplain Modifier#methodModifiers() method flags} specified in the JVM
+     * specification will be included in the returned mask.
      */
     int getModifiers();
 
@@ -218,9 +218,10 @@
     Constant getEncoding();
 
     /**
-     * Checks if this method is present in the virtual table.
+     * Checks if this method is present in the virtual table for subtypes of the specified
+     * {@linkplain ResolvedJavaType type}.
      *
-     * @return true is this method is present in the virtual table
+     * @return true is this method is present in the virtual table for subtypes of this type.
      */
-    boolean isInVirtualMethodTable();
+    boolean isInVirtualMethodTable(ResolvedJavaType resolved);
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Fri May 30 15:09:09 2014 +0200
@@ -31,7 +31,7 @@
  * thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools}
  * .
  */
-public interface ResolvedJavaType extends JavaType {
+public interface ResolvedJavaType extends JavaType, ModifiersProvider {
 
     /**
      * Represents each of the several different parts of the runtime representation of a type which
@@ -54,7 +54,7 @@
     /**
      * Gets the encoding of (that is, a constant representing the value of) the specified part of
      * this type.
-     * 
+     *
      * @param r the part of this type
      * @return a constant representing a reference to the specified part of this type
      */
@@ -62,7 +62,7 @@
 
     /**
      * Checks whether this type has a finalizer method.
-     * 
+     *
      * @return {@code true} if this class has a finalizer
      */
     boolean hasFinalizer();
@@ -70,51 +70,52 @@
     /**
      * Checks whether this type has any finalizable subclasses so far. Any decisions based on this
      * information require the registration of a dependency, since this information may change.
-     * 
+     *
      * @return {@code true} if this class has any subclasses with finalizers
      */
     boolean hasFinalizableSubclass();
 
     /**
      * Checks whether this type is an interface.
-     * 
+     *
      * @return {@code true} if this type is an interface
      */
     boolean isInterface();
 
     /**
      * Checks whether this type is an instance class.
-     * 
+     *
      * @return {@code true} if this type is an instance class
      */
     boolean isInstanceClass();
 
     /**
      * Checks whether this type is an array class.
-     * 
+     *
      * @return {@code true} if this type is an array class
      */
     boolean isArray();
 
     /**
      * Checks whether this type is primitive.
-     * 
+     *
      * @return {@code true} if this type is primitive
      */
     boolean isPrimitive();
 
     /**
-     * Returns the Java language modifiers for this type, as an integer. The {@link Modifier} class
-     * should be used to decode the modifiers. Only the flags specified in the JVM specification
-     * will be included in the returned mask. This method is identical to
-     * {@link Class#getModifiers()} in terms of the value return for this type.
+     * {@inheritDoc}
+     * <p>
+     * Only the flags specified in the JVM specification will be included in the returned mask. This
+     * method is identical to {@link Class#getModifiers()} in terms of the value return for this
+     * type.
      */
     int getModifiers();
 
     /**
      * Checks whether this type is initialized. If a type is initialized it implies that it was
      * {@link #isLinked() linked} and that the static initializer has run.
-     * 
+     *
      * @return {@code true} if this type is initialized
      */
     boolean isInitialized();
@@ -127,7 +128,7 @@
     /**
      * Checks whether this type is linked and verified. When a type is linked the static initializer
      * has not necessarily run. An {@link #isInitialized() initialized} type is always linked.
-     * 
+     *
      * @return {@code true} if this type is linked
      */
     boolean isLinked();
@@ -141,7 +142,7 @@
 
     /**
      * Checks whether the specified object is an instance of this type.
-     * 
+     *
      * @param obj the object to test
      * @return {@code true} if the object is an instance of this type
      */
@@ -150,7 +151,7 @@
     /**
      * Returns this type if it is an exact type otherwise returns null. This type is exact if it is
      * void, primitive, final, or an array of a final or primitive type.
-     * 
+     *
      * @return this type if it is exact; {@code null} otherwise
      */
     ResolvedJavaType asExactType();
@@ -172,7 +173,7 @@
     /**
      * Walks the class hierarchy upwards and returns the least common class that is a superclass of
      * both the current and the given type.
-     * 
+     *
      * @return the least common type that is a super type of both the current and the given type, or
      *         {@code null} if primitive types are involved.
      */
@@ -194,7 +195,7 @@
      * <p>
      * If the compiler uses the result of this method for its compilation, it must register an
      * assumption because dynamic class loading can invalidate the result of this method.
-     * 
+     *
      * @return the unique concrete subclass for this type as described above
      */
     ResolvedJavaType findUniqueConcreteSubtype();
@@ -208,12 +209,13 @@
      * This resolution process only searches "up" the class hierarchy of this type. A broader search
      * that also walks "down" the hierarchy is implemented by
      * {@link #findUniqueConcreteMethod(ResolvedJavaMethod)}.
-     * 
+     *
      * @param method the method to select the implementation of
+     * @param callerType the caller or context type used to perform access checks
      * @return the concrete method that would be selected at runtime, or {@code null} if there is no
      *         concrete implementation of {@code method} in this type or any of its superclasses
      */
-    ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method);
+    ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType);
 
     /**
      * Given a {@link ResolvedJavaMethod} A, returns a concrete {@link ResolvedJavaMethod} B that is
@@ -223,7 +225,7 @@
      * <p>
      * If the compiler uses the result of this method for its compilation, it must register an
      * assumption because dynamic class loading can invalidate the result of this method.
-     * 
+     *
      * @param method the method A for which a unique concrete target is searched
      * @return the unique concrete target or {@code null} if no such target exists or assumptions
      *         are not supported by this runtime
@@ -237,7 +239,7 @@
      * is, for a single JVM execution the same order is returned each time this method is called. It
      * is also the "natural" order, which means that the JVM would expect the fields in this order
      * if no specific order is given.
-     * 
+     *
      * @param includeSuperclasses if true, then instance fields for the complete hierarchy of this
      *            type are included in the result
      * @return an array of instance fields
@@ -245,9 +247,17 @@
     ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses);
 
     /**
+     * Returns the static fields of this class, including
+     * {@linkplain ResolvedJavaField#isInternal() internal} fields. A zero-length array is returned
+     * for array and primitive types. The order of fields returned by this method is stable. That
+     * is, for a single JVM execution the same order is returned each time this method is called.
+     */
+    ResolvedJavaField[] getStaticFields();
+
+    /**
      * Returns the annotation for the specified type of this class, if such an annotation is
      * present.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @return this element's annotation for the specified annotation type if present on this class,
      *         else {@code null}
@@ -257,7 +267,7 @@
     /**
      * Returns the instance field of this class (or one of its super classes) at the given offset,
      * or {@code null} if there is no such field.
-     * 
+     *
      * @param offset the offset of the field to look for
      * @return the field with the given offset, or {@code null} if there is no such field.
      */
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Fri May 30 15:09:09 2014 +0200
@@ -45,7 +45,7 @@
 
     /**
      * Initializes a new value of the specified kind.
-     * 
+     *
      * @param platformKind the kind
      */
     protected Value(PlatformKind platformKind) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodHandleAccessProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * 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.replacements;
+
+import java.lang.invoke.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Interface to access the internals of the {@link MethodHandle} implementation of the VM. An
+ * implementation of this interface is usually required to access non-public classes, methods, and
+ * fields of {@link MethodHandle}, i.e., data that is not standardized by the Java specification.
+ */
+public interface MethodHandleAccessProvider {
+
+    /**
+     * Identification for methods defined on the class {@link MethodHandle} that are processed by
+     * the {@link MethodHandleAccessProvider}.
+     */
+    public enum IntrinsicMethod {
+        /** The method {@code MethodHandle.invokeBasic}. */
+        INVOKE_BASIC,
+        /** The method {@code MethodHandle.linkToStatic}. */
+        LINK_TO_STATIC,
+        /** The method {@code MethodHandle.linkToSpecial}. */
+        LINK_TO_SPECIAL,
+        /** The method {@code MethodHandle.linkToVirtual}. */
+        LINK_TO_VIRTUAL,
+        /** The method {@code MethodHandle.linkToInterface}. */
+        LINK_TO_INTERFACE
+    }
+
+    /**
+     * Returns the method handle method intrinsic identifier for the provided method, or
+     * {@code null} if the method is not an intrinsic processed by this interface.
+     */
+    IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method);
+
+    /**
+     * Resolves the invocation target for an invocation of {@link IntrinsicMethod#INVOKE_BASIC
+     * MethodHandle.invokeBasic} with the given constant receiver {@link MethodHandle}. Returns
+     * {@code null} if the invocation target is not available at this time.
+     * <p>
+     * The first invocations of a method handle can use an interpreter to lookup the actual invoked
+     * method; frequently executed method handles can use Java bytecode generation to avoid the
+     * interpreter overhead. If the parameter forceBytecodeGeneration is set to true, the VM should
+     * try to generate bytecodes before this method returns.
+     */
+    ResolvedJavaMethod resolveInvokeBasicTarget(Constant methodHandle, boolean forceBytecodeGeneration);
+
+    /**
+     * Resolves the invocation target for an invocation of a {@code MethodHandle.linkTo*} method
+     * with the given constant member name. The member name is the last parameter of the
+     * {@code linkTo*} method. Returns {@code null} if the invocation target is not available at
+     * this time.
+     */
+    ResolvedJavaMethod resolveLinkToTarget(Constant memberName);
+}
--- a/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java	Fri May 30 15:09:09 2014 +0200
@@ -28,7 +28,7 @@
 
 public class Graal {
 
-    private static GraalRuntime runtime;
+    private static final GraalRuntime runtime;
 
     private static native GraalRuntime initializeRuntime();
 
@@ -47,12 +47,13 @@
     }
 
     static {
+        GraalRuntime rt;
         try {
-            runtime = initializeRuntime();
+            rt = initializeRuntime();
         } catch (UnsatisfiedLinkError e) {
-            runtime = new InvalidGraalRuntime();
+            rt = new InvalidGraalRuntime();
         }
-
+        runtime = rt;
         Reflection.registerFieldsToFilter(Graal.class, "runtime");
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Service.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.runtime;
+
+/**
+ * Denotes a service that may be efficiently loaded by {@link Services#load(Class)}.
+ */
+public interface Service {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Services.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.runtime;
+
+import static java.lang.String.*;
+
+import java.util.*;
+
+/**
+ * A mechanism on top of the standard {@link ServiceLoader} that enables a runtime to efficiently
+ * load services marked by {@link Service}. This may be important for services loaded early in the
+ * runtime initialization process.
+ */
+public class Services {
+
+    private static final ClassValue<List<Service>> cache = new ClassValue<List<Service>>() {
+        @Override
+        protected List<Service> computeValue(Class<?> type) {
+            Service[] names = getServiceImpls(type);
+            if (names == null || names.length == 0) {
+                throw new InternalError(format("No implementations for %s found (ensure %s extends %s)", type.getSimpleName(), type.getSimpleName(), Service.class));
+            }
+            return Arrays.asList(names);
+        }
+    };
+
+    /**
+     * Gets an {@link Iterable} of the implementations available for a given service.
+     */
+    @SuppressWarnings("unchecked")
+    public static <S> Iterable<S> load(Class<S> service) {
+        if (Service.class.isAssignableFrom(service)) {
+            try {
+                return (Iterable<S>) cache.get(service);
+            } catch (UnsatisfiedLinkError e) {
+                // Fall back to standard SerivceLoader
+            }
+        }
+        return ServiceLoader.loadInstalled(service);
+    }
+
+    private static native <S> S[] getServiceImpls(Class<?> service);
+}
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri May 30 15:09:09 2014 +0200
@@ -784,15 +784,39 @@
     }
 
     public final void idivl(Register src) {
-        int encode = prefixAndEncode(src.encoding);
+        int encode = prefixAndEncode(7, src.encoding);
         emitByte(0xF7);
-        emitByte(0xF8 | encode);
+        emitByte(0xC0 | encode);
     }
 
     public final void divl(Register src) {
-        int encode = prefixAndEncode(src.encoding);
+        int encode = prefixAndEncode(6, src.encoding);
+        emitByte(0xF7);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void mull(Register src) {
+        int encode = prefixAndEncode(4, src.encoding);
+        emitByte(0xF7);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void mull(AMD64Address src) {
+        prefix(src);
         emitByte(0xF7);
-        emitByte(0xF0 | encode);
+        emitOperandHelper(4, src);
+    }
+
+    public final void imull(Register src) {
+        int encode = prefixAndEncode(5, src.encoding);
+        emitByte(0xF7);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void imull(AMD64Address src) {
+        prefix(src);
+        emitByte(0xF7);
+        emitOperandHelper(5, src);
     }
 
     public final void imull(Register dst, Register src) {
@@ -1647,9 +1671,14 @@
     public final void shrl(Register dst, int imm8) {
         assert isShiftCount(imm8) : "illegal shift count";
         int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xC1);
-        emitByte(0xE8 | encode);
-        emitByte(imm8);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xE8 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xE8 | encode);
+            emitByte(imm8);
+        }
     }
 
     public final void shrl(Register dst) {
@@ -1658,6 +1687,82 @@
         emitByte(0xE8 | encode);
     }
 
+    public final void roll(Register dst, int imm8) {
+        assert isShiftCount(imm8) : "illegal shift count";
+        int encode = prefixAndEncode(dst.encoding);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xC0 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xC0 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void roll(Register dst) {
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void rorl(Register dst, int imm8) {
+        assert isShiftCount(imm8) : "illegal shift count";
+        int encode = prefixAndEncode(dst.encoding);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xC8 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xC8 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void rorl(Register dst) {
+        int encode = prefixAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xC8 | encode);
+    }
+
+    public final void rolq(Register dst, int imm8) {
+        assert isShiftCount(imm8) : "illegal shift count";
+        int encode = prefixqAndEncode(dst.encoding);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xC0 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xC0 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void rolq(Register dst) {
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void rorq(Register dst, int imm8) {
+        assert isShiftCount(imm8) : "illegal shift count";
+        int encode = prefixqAndEncode(dst.encoding);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xC8 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xC8 | encode);
+            emitByte(imm8);
+        }
+    }
+
+    public final void rorq(Register dst) {
+        int encode = prefixqAndEncode(dst.encoding);
+        emitByte(0xD3);
+        emitByte(0xC8 | encode);
+    }
+
     public final void sqrtsd(Register dst, AMD64Address src) {
         assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
@@ -1755,7 +1860,7 @@
     }
 
     public final void testl(AMD64Address dst, int imm32) {
-        prefixq(dst);
+        prefix(dst);
         emitByte(0xF7);
         emitOperandHelper(0, dst);
         emitInt(imm32);
@@ -2265,15 +2370,39 @@
     }
 
     public final void divq(Register src) {
-        int encode = prefixqAndEncode(src.encoding);
+        int encode = prefixqAndEncode(6, src.encoding);
         emitByte(0xF7);
-        emitByte(0xF0 | encode);
+        emitByte(0xC0 | encode);
     }
 
     public final void idivq(Register src) {
-        int encode = prefixqAndEncode(src.encoding);
+        int encode = prefixqAndEncode(7, src.encoding);
+        emitByte(0xF7);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void mulq(Register src) {
+        int encode = prefixqAndEncode(4, src.encoding);
+        emitByte(0xF7);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void mulq(AMD64Address src) {
+        prefixq(src);
         emitByte(0xF7);
-        emitByte(0xF8 | encode);
+        emitOperandHelper(4, src);
+    }
+
+    public final void imulq(Register src) {
+        int encode = prefixqAndEncode(5, src.encoding);
+        emitByte(0xF7);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void imulq(AMD64Address src) {
+        prefixq(src);
+        emitByte(0xF7);
+        emitOperandHelper(5, src);
     }
 
     public final void imulq(Register dst, Register src) {
@@ -2442,9 +2571,14 @@
     public final void shrq(Register dst, int imm8) {
         assert isShiftCount(imm8 >> 1) : "illegal shift count";
         int encode = prefixqAndEncode(dst.encoding);
-        emitByte(0xC1);
-        emitByte(0xE8 | encode);
-        emitByte(imm8);
+        if (imm8 == 1) {
+            emitByte(0xD1);
+            emitByte(0xE8 | encode);
+        } else {
+            emitByte(0xC1);
+            emitByte(0xE8 | encode);
+            emitByte(imm8);
+        }
     }
 
     public final void shrq(Register dst) {
@@ -2512,6 +2646,32 @@
         emitInt(imm32);
     }
 
+    public final void xaddl(AMD64Address dst, Register src) {
+        prefix(dst, src);
+        emitByte(0x0F);
+        emitByte(0xC1);
+        emitOperandHelper(src, dst);
+    }
+
+    public final void xaddq(AMD64Address dst, Register src) {
+        prefixq(dst, src);
+        emitByte(0x0F);
+        emitByte(0xC1);
+        emitOperandHelper(src, dst);
+    }
+
+    public final void xchgl(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x87);
+        emitOperandHelper(dst, src);
+    }
+
+    public final void xchgq(Register dst, AMD64Address src) {
+        prefixq(src, dst);
+        emitByte(0x87);
+        emitOperandHelper(dst, src);
+    }
+
     public final void xorq(Register dst, int imm32) {
         emitArithImm32q(6, dst, imm32);
     }
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri May 30 15:09:09 2014 +0200
@@ -79,6 +79,14 @@
         }
     }
 
+    public final void movptr(Register dst, AMD64Address src) {
+        movq(dst, src);
+    }
+
+    public final void movptr(AMD64Address dst, Register src) {
+        movq(dst, src);
+    }
+
     public final void movptr(AMD64Address dst, int src) {
         movslq(dst, src);
     }
@@ -277,7 +285,7 @@
     /**
      * Emit code to save a given set of callee save registers in the {@linkplain CalleeSaveLayout
      * CSA} within the frame.
-     * 
+     *
      * @param csl the description of the CSA
      * @param frameToCSA offset from the frame pointer to the CSA
      */
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Fri May 30 15:09:09 2014 +0200
@@ -136,6 +136,11 @@
         emitAddrOp("lda_global_u64", dest, addr);
     }
 
+    public final void emitLea(Value dest, HSAILAddress addr) {
+        String prefix = getArgType(dest);
+        emitString(String.format("add_%s %s, $%s, 0x%s;", prefix, HSAIL.mapRegister(dest), addr.getBase().name, Long.toHexString(addr.getDisplacement())));
+    }
+
     public final void emitLoadKernelArg(Value dest, String kernArgName, String argTypeStr) {
         emitString("ld_kernarg_" + argTypeStr + " " + HSAIL.mapRegister(dest) + ", [" + kernArgName + "];");
     }
@@ -185,16 +190,9 @@
         emitString("st_spill_" + getArgTypeFromKind(kind) + " " + HSAIL.mapRegister(src) + ", " + mapStackSlot(dest, getArgSizeFromKind(kind)) + ";");
     }
 
-    /**
-     * The mapping to stack slots is always relative to the beginning of the spillseg.
-     * HSAIL.getStackOffset returns the positive version of the originally negative offset. Then we
-     * back up from that by the argSize in bytes. This ensures that slots of different size do not
-     * overlap, even though we have converted from negative to positive offsets.
-     */
     public static String mapStackSlot(Value reg, int argSize) {
-        long offset = HSAIL.getStackOffset(reg);
-        int argSizeBytes = argSize / 8;
-        return "[%spillseg]" + "[" + (offset - argSizeBytes) + "]";
+        long startOffset = HSAIL.getStackOffsetStart(reg, argSize);
+        return "[%spillseg]" + "[" + startOffset + "]";
     }
 
     public void cbr(String target1) {
@@ -250,6 +248,9 @@
             case Byte:
                 prefix = "s8";
                 break;
+            case Boolean:
+                prefix = "u8";
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -548,6 +549,17 @@
     }
 
     /**
+     * Emits an atomic_exch_global instruction.
+     *
+     * @param result result operand that gets the original contents of the memory location
+     * @param address the memory location
+     * @param newValue the new value to write to the memory location
+     */
+    public void emitAtomicExch(Kind accessKind, AllocatableValue result, HSAILAddress address, Value newValue) {
+        emitString(String.format("atomic_exch_global_b%d   %s, %s, %s;", getArgSizeFromKind(accessKind), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(newValue)));
+    }
+
+    /**
      * Emits a comment. Useful for debugging purposes.
      *
      * @param comment
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Fri May 30 15:09:09 2014 +0200
@@ -30,11 +30,6 @@
 
 public class SPARCAddress extends AbstractAddress {
 
-    /**
-     * Stack bias for stack and frame pointer loads.
-     */
-    private static final int STACK_BIAS = 0x7ff;
-
     private final Register base;
     private final Register index;
     private final int displacement;
@@ -42,7 +37,7 @@
     /**
      * Creates an {@link SPARCAddress} with given base register, no scaling and a given
      * displacement.
-     * 
+     *
      * @param base the base register
      * @param displacement the displacement
      */
@@ -54,7 +49,7 @@
 
     /**
      * Creates an {@link SPARCAddress} with given base register, no scaling and a given index.
-     * 
+     *
      * @param base the base register
      * @param index the index register
      */
@@ -113,7 +108,7 @@
     /**
      * This method adds the stack-bias to the displacement if the base register is either
      * {@link SPARC#sp} or {@link SPARC#fp}.
-     * 
+     *
      * @return Optional additive displacement.
      */
     public int getDisplacement() {
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri May 30 15:09:09 2014 +0200
@@ -1007,7 +1007,7 @@
         Wrreg(0x30, "wrreg"),
         Saved(0x31, "saved"),
 
-        Fpop1(0x34, "fpop1"),
+        Fpop1(0b11_0100, "fpop1"),
         Fpop2(0x35, "fpop2"),
         Impdep1(0x36, "impdep1"),
         Impdep2(0x37, "impdep2"),
@@ -1036,14 +1036,14 @@
         Ldx(0b001011, "ldx"),
         Stx(0b001110, "stx"),
 
-        Ldf(0x20, "ldf"),
+        Ldf(0b100000, "ldf"),
         Ldfsr(0x21, "ldfsr"),
         Ldaf(0x22, "ldaf"),
-        Lddf(0x23, "lddf"),
-        Stf(0x24, "stf"),
+        Lddf(0b100011, "lddf"),
+        Stf(0b100100, "stf"),
         Stfsr(0x25, "stfsr"),
         Staf(0x26, "staf"),
-        Stdf(0x27, "stdf");
+        Stdf(0b100111, "stdf");
 
         // @formatter:on
 
@@ -1092,9 +1092,9 @@
     public enum Opfs {
         // @formatter:off
 
-        Fmovs(0x01, "fmovs"),
-        Fmovd(0x02, "fmovd"),
-        Fmovq(0x03, "fmovq"),
+        Fmovs(0b0_0000_0001, "fmovs"),
+        Fmovd(0b0_0000_0010, "fmovd"),
+        Fmovq(0b0_0000_0011, "fmovq"),
         Fnegs(0x05, "fnegs"),
         Fnegd(0x06, "fnegd"),
         Fnegq(0x07, "fnegq"),
@@ -2438,6 +2438,20 @@
         }
     }
 
+    public static class Fmovs extends Fmt3p {
+
+        public Fmovs(Register src, Register dst) {
+            super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovs, g0, src, dst);
+        }
+    }
+
+    public static class Fmovd extends Fmt3p {
+
+        public Fmovd(Register src, Register dst) {
+            super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovd, g0, src, dst);
+        }
+    }
+
     public static class Fmuls extends Fmt3p {
 
         public Fmuls(Register src1, Register src2, Register dst) {
@@ -3242,6 +3256,20 @@
         }
     }
 
+    public static class Stdf extends Fmt11 {
+
+        public Stdf(Register dst, SPARCAddress src) {
+            super(Op3s.Stdf, src, dst);
+        }
+    }
+
+    public static class Stf extends Fmt11 {
+
+        public Stf(Register dst, SPARCAddress src) {
+            super(Op3s.Stf, src, dst);
+        }
+    }
+
     public static class Sth extends Fmt11 {
 
         public Sth(Register dst, SPARCAddress addr) {
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,7 +48,7 @@
 
     /**
      * Closes this buffer. No extra data can be written to this buffer after this call.
-     * 
+     *
      * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
      *            including) {@code position()} is returned
      * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
@@ -68,7 +68,7 @@
 
     /**
      * Copies the data from this buffer into a given array.
-     * 
+     *
      * @param dst the destination array
      * @param off starting position in {@code dst}
      * @param len number of bytes to copy
@@ -114,7 +114,7 @@
     }
 
     public int emitByte(int b, int pos) {
-        assert NumUtil.isUByte(b);
+        assert NumUtil.isUByte(b) || NumUtil.isByte(b);
         int newPos = pos + 1;
         ensureSize(newPos);
         data[pos] = (byte) (b & 0xFF);
@@ -139,7 +139,7 @@
 
         @Override
         public int emitShort(int b, int pos) {
-            assert NumUtil.isUShort(b);
+            assert NumUtil.isUShort(b) || NumUtil.isShort(b);
             int newPos = pos + 2;
             ensureSize(pos + 2);
             data[pos] = (byte) ((b >> 8) & 0xFF);
@@ -188,7 +188,7 @@
 
         @Override
         public int emitShort(int b, int pos) {
-            assert NumUtil.isUShort(b);
+            assert NumUtil.isUShort(b) || NumUtil.isShort(b);
             int newPos = pos + 2;
             ensureSize(newPos);
             data[pos] = (byte) (b & 0xFF);
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,7 @@
  */
 package com.oracle.graal.baseline;
 
-import static com.oracle.graal.phases.GraalOptions.*;
-import static java.lang.reflect.Modifier.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
@@ -36,6 +35,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
@@ -45,13 +45,12 @@
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.phases.*;
 
-public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, LIRFrameStateBuilder> implements BytecodeParserTool {
+public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, BaselineFrameStateBuilder> implements BytecodeParserTool {
     private Backend backend;
-    protected LIRGenerator gen;
+    protected LIRGeneratorTool gen;
     private LIRGenerationResult lirGenRes;
     private BytecodeLIRBuilder lirBuilder;
     @SuppressWarnings("unused") private BciBlock[] loopHeaders;
@@ -75,7 +74,7 @@
     }
 
     public BaselineBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
-                    LIRFrameStateBuilder frameState, BytecodeStream stream, ProfilingInfo profilingInfo, ConstantPool constantPool, int entryBCI, Backend backend) {
+                    BaselineFrameStateBuilder frameState, BytecodeStream stream, ProfilingInfo profilingInfo, ConstantPool constantPool, int entryBCI, Backend backend) {
 
         super(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, stream, profilingInfo, constantPool, entryBCI);
         this.backend = backend;
@@ -94,8 +93,14 @@
 
         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);
+            BciBlockMapping blockMap;
+            try (Scope ds = Debug.scope("BciBlockMapping")) {
+                // compute the block map, setup exception handlers and get the entrypoint(s)
+                blockMap = BciBlockMapping.create(method);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+
             loopHeaders = blockMap.loopHeaders;
             liveness = blockMap.liveness;
             blockVisited = new BciBlockBitMap(blockMap);
@@ -106,11 +111,11 @@
                 }
             }
 
-            if (isSynchronized(method.getModifiers())) {
+            if (method.isSynchronized()) {
                 throw GraalInternalError.unimplemented("Handle synchronized methods");
             }
 
-            frameState = new LIRFrameStateBuilder(method);
+            frameState = new BaselineFrameStateBuilder(method);
             frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
 
             currentBlock = blockMap.startBlock;
@@ -122,22 +127,17 @@
             // add loops ? how do we add looks when we haven't parsed the bytecode?
 
             // create the control flow graph
-            LIRControlFlowGraph cfg = new LIRControlFlowGraph(blockMap);
-
-            BlocksToDoubles blockProbabilities = new BlocksToDoubles(blockMap.blocks.size());
-            for (BciBlock b : blockMap.blocks) {
-                blockProbabilities.put(b, 1);
-            }
+            BaselineControlFlowGraph cfg = BaselineControlFlowGraph.compute(blockMap);
 
             // 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);
+            List<? extends AbstractBlock<?>> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.blocks.size(), blockMap.startBlock);
+            List<? extends AbstractBlock<?>> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.blocks.size(), blockMap.startBlock);
             LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder);
 
             FrameMap frameMap = backend.newFrameMap(null);
             TargetDescription target = backend.getTarget();
             CallingConvention cc = CodeUtil.getCallingConvention(backend.getProviders().getCodeCache(), CallingConvention.Type.JavaCallee, method, false);
-            this.lirGenRes = backend.newLIRGenerationResult(lir, frameMap, null);
+            this.lirGenRes = backend.newLIRGenerationResult(lir, frameMap, method, null);
             this.gen = backend.newLIRGenerator(cc, lirGenRes);
             this.lirBuilder = backend.newBytecodeLIRBuilder(gen, this);
 
@@ -441,13 +441,13 @@
     }
 
     @Override
-    protected Value genCheckCast(ResolvedJavaType type, Value object, JavaTypeProfile profileForTypeCheck, boolean b) {
+    protected Value createCheckCast(ResolvedJavaType type, Value object, JavaTypeProfile profileForTypeCheck, boolean b) {
         // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented("Auto-generated method stub");
     }
 
     @Override
-    protected Value genInstanceOf(ResolvedJavaType type, Value object, JavaTypeProfile profileForTypeCheck) {
+    protected Value createInstanceOf(ResolvedJavaType type, Value object, JavaTypeProfile profileForTypeCheck) {
         // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented("Auto-generated method stub");
     }
@@ -478,14 +478,21 @@
 
     @Override
     protected Value genLoadField(Value receiver, ResolvedJavaField field) {
+        if (field.isStatic()) {
+            Value classRef = lirBuilder.getClassConstant(field.getDeclaringClass());
+            long displacement = lirBuilder.getFieldOffset(field);
+            Value address = gen.emitAddress(classRef, displacement, Value.ILLEGAL, 0);
+            PlatformKind readKind = gen.getPlatformKind(StampFactory.forKind(field.getKind()));
+            LIRFrameState state = createFrameState(frameState);
+            return gen.emitLoad(readKind, address, state);
+        }
         // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented("Auto-generated method stub");
     }
 
     @Override
     protected void emitNullCheck(Value receiver) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
+        gen.emitNullCheck(receiver, createFrameState(frameState));
     }
 
     @Override
@@ -495,9 +502,38 @@
     }
 
     @Override
-    protected Value genArrayLength(Value x) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
+    protected Value genArrayLength(Value array) {
+        emitNullCheck(array);
+        long displacement = lirBuilder.getArrayLengthOffset();
+        Value address = gen.emitAddress(array, displacement, Value.ILLEGAL, 0);
+        PlatformKind readKind = gen.getPlatformKind(StampFactory.forKind(Kind.Int));
+        LIRFrameState state = createFrameState(frameState);
+        return gen.emitLoad(readKind, address, state);
+    }
+
+    private LIRFrameState createFrameState(BaselineFrameStateBuilder state) {
+        LabelRef exceptionEdge = null;
+        BytecodeFrame caller = null;
+        boolean duringCall = false;
+        int numLocals = state.localsSize();
+        int numStack = state.stackSize();
+        int numLocks = state.lockDepth();
+        Value[] values = new Value[numLocals + numStack + numLocks];
+
+        for (int i = 0; i < numLocals; i++) {
+            values[i] = state.localAt(i);
+        }
+
+        for (int i = 0; i < numStack; i++) {
+            values[numLocals + i] = state.stackAt(i);
+        }
+
+        for (int i = 0; i < numStack; i++) {
+            values[numLocals + numStack + i] = state.lockAt(i);
+        }
+
+        BytecodeFrame frame = new BytecodeFrame(caller, method, bci(), state.rethrowException(), duringCall, values, numLocals, numStack, numLocks);
+        return new LIRFrameState(frame, null, exceptionEdge);
     }
 
     @Override
@@ -609,7 +645,7 @@
         }
 
         // We already saw this block before, so we have to merge states.
-        if (!((LIRFrameStateBuilder) block.entryState).isCompatibleWith(frameState)) {
+        if (!((BaselineFrameStateBuilder) block.entryState).isCompatibleWith(frameState)) {
             throw new BailoutException("stacks do not match; bytecodes would not verify");
         }
 
@@ -617,7 +653,7 @@
             assert currentBlock == null || currentBlock.getId() >= block.getId() : "must be backward branch";
             if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) {
                 // this is the only successor of the current block so we can adjust
-                adaptFramestate((LIRFrameStateBuilder) block.entryState);
+                adaptFramestate((BaselineFrameStateBuilder) block.entryState);
                 return;
             }
             GraalInternalError.unimplemented("Loops not yet supported");
@@ -631,7 +667,7 @@
          */
         if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) {
             // this is the only successor of the current block so we can adjust
-            adaptFramestate((LIRFrameStateBuilder) block.entryState);
+            adaptFramestate((BaselineFrameStateBuilder) block.entryState);
             return;
         }
         GraalInternalError.unimplemented("second block visit not yet implemented");
@@ -675,7 +711,7 @@
         }
     }
 
-    private void adaptFramestate(LIRFrameStateBuilder other) {
+    private void adaptFramestate(BaselineFrameStateBuilder other) {
         assert frameState.isCompatibleWith(other) : "framestates not compatible!";
         PhiResolver resolver = new PhiResolver(gen);
         for (int i = 0; i < frameState.stackSize(); i++) {
@@ -693,7 +729,7 @@
 
     @Override
     protected void processBlock(BciBlock block) {
-        frameState = (LIRFrameStateBuilder) block.entryState;
+        frameState = (BaselineFrameStateBuilder) block.entryState;
         setCurrentFrameState(frameState);
         currentBlock = block;
         iterateBytecodesForBlock(block);
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.baseline;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -57,7 +57,7 @@
         ConstantPool constantPool = method.getConstantPool();
         TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
 
-        LIRFrameStateBuilder frameState = new LIRFrameStateBuilder(method);
+        BaselineFrameStateBuilder frameState = new BaselineFrameStateBuilder(method);
 
         BaselineBytecodeParser parser = new BaselineBytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, stream, profilingInfo, constantPool, entryBCI, backend);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineControlFlowGraph.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.baseline;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+
+public class BaselineControlFlowGraph implements AbstractControlFlowGraph<BciBlock> {
+
+    private List<BciBlock> blocks;
+    private Collection<Loop<BciBlock>> loops;
+
+    public static BaselineControlFlowGraph compute(BciBlockMapping blockMap) {
+        try (Scope ds = Debug.scope("BaselineCFG", blockMap)) {
+            BaselineControlFlowGraph cfg = new BaselineControlFlowGraph(blockMap);
+            cfg.computeLoopInformation(blockMap);
+            return cfg;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private BaselineControlFlowGraph(BciBlockMapping blockMap) {
+        blocks = blockMap.blocks;
+        loops = new ArrayList<>();
+    }
+
+    public List<BciBlock> getBlocks() {
+        return blocks;
+    }
+
+    public Collection<Loop<BciBlock>> getLoops() {
+        return loops;
+    }
+
+    public BciBlock getStartBlock() {
+        if (!blocks.isEmpty()) {
+            return blocks.get(0);
+        }
+        return null;
+    }
+
+    private void computeLoopInformation(BciBlockMapping blockMap) {
+        try (Indent indent = Debug.logAndIndent("computeLoopInformation")) {
+            for (BciBlock block : blocks) {
+                calcLoop(block, blockMap);
+                Debug.log("Block: %s, Loop: %s", block, block.getLoop());
+            }
+        }
+    }
+
+    private Loop<BciBlock> getLoop(int index, BciBlockMapping blockMap) {
+        BciBlock header = blockMap.getLoopHeader(index);
+        assert header.getLoopDepth() > 0;
+        Loop<BciBlock> loop = header.getLoop();
+
+        if (loop == null) {
+            Loop<BciBlock> parent = null;
+
+            if (header.getLoopDepth() > 1) {
+                // Recursively create out loops.
+                Iterator<Integer> i = header.loopIdIterable().iterator();
+                assert i.hasNext() : "BciBlock.loopIdIterable() must return exactly BciBlock.getLoopDepth() elements!";
+                int outerLoopId = i.next();
+                assert index == outerLoopId : "The first loopId must be the id of the loop that is started by this header!";
+                assert i.hasNext() : "BciBlock.loopIdIterable() must return exactly BciBlock.getLoopDepth() elements!";
+                outerLoopId = i.next();
+                parent = getLoop(outerLoopId, blockMap);
+            }
+
+            loop = new BaselineLoop(parent, index, header);
+            loops.add(loop);
+            header.setLoop(loop);
+        }
+        return loop;
+    }
+
+    private void calcLoop(BciBlock block, BciBlockMapping blockMap) {
+        int loopId = block.getLoopId();
+        if (loopId != -1) {
+            block.setLoop(getLoop(loopId, blockMap));
+
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineFrameStateBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.baseline;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.*;
+
+public class BaselineFrameStateBuilder extends AbstractFrameStateBuilder<Value, BaselineFrameStateBuilder> {
+
+    private static final Value[] EMPTY_ARRAY = new Value[0];
+
+    public BaselineFrameStateBuilder(ResolvedJavaMethod method) {
+        // we always need at least one stack slot (for exceptions)
+        super(method, new Value[method.getMaxLocals()], new Value[Math.max(1, method.getMaxStackSize())], EMPTY_ARRAY);
+    }
+
+    protected BaselineFrameStateBuilder(BaselineFrameStateBuilder other) {
+        super(other);
+    }
+
+    @Override
+    protected Value[] getEmtpyArray() {
+        return EMPTY_ARRAY;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[locals: [");
+        for (int i = 0; i < locals.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString());
+        }
+        sb.append("] stack: [");
+        for (int i = 0; i < stackSize; i++) {
+            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString());
+        }
+        sb.append("] locks: [");
+        for (int i = 0; i < lockedObjects.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString());
+        }
+        sb.append("]");
+        if (rethrowException) {
+            sb.append(" rethrowException");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    @Override
+    public BaselineFrameStateBuilder copy() {
+        return new BaselineFrameStateBuilder(this);
+    }
+
+    private static boolean isCompatible(Value x, Value y) {
+        if (x == null && y == null) {
+            return true;
+        }
+        if ((x == null || y == null) || (x.getKind() != y.getKind())) {
+            return false;
+        }
+        return true;
+
+    }
+
+    @Override
+    public boolean isCompatibleWith(BaselineFrameStateBuilder other) {
+        assert method.equals(other.method) && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
+
+        if (stackSize() != other.stackSize()) {
+            return false;
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            if (!isCompatible(stackAt(i), other.stackAt(i))) {
+                return false;
+            }
+        }
+        if (lockedObjects.length != other.lockedObjects.length) {
+            return false;
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineLoop.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.baseline;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+
+public class BaselineLoop extends Loop<BciBlock> {
+
+    protected BaselineLoop(Loop<BciBlock> parent, int index, BciBlock header) {
+        super(parent, index, header);
+    }
+
+    @Override
+    public long numBackedges() {
+        // currently only loops with one backedge are supported
+        return 1;
+    }
+
+}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.baseline;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-
-public class LIRBlock extends AbstractBlockBase<LIRBlock> {
-
-    public LIRBlock(int id) {
-        this.id = id;
-        predecessors = Collections.emptyList();
-        successors = Collections.emptyList();
-    }
-
-    public Loop<LIRBlock> getLoop() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public int getLoopDepth() {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    public boolean isLoopEnd() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    public boolean isLoopHeader() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    public boolean isExceptionEntry() {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.baseline;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-
-public class LIRControlFlowGraph implements AbstractControlFlowGraph<BciBlock> {
-
-    private BciBlock[] blocks;
-    private Collection<Loop<BciBlock>> loops;
-    private BitSet visited;
-
-    public LIRControlFlowGraph(BciBlockMapping blockMap) {
-        blocks = blockMap.blocks.toArray(new BciBlock[0]);
-        loops = new ArrayList<>();
-        computeLoopInformation();
-    }
-
-    public BciBlock[] getBlocks() {
-        return blocks;
-    }
-
-    public Collection<Loop<BciBlock>> getLoops() {
-        return loops;
-    }
-
-    public BciBlock getStartBlock() {
-        if (blocks.length > 0) {
-            return blocks[0];
-        }
-        return null;
-    }
-
-    private void computeLoopInformation() {
-        visited = new BitSet(blocks.length);
-        Deque<LIRLoop> stack = new ArrayDeque<>();
-        for (int i = blocks.length - 1; i >= 0; i--) {
-            BciBlock block = blocks[i];
-            calcLoop(block, stack);
-        }
-    }
-
-    private void calcLoop(BciBlock block, Deque<LIRLoop> stack) {
-        if (visited.get(block.getId())) {
-            return;
-        }
-        visited.set(block.getId());
-        if (block.isLoopEnd()) {
-            BciBlock loopHeader = getLoopHeader(block);
-            LIRLoop l = new LIRLoop(stack.peek(), loops.size(), loopHeader);
-            loops.add(l);
-            stack.push(l);
-        }
-        block.loop = stack.peek();
-        if (block.isLoopHeader()) {
-            assert block.loop.header.equals(block);
-            stack.pop();
-        }
-        for (BciBlock pred : block.getPredecessors()) {
-            calcLoop(pred, stack);
-        }
-    }
-
-    private static BciBlock getLoopHeader(BciBlock block) {
-        assert block.isLoopEnd();
-        for (BciBlock sux : block.getSuccessors()) {
-            if (sux.isLoopHeader() && sux.getId() <= block.getId() && block.loops == sux.loops) {
-                return sux;
-            }
-        }
-        throw GraalInternalError.shouldNotReachHere("No loop header found for " + block);
-    }
-
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRFrameStateBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.baseline;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.*;
-
-public class LIRFrameStateBuilder extends AbstractFrameStateBuilder<Value, LIRFrameStateBuilder> {
-
-    private static final Value[] EMPTY_ARRAY = new Value[0];
-
-    public LIRFrameStateBuilder(ResolvedJavaMethod method) {
-        // we always need at least one stack slot (for exceptions)
-        super(method, new Value[method.getMaxLocals()], new Value[Math.max(1, method.getMaxStackSize())], EMPTY_ARRAY);
-    }
-
-    protected LIRFrameStateBuilder(LIRFrameStateBuilder other) {
-        super(other);
-    }
-
-    @Override
-    protected Value[] getEmtpyArray() {
-        return EMPTY_ARRAY;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[locals: [");
-        for (int i = 0; i < locals.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString());
-        }
-        sb.append("] stack: [");
-        for (int i = 0; i < stackSize; i++) {
-            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString());
-        }
-        sb.append("] locks: [");
-        for (int i = 0; i < lockedObjects.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString());
-        }
-        sb.append("]");
-        if (rethrowException) {
-            sb.append(" rethrowException");
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    @Override
-    public LIRFrameStateBuilder copy() {
-        return new LIRFrameStateBuilder(this);
-    }
-
-    private static boolean isCompatible(Value x, Value y) {
-        if (x == null && y == null) {
-            return true;
-        }
-        if ((x == null || y == null) || (x.getKind() != y.getKind())) {
-            return false;
-        }
-        return true;
-
-    }
-
-    @Override
-    public boolean isCompatibleWith(LIRFrameStateBuilder other) {
-        assert method.equals(other.method) && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
-
-        if (stackSize() != other.stackSize()) {
-            return false;
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            if (!isCompatible(stackAt(i), other.stackAt(i))) {
-                return false;
-            }
-        }
-        if (lockedObjects.length != other.lockedObjects.length) {
-            return false;
-        }
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRLoop.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.baseline;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-
-public class LIRLoop extends Loop<BciBlock> {
-
-    protected LIRLoop(Loop<BciBlock> parent, int index, BciBlock header) {
-        super(parent, index, header);
-    }
-
-    @Override
-    public long numBackedges() {
-        // currently only loops with one backedge are supported
-        return 1;
-    }
-
-}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -37,7 +37,7 @@
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
@@ -52,6 +52,7 @@
 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.AMD64Arithmetic.Unary2RegOp;
 import com.oracle.graal.lir.amd64.AMD64Compare.CompareMemoryOp;
 import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
@@ -68,9 +69,7 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp;
 import com.oracle.graal.lir.amd64.AMD64Move.ZeroExtendLoadOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -98,20 +97,14 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c, boolean isCompressed) {
+    public boolean canStoreConstant(Constant c) {
         // there is no immediate move of 64-bit constants on Intel
         switch (c.getKind()) {
             case Long:
-                if (isCompressed) {
-                    return true;
-                }
                 return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c);
             case Double:
                 return false;
             case Object:
-                if (isCompressed) {
-                    return true;
-                }
                 return c.isNull();
             default:
                 return true;
@@ -132,13 +125,7 @@
 
     @Override
     public Variable emitMove(Value input) {
-        PlatformKind kind;
-        if (input instanceof Constant) {
-            kind = input.getKind().getStackKind();
-        } else {
-            kind = input.getPlatformKind();
-        }
-        Variable result = newVariable(kind);
+        Variable result = newVariable(input.getPlatformKind());
         emitMove(result, input);
         return result;
     }
@@ -249,18 +236,21 @@
     public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
         boolean mirrored = emitCompare(cmpKind, left, right);
         Condition finalCondition = mirrored ? cond.mirror() : cond;
-        switch (left.getKind().getStackKind()) {
-            case Int:
-            case Long:
-            case Object:
-                append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-                break;
-            case Float:
-            case Double:
-                append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("" + left.getKind());
+        if (cmpKind == Kind.Float || cmpKind == Kind.Double) {
+            append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+        } else {
+            append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+        }
+    }
+
+    public void emitCompareBranchMemory(Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        boolean mirrored = emitCompareMemory(cmpKind, left, right, state);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        if (cmpKind == Kind.Float || cmpKind == Kind.Double) {
+            append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+        } else {
+            append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
         }
     }
 
@@ -281,18 +271,10 @@
         Condition finalCondition = mirrored ? cond.mirror() : cond;
 
         Variable result = newVariable(trueValue.getKind());
-        switch (left.getKind().getStackKind()) {
-            case Int:
-            case Long:
-            case Object:
-                append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
-                break;
-            case Float:
-            case Double:
-                append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("" + left.getKind());
+        if (cmpKind == Kind.Float || cmpKind == Kind.Double) {
+            append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
+        } else {
+            append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
         }
         return result;
     }
@@ -344,7 +326,27 @@
         }
     }
 
-    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Value value, LIRFrameState state) {
+    /**
+     * This method emits the compare against memory instruction, and may reorder the operands. It
+     * returns true if it did so.
+     *
+     * @param b the right operand of the comparison
+     * @return true if the left and right operands were switched, false otherwise
+     */
+    private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) {
+        boolean mirrored;
+        if (LIRValueUtil.isVariable(a)) {
+            Variable left = load(a);
+            emitCompareRegMemoryOp(cmpKind, left, b, state);
+            mirrored = false;
+        } else {
+            emitCompareMemoryConOp(cmpKind, b, (Constant) a, state);
+            mirrored = true;
+        }
+        return mirrored;
+    }
+
+    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Constant value, LIRFrameState state) {
         assert kind.getStackKind() == value.getKind().getStackKind();
         switch (kind) {
             case Byte:
@@ -361,6 +363,10 @@
             case Long:
                 append(new CompareMemoryOp(LCMP, kind, address, value, state));
                 break;
+            case Object:
+                assert value.isNull();
+                append(new CompareMemoryOp(ACMP, kind, address, value, state));
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -563,7 +569,38 @@
         }
     }
 
-    protected Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+    private Value emitMulHigh(AMD64Arithmetic opcode, Value a, Value b) {
+        MulHighOp mulHigh = new MulHighOp(opcode, asAllocatable(b));
+        emitMove(mulHigh.x, a);
+        append(mulHigh);
+        return emitMove(mulHigh.highResult);
+    }
+
+    @Override
+    public Value emitMulHigh(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitMulHigh(IMUL, a, b);
+            case Long:
+                return emitMulHigh(LMUL, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitMulHigh(IUMUL, a, b);
+            case Long:
+                return emitMulHigh(LUMUL, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public 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;
@@ -589,8 +626,7 @@
         append(new DivRemOp(op, rax, asAllocatable(b), state));
     }
 
-    public Value[] emitIntegerDivRem(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Value[] emitIntegerDivRem(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
                 emitDivRem(IDIVREM, a, b, state);
@@ -604,13 +640,13 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                emitDivRem(IDIV, a, b, state(deopting));
+                emitDivRem(IDIV, a, b, state);
                 return emitMove(RAX_I);
             case Long:
-                emitDivRem(LDIV, a, b, state(deopting));
+                emitDivRem(LDIV, a, b, state);
                 return emitMove(RAX_L);
             case Float: {
                 Variable result = newVariable(a.getPlatformKind());
@@ -628,13 +664,13 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                emitDivRem(IREM, a, b, state(deopting));
+                emitDivRem(IREM, a, b, state);
                 return emitMove(RDX_I);
             case Long:
-                emitDivRem(LREM, a, b, state(deopting));
+                emitDivRem(LREM, a, b, state);
                 return emitMove(RDX_L);
             case Float: {
                 Variable result = newVariable(a.getPlatformKind());
@@ -652,8 +688,7 @@
     }
 
     @Override
-    public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
                 emitDivRem(IUDIV, a, b, state);
@@ -667,8 +702,7 @@
     }
 
     @Override
-    public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Variable emitURem(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
                 emitDivRem(IUREM, a, b, state);
@@ -765,9 +799,31 @@
         }
     }
 
-    private AllocatableValue emitConvert1Op(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) {
+    public Variable emitRol(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitShift(IROL, a, b);
+            case Long:
+                return emitShift(LROL, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public Variable emitRor(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitShift(IROR, a, b);
+            case Long:
+                return emitShift(LROR, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    private AllocatableValue emitConvert2RegOp(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) {
         Variable result = newVariable(kind);
-        append(new Unary1Op(op, result, input));
+        append(new Unary2RegOp(op, result, input));
         return result;
     }
 
@@ -850,7 +906,7 @@
     public Value emitNarrow(Value inputVal, int bits) {
         if (inputVal.getKind() == Kind.Long && bits <= 32) {
             // TODO make it possible to reinterpret Long as Int in LIR without move
-            return emitConvert1Op(Kind.Int, L2I, asAllocatable(inputVal));
+            return emitConvert2RegOp(Kind.Int, L2I, asAllocatable(inputVal));
         } else {
             return inputVal;
         }
@@ -1020,7 +1076,7 @@
     }
 
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         // a temp is needed for loading object constants
         boolean needsTemp = key.getKind() == Kind.Object;
         append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,497 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.compiler.amd64;
-
-import static com.oracle.graal.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.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-public class AMD64MemoryPeephole implements MemoryArithmeticLIRLowerer {
-    protected final AMD64NodeLIRBuilder gen;
-    protected List<ValueNode> deferredNodes;
-
-    protected AMD64MemoryPeephole(AMD64NodeLIRBuilder gen) {
-        this.gen = gen;
-    }
-
-    public Value setResult(ValueNode x, Value operand) {
-        return gen.setResult(x, operand);
-    }
-
-    @Override
-    public boolean memoryPeephole(Access access, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred) {
-        this.deferredNodes = deferred;
-        boolean result = operation.generate(this, access);
-        if (result) {
-            Debug.log("merge %s %s with %1s %s %s", access, access.asNode().stamp(), operation, result, access.asNode().graph().method());
-        } else {
-            Debug.log("can't merge %s %s with %1s", access, access.asNode().stamp(), operation);
-        }
-        this.deferredNodes = null;
-        return result;
-    }
-
-    protected LIRFrameState getState(Access access) {
-        if (access instanceof DeoptimizingNode) {
-            return gen.getLIRGenerator().state((DeoptimizingNode) access);
-        }
-        return null;
-    }
-
-    protected Kind getMemoryKind(Access access) {
-        return (Kind) gen.getLIRGenerator().getPlatformKind(access.asNode().stamp());
-    }
-
-    protected AMD64AddressValue makeAddress(Access access) {
-        return (AMD64AddressValue) access.accessLocation().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(access.object()));
-    }
-
-    protected Value emitBinaryMemory(AMD64Arithmetic op, boolean commutative, ValueNode x, ValueNode y, Access access) {
-        ValueNode other = x;
-        if (uncast(other) == access) {
-            if (commutative) {
-                other = y;
-            } else {
-                return null;
-            }
-        }
-        ensureEvaluated(other);
-        return gen.getLIRGenerator().emitBinaryMemory(op, getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(other)), makeAddress(access), getState(access));
-    }
-
-    /**
-     * Constants with multiple users need to be evaluated in the right location so that later users
-     * can pick up the operand. Make sure that happens when it needs to.
-     */
-    protected void ensureEvaluated(ValueNode node) {
-        evaluateDeferred(node);
-        evaluateDeferred();
-    }
-
-    protected void evaluateDeferred(ValueNode node) {
-        // Ensure the other input value has a generated value.
-        if (ConstantNodeRecordsUsages) {
-            if (!gen.hasOperand(node)) {
-                assert node instanceof ConstantNode : node;
-                ((ConstantNode) node).generate(gen);
-            }
-        }
-    }
-
-    protected void evaluateDeferred() {
-        if (deferredNodes != null) {
-            for (ValueNode node : deferredNodes) {
-                evaluateDeferred(node);
-            }
-        }
-    }
-
-    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
-        AMD64AddressValue address = makeAddress(access);
-        LIRFrameState state = getState(access);
-        evaluateDeferred();
-        return gen.getLIRGenerator().emitConvert2MemoryOp(kind, op, address, state);
-    }
-
-    @Override
-    public Value emitAddMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IADD, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LADD, true, x, y, access);
-            case Float:
-                return emitBinaryMemory(FADD, true, x, y, access);
-            case Double:
-                return emitBinaryMemory(DADD, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitSubMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(ISUB, false, x, y, access);
-            case Long:
-                return emitBinaryMemory(LSUB, false, x, y, access);
-            case Float:
-                return emitBinaryMemory(FSUB, false, x, y, access);
-            case Double:
-                return emitBinaryMemory(DSUB, false, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitMulMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IMUL, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LMUL, true, x, y, access);
-            case Float:
-                return emitBinaryMemory(FMUL, true, x, y, access);
-            case Double:
-                return emitBinaryMemory(DMUL, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitDivMemory(ValueNode x, ValueNode y, Access access) {
-        return null;
-    }
-
-    @Override
-    public Value emitRemMemory(ValueNode x, ValueNode y, Access access) {
-        return null;
-    }
-
-    @Override
-    public Value emitAndMemory(ValueNode x, ValueNode y, Access access) {
-        Kind kind = getMemoryKind(access);
-        switch (kind) {
-            case Int:
-                return emitBinaryMemory(IAND, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LAND, true, x, y, access);
-            case Short: {
-                ValueNode other = selectOtherInput(x, y, access);
-                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
-                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
-                    // Convert to unsigned load
-                    ensureEvaluated(other);
-                    return emitZeroExtendMemory(16, 32, access);
-                }
-                return null;
-            }
-            case Byte: {
-                if (OptFoldMemory.getValue()) {
-                    return null;
-                }
-                ValueNode other = selectOtherInput(x, y, access);
-                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
-                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
-                    // Convert to unsigned load
-                    ensureEvaluated(other);
-                    return emitConvert2MemoryOp(Kind.Int, MOV_B2UI, access);
-                }
-                return null;
-            }
-
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitOrMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IOR, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LOR, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitXorMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IXOR, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LXOR, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitReinterpretMemory(Stamp stamp, Access access) {
-        PlatformKind to = gen.getLIRGenerator().getPlatformKind(stamp);
-        Kind from = getMemoryKind(access);
-        assert to != from : "should have been eliminated";
-
-        /*
-         * Conversions between integer to floating point types require moves between CPU and FPU
-         * registers.
-         */
-        switch ((Kind) to) {
-            case Int:
-                switch (from) {
-                    case Float:
-                        return emitConvert2MemoryOp(to, MOV_F2I, access);
-                }
-                break;
-            case Long:
-                switch (from) {
-                    case Double:
-                        return emitConvert2MemoryOp(to, MOV_D2L, access);
-                }
-                break;
-            case Float:
-                switch (from) {
-                    case Int:
-                        return emitConvert2MemoryOp(to, MOV_I2F, access);
-                }
-                break;
-            case Double:
-                switch (from) {
-                    case Long:
-                        return emitConvert2MemoryOp(to, MOV_L2D, access);
-                }
-                break;
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
-
-    @Override
-    public Value emitFloatConvertMemory(FloatConvert op, Access access) {
-        switch (op) {
-            case D2F:
-                return emitConvert2MemoryOp(Kind.Float, D2F, access);
-            case D2I:
-                return emitConvert2MemoryOp(Kind.Int, D2I, access);
-            case D2L:
-                return emitConvert2MemoryOp(Kind.Long, D2L, access);
-            case F2D:
-                return emitConvert2MemoryOp(Kind.Double, F2D, access);
-            case F2I:
-                return emitConvert2MemoryOp(Kind.Int, F2I, access);
-            case F2L:
-                return emitConvert2MemoryOp(Kind.Long, F2L, access);
-            case I2D:
-                return emitConvert2MemoryOp(Kind.Double, I2D, access);
-            case I2F:
-                return emitConvert2MemoryOp(Kind.Float, I2F, access);
-            case L2D:
-                return emitConvert2MemoryOp(Kind.Double, L2D, access);
-            case L2F:
-                return emitConvert2MemoryOp(Kind.Float, L2F, access);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public Value emitSignExtendMemory(Access access, int fromBits, int toBits) {
-        assert fromBits <= toBits && toBits <= 64;
-        if (fromBits == toBits) {
-            return null;
-        } else if (toBits > 32) {
-            // sign extend to 64 bits
-            switch (fromBits) {
-                case 8:
-                    return emitConvert2MemoryOp(Kind.Long, B2L, access);
-                case 16:
-                    return emitConvert2MemoryOp(Kind.Long, S2L, access);
-                case 32:
-                    return emitConvert2MemoryOp(Kind.Long, I2L, access);
-                default:
-                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        } else {
-
-            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
-            switch (fromBits) {
-                case 8:
-                    return emitConvert2MemoryOp(Kind.Int, B2I, access);
-                case 16:
-                    return emitConvert2MemoryOp(Kind.Int, S2I, access);
-                case 32:
-                    return null;
-                default:
-                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        }
-    }
-
-    @Override
-    public Value emitNarrowMemory(int resultBits, Access access) {
-        // TODO
-        return null;
-    }
-
-    @Override
-    public Value emitZeroExtendMemory(int fromBits, int toBits, Access access) {
-        assert fromBits != toBits;
-        Kind memoryKind = getMemoryKind(access);
-        if (memoryKind.getBitCount() != fromBits && !memoryKind.isUnsigned()) {
-            // The memory being read from is signed and smaller than the result size so
-            // this is a sign extension to inputBits followed by a zero extension to resultBits
-            // which can't be expressed in a memory operation.
-            return null;
-        }
-        if (memoryKind == Kind.Short) {
-            memoryKind = Kind.Char;
-        }
-        evaluateDeferred();
-        return gen.getLIRGenerator().emitZeroExtendMemory(memoryKind, toBits, makeAddress(access), getState(access));
-    }
-
-    public boolean emitIfMemory(IfNode x, Access access) {
-        return emitBranchMemory(x.condition(), access, gen.getLIRBlock(x.trueSuccessor()), gen.getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
-    }
-
-    private boolean emitBranchMemory(LogicNode node, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        if (node instanceof IsNullNode) {
-            // can't do anything interesting.
-            return false;
-        } else if (node instanceof CompareNode) {
-            CompareNode compare = (CompareNode) node;
-            return emitCompareBranchMemory(compare, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else if (node instanceof LogicConstantNode) {
-            return false;
-        } else if (node instanceof IntegerTestNode) {
-            return emitIntegerTestBranchMemory((IntegerTestNode) node, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else {
-            throw GraalInternalError.unimplemented(node.toString());
-        }
-    }
-
-    public boolean emitCompareBranchMemory(CompareNode compare, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        return emitCompareBranchMemory(compare.x(), compare.y(), access, compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    public boolean emitIntegerTestBranchMemory(IntegerTestNode test, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        return emitIntegerTestBranchMemory(test.x(), test.y(), access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    private boolean emitIntegerTestBranchMemory(ValueNode left, ValueNode right, Access access, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
-        ValueNode other = selectOtherInput(left, right, access);
-        Kind kind = getMemoryKind(access);
-        if (other.isConstant()) {
-            if (kind != kind.getStackKind()) {
-                return false;
-            }
-            Constant constant = other.asConstant();
-            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return false;
-            }
-            ensureEvaluated(other);
-            gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
-        } else {
-            evaluateDeferred();
-            gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), gen.operand(other), getState(access)));
-        }
-
-        gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
-        return true;
-    }
-
-    /**
-     * @return the input which is not equal to access, accounting for possible UnsafeCastNodes.
-     */
-    protected ValueNode selectOtherInput(ValueNode left, ValueNode right, Access access) {
-        assert uncast(left) == access || uncast(right) == access;
-        return uncast(left) == access ? right : left;
-    }
-
-    protected ValueNode uncast(ValueNode value) {
-        if (value instanceof UnsafeCastNode) {
-            UnsafeCastNode cast = (UnsafeCastNode) value;
-            return cast.getOriginalNode();
-        }
-        return value;
-    }
-
-    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
-                    double trueLabelProbability) {
-        ValueNode other = selectOtherInput(left, right, access);
-        Kind kind = getMemoryKind(access);
-        boolean mirrored = false;
-
-        if (other.isConstant()) {
-            Constant constant = other.asConstant();
-            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return false;
-            }
-            if (kind.isNumericFloat()) {
-                Debug.log("Skipping constant compares for float kinds");
-                return false;
-            }
-            if (kind == Kind.Object) {
-                if (!constant.isNull()) {
-                    Debug.log("Skipping constant compares for Object kinds");
-                    return false;
-                }
-            }
-            ensureEvaluated(other);
-            gen.getLIRGenerator().emitCompareMemoryConOp(kind, makeAddress(access), constant, getState(access));
-            mirrored = uncast(right) == access;
-        } else {
-            if (kind == Kind.Object) {
-                // Can't compare against objects since they require encode/decode
-                Debug.log("Skipping compares for Object kinds");
-                return false;
-            }
-
-            evaluateDeferred();
-            gen.getLIRGenerator().emitCompareRegMemoryOp(kind, gen.operand(other), makeAddress(access), getState(access));
-            mirrored = uncast(left) == access;
-        }
-
-        Condition finalCondition = mirrored ? cond.mirror() : cond;
-        switch (kind.getStackKind()) {
-            case Long:
-            case Int:
-            case Object:
-                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            case Float:
-            case Double:
-                gen.append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            default:
-                throw GraalInternalError.shouldNotReachHere("" + kind.getStackKind());
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -23,33 +23,31 @@
 
 package com.oracle.graal.compiler.amd64;
 
+import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
+
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.extended.*;
 
 public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
 
-    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         super(graph, gen);
     }
 
-    protected MemoryArithmeticLIRLowerer memoryPeephole;
-
-    @Override
-    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
-        if (memoryPeephole == null) {
-            // Use the generic one
-            memoryPeephole = new AMD64MemoryPeephole(this);
-        }
-        return memoryPeephole;
-    }
-
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
         AllocatableValue targetAddress = AMD64.rax.asValue();
@@ -58,12 +56,6 @@
     }
 
     @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;
@@ -73,7 +65,7 @@
                 if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
                     FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
                     if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && !hasOperand(otherDivRem)) {
-                        Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode);
+                        Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), state((DeoptimizingNode) valueNode));
                         if (divRem instanceof IntegerDivNode) {
                             setResult(divRem, results[0]);
                             setResult(otherDivRem, results[1]);
@@ -90,6 +82,391 @@
         return false;
     }
 
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected Kind getMemoryKind(Access access) {
+        return (Kind) gen.getPlatformKind(access.asNode().stamp());
+    }
+
+    protected AMD64AddressValue makeAddress(Access access) {
+        return (AMD64AddressValue) access.accessLocation().generateAddress(this, gen, operand(access.object()));
+    }
+
+    protected ValueNode uncast(ValueNode value) {
+        if (value instanceof UnsafeCastNode) {
+            UnsafeCastNode cast = (UnsafeCastNode) value;
+            return cast.getOriginalNode();
+        }
+        return value;
+    }
+
+    protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
+        Condition cond = compare.condition();
+        Kind kind = getMemoryKind(access);
+
+        if (value.isConstant()) {
+            Constant constant = value.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            if (kind.isNumericFloat()) {
+                Debug.log("Skipping constant compares for float kinds");
+                return null;
+            }
+            if (kind == Kind.Object) {
+                if (!constant.isNull()) {
+                    Debug.log("Skipping constant compares for Object kinds");
+                    return null;
+                }
+            }
+        } else {
+            if (kind == Kind.Object) {
+                // Can't compare against objects since they require encode/decode
+                Debug.log("Skipping compares for Object kinds");
+                return null;
+            }
+        }
+
+        PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp());
+        if (cmpKind instanceof Kind) {
+            // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
+            // that's not true. It might be mirrored again the actual compare is emitted but that's
+            // ok.
+            Condition finalCondition = uncast(compare.x()) == access ? cond.mirror() : cond;
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+                    LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+                    boolean unorderedIsTrue = compare.unorderedIsTrue();
+                    double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+                    Value other;
+                    if (value.isConstant()) {
+                        other = value.asConstant();
+                    } else {
+                        other = operand(value);
+                    }
+
+                    getLIRGeneratorTool().emitCompareBranchMemory((Kind) cmpKind, other, makeAddress(access), getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel,
+                                    trueLabelProbability);
+                    return null;
+                }
+            };
+        }
+        return null;
+
+    }
+
+    private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
+        LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
+        double trueLabelProbability = x.probability(x.trueSuccessor());
+        Kind kind = getMemoryKind(access);
+        if (value.isConstant()) {
+            if (kind != kind.getStackKind()) {
+                return null;
+            }
+            Constant constant = value.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            return builder -> {
+                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        } else {
+            return builder -> {
+                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        }
+    }
+
+    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
+        AMD64AddressValue address = makeAddress(access);
+        LIRFrameState state = getState(access);
+        return getLIRGeneratorTool().emitConvert2MemoryOp(kind, op, address, state);
+    }
+
+    private Value emitFloatConvertMemory(FloatConvertNode op, Access access) {
+        switch (op.getOp()) {
+            case D2F:
+                return emitConvert2MemoryOp(Kind.Float, D2F, access);
+            case D2I:
+                return emitConvert2MemoryOp(Kind.Int, D2I, access);
+            case D2L:
+                return emitConvert2MemoryOp(Kind.Long, D2L, access);
+            case F2D:
+                return emitConvert2MemoryOp(Kind.Double, F2D, access);
+            case F2I:
+                return emitConvert2MemoryOp(Kind.Int, F2I, access);
+            case F2L:
+                return emitConvert2MemoryOp(Kind.Long, F2L, access);
+            case I2D:
+                return emitConvert2MemoryOp(Kind.Double, I2D, access);
+            case I2F:
+                return emitConvert2MemoryOp(Kind.Float, I2F, access);
+            case L2D:
+                return emitConvert2MemoryOp(Kind.Double, L2D, access);
+            case L2F:
+                return emitConvert2MemoryOp(Kind.Float, L2F, access);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        Kind kind = null;
+        AMD64Arithmetic op = null;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            kind = Kind.Long;
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    op = B2L;
+                    break;
+                case 16:
+                    op = S2L;
+                    break;
+                case 32:
+                    op = I2L;
+                    break;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+            kind = Kind.Int;
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    op = B2I;
+                    break;
+                case 16:
+                    op = S2I;
+                    break;
+                case 32:
+                    return null;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+        if (kind != null && op != null) {
+            Kind localKind = kind;
+            AMD64Arithmetic localOp = op;
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    return emitConvert2MemoryOp(localKind, localOp, access);
+                }
+            };
+        }
+        return null;
+    }
+
+    private Value emitReinterpretMemory(PlatformKind to, Access access) {
+        AMD64AddressValue address = makeAddress(access);
+        LIRFrameState state = getState(access);
+        return getLIRGeneratorTool().emitLoad(to, address, state);
+    }
+
+    protected AMD64Arithmetic getOp(ValueNode operation, Access access) {
+        Kind memoryKind = getMemoryKind(access);
+        if (operation.getClass() == IntegerAddNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IADD;
+                case Long:
+                    return LADD;
+            }
+        } else if (operation.getClass() == FloatAddNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FADD;
+                case Double:
+                    return DADD;
+            }
+        } else if (operation.getClass() == AndNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IAND;
+                case Long:
+                    return LAND;
+            }
+        } else if (operation.getClass() == OrNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IOR;
+                case Long:
+                    return LOR;
+            }
+        } else if (operation.getClass() == XorNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IXOR;
+                case Long:
+                    return LXOR;
+            }
+        } else if (operation.getClass() == IntegerSubNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return ISUB;
+                case Long:
+                    return LSUB;
+            }
+        } else if (operation.getClass() == FloatSubNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FSUB;
+                case Double:
+                    return DSUB;
+            }
+        } else if (operation.getClass() == IntegerMulNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IMUL;
+                case Long:
+                    return LMUL;
+            }
+        } else if (operation.getClass() == FloatMulNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FMUL;
+                case Double:
+                    return DMUL;
+            }
+        }
+        return null;
+    }
+
+    @MatchRule("(If (IntegerTest Read=access value))")
+    @MatchRule("(If (IntegerTest FloatingRead=access value))")
+    public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
+        return emitIntegerTestBranchMemory(root, value, access);
+    }
+
+    @MatchRule("(If (IntegerEquals=compare value Read=access))")
+    @MatchRule("(If (IntegerLessThan=compare value Read=access))")
+    @MatchRule("(If (IntegerBelowThan=compare value Read=access))")
+    @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerBelowThan=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatEquals=compare value Read=access))")
+    @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatLessThan=compare value Read=access))")
+    @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
+    public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+        return emitCompareBranchMemory(root, compare, value, access);
+    }
+
+    @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
+    public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
+        if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(lshift.x()), operand(lshift.y()));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
+    public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
+        if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))")
+    public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
+        if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    @MatchRule("(IntegerAdd value Read=access)")
+    @MatchRule("(IntegerSub value Read=access)")
+    @MatchRule("(IntegerMul value Read=access)")
+    @MatchRule("(FloatAdd value Read=access)")
+    @MatchRule("(FloatSub value Read=access)")
+    @MatchRule("(FloatMul value Read=access)")
+    @MatchRule("(Or value Read=access)")
+    @MatchRule("(Xor value Read=access)")
+    @MatchRule("(And value Read=access)")
+    @MatchRule("(IntegerAdd value FloatingRead=access)")
+    @MatchRule("(IntegerSub value FloatingRead=access)")
+    @MatchRule("(IntegerMul value FloatingRead=access)")
+    @MatchRule("(FloatAdd value FloatingRead=access)")
+    @MatchRule("(FloatSub value FloatingRead=access)")
+    @MatchRule("(FloatMul value FloatingRead=access)")
+    @MatchRule("(Or value FloatingRead=access)")
+    @MatchRule("(Xor value FloatingRead=access)")
+    @MatchRule("(And value FloatingRead=access)")
+    public ComplexMatchResult binaryRead(BinaryNode root, ValueNode value, Access access) {
+        AMD64Arithmetic op = getOp(root, access);
+        if (op != null) {
+            return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access));
+        }
+        return null;
+    }
+
+    @MatchRule("(Write Narrow=narrow location value)")
+    public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
+        return builder -> {
+            PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp());
+            Value address = root.location().generateAddress(builder, getLIRGeneratorTool(), operand(root.object()));
+            Value v = operand(narrow.getInput());
+            getLIRGeneratorTool().emitStore(writeKind, address, v, state(root));
+            return null;
+        };
+    }
+
+    @MatchRule("(SignExtend Read=access)")
+    @MatchRule("(SignExtend FloatingRead=access)")
+    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
+        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        Kind memoryKind = getMemoryKind(access);
+        if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) {
+            /*
+             * The memory being read from is signed and smaller than the result size so this is a
+             * sign extension to inputBits followed by a zero extension to resultBits which can't be
+             * expressed in a memory operation.
+             */
+            return null;
+        }
+        return builder -> getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), makeAddress(access), getState(access));
+    }
+
+    @MatchRule("(FloatConvert Read=access)")
+    @MatchRule("(FloatConvert FloatingRead=access)")
+    public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
+        return builder -> emitFloatConvertMemory(root, access);
+
+    }
+
+    @MatchRule("(Reinterpret Read=access)")
+    @MatchRule("(Reinterpret FloatingRead=access)")
+    public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
+        return builder -> {
+            PlatformKind kind = getLIRGeneratorTool().getPlatformKind(root.stamp());
+            return emitReinterpretMemory(kind, access);
+        };
+
+    }
+
     @Override
     public void visitBreakpointNode(BreakpointNode node) {
         JavaType[] sig = new JavaType[node.arguments().size()];
@@ -103,11 +480,11 @@
 
     @Override
     public void visitInfopointNode(InfopointNode i) {
-        append(new InfopointOp(gen.stateFor(i.getState()), i.reason));
+        append(new InfopointOp(stateFor(i.getState()), i.reason));
     }
 
     @Override
-    public AMD64LIRGenerator getLIRGenerator() {
+    public AMD64LIRGenerator getLIRGeneratorTool() {
         return (AMD64LIRGenerator) gen;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+public abstract class FieldIntrospection extends UnsafeAccess {
+
+    /**
+     * Interface used by {@link #rescanAllFieldOffsets(CalcOffset)} to determine the offset (in
+     * bytes) of a field.
+     */
+    public interface CalcOffset {
+
+        long getOffset(Field field);
+    }
+
+    public static class DefaultCalcOffset implements CalcOffset {
+
+        @Override
+        public long getOffset(Field field) {
+            return unsafe.objectFieldOffset(field);
+        }
+    }
+
+    protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
+
+    private final Class<?> clazz;
+    protected long[] dataOffsets;
+    protected Map<Long, String> fieldNames;
+    protected Map<Long, Class<?>> fieldTypes;
+
+    public FieldIntrospection(Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    public Class<?> getClazz() {
+        return clazz;
+    }
+
+    public static void rescanAllFieldOffsets(CalcOffset calc) {
+        for (FieldIntrospection nodeClass : allClasses.values()) {
+            nodeClass.rescanFieldOffsets(calc);
+        }
+    }
+
+    protected abstract void rescanFieldOffsets(CalcOffset calc);
+
+    public abstract static class BaseFieldScanner {
+
+        private final CalcOffset calc;
+
+        /** The offsets of fields that are not specially handled by subclasses. */
+        public final ArrayList<Long> dataOffsets = new ArrayList<>();
+
+        public final Map<Long, String> fieldNames = new HashMap<>();
+        public final Map<Long, Class<?>> fieldTypes = new HashMap<>();
+
+        protected BaseFieldScanner(CalcOffset calc) {
+            this.calc = calc;
+        }
+
+        public void scan(Class<?> clazz) {
+            Class<?> currentClazz = clazz;
+            do {
+                for (Field field : currentClazz.getDeclaredFields()) {
+                    if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) {
+                        continue;
+                    }
+                    Class<?> type = field.getType();
+                    long offset = calc.getOffset(field);
+
+                    // scanField() may overwrite the name with a customized name.
+                    fieldNames.put(offset, field.getName());
+                    fieldTypes.put(offset, type);
+
+                    scanField(field, type, offset);
+                }
+                currentClazz = currentClazz.getSuperclass();
+            } while (currentClazz.getSuperclass() != Object.class);
+        }
+
+        protected abstract void scanField(Field field, Class<?> type, long offset);
+    }
+
+    protected static void copyInto(long[] dest, long[] src) {
+        assert dest.length == src.length;
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = src[i];
+        }
+    }
+
+    protected static <T> void copyInto(T[] dest, T[] src) {
+        assert dest.length == src.length;
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = src[i];
+        }
+    }
+
+    protected static <T> void copyInto(T[] dest, List<T> src) {
+        assert dest.length == src.size();
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = src.get(i);
+        }
+    }
+
+    protected static <T> T[] arrayUsingSortedOffsets(Map<Long, T> map, long[] sortedOffsets, T[] result) {
+        for (int i = 0; i < sortedOffsets.length; i++) {
+            result[i] = map.get(sortedOffsets[i]);
+        }
+        return result;
+    }
+
+    protected static long[] sortedLongCopy(ArrayList<Long> list1) {
+        Collections.sort(list1);
+        long[] result = new long[list1.size()];
+        for (int i = 0; i < list1.size(); i++) {
+            result[i] = list1.get(i);
+        }
+        return result;
+    }
+
+    protected static long[] sortedLongCopy(ArrayList<Long> list1, ArrayList<Long> list2) {
+        Collections.sort(list1);
+        Collections.sort(list2);
+        long[] result = new long[list1.size() + list2.size()];
+        for (int i = 0; i < list1.size(); i++) {
+            result[i] = list1.get(i);
+        }
+        for (int i = 0; i < list2.size(); i++) {
+            result[list1.size() + i] = list2.get(i);
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,287 @@
+/*
+ * 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.common;
+
+import com.oracle.graal.options.*;
+
+/**
+ * This class encapsulates options that control the behavior of the Graal compiler.
+ */
+// @formatter:off
+public final class GraalOptions {
+
+    @Option(help = "Use baseline compiler configuration")
+    public static final OptionValue<Boolean> UseBaselineCompiler = new OptionValue<>(false);
+    @Option(help = "Enable use of compiler intrinsics")
+    public static final OptionValue<Boolean> Intrinsify = new OptionValue<>(true);
+    @Option(help = "Enable inlining of monomorphic calls")
+    public static final OptionValue<Boolean> InlineMonomorphicCalls = new OptionValue<>(true);
+    @Option(help = "Enable inlining of polymorphic calls")
+    public static final OptionValue<Boolean> InlinePolymorphicCalls = new OptionValue<>(true);
+    @Option(help = "Enable inlining of megamorphic calls")
+    public static final OptionValue<Boolean> InlineMegamorphicCalls = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Double> MegamorphicInliningMinMethodProbability = new OptionValue<>(0.33D);
+    @Option(help = "")
+    public static final OptionValue<Integer> MaximumDesiredSize = new OptionValue<>(20000);
+    @Option(help = "")
+    public static final OptionValue<Integer> MaximumRecursiveInlining = new OptionValue<>(5);
+
+    // inlining settings
+    @Option(help = "")
+    public static final OptionValue<Float> BoostInliningForEscapeAnalysis = new OptionValue<>(2f);
+    @Option(help = "")
+    public static final OptionValue<Float> RelevanceCapForInlining = new OptionValue<>(1f);
+    @Option(help = "")
+    public static final OptionValue<Float> CapInheritedRelevance = new OptionValue<>(1f);
+    @Option(help = "")
+    public static final OptionValue<Boolean> IterativeInlining = new OptionValue<>(false);
+
+    @Option(help = "")
+    public static final OptionValue<Integer> TrivialInliningSize = new OptionValue<>(10);
+    @Option(help = "")
+    public static final OptionValue<Integer> MaximumInliningSize = new OptionValue<>(300);
+    @Option(help = "")
+    public static final OptionValue<Integer> SmallCompiledLowLevelGraphSize = new OptionValue<>(300);
+    @Option(help = "")
+    public static final OptionValue<Double> LimitInlinedInvokes = new OptionValue<>(5.0);
+    @Option(help = "")
+    public static final OptionValue<Boolean> InlineEverything = new OptionValue<>(false);
+
+    // escape analysis settings
+    @Option(help = "")
+    public static final OptionValue<Boolean> PartialEscapeAnalysis = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Integer> EscapeAnalysisIterations = new OptionValue<>(2);
+    @Option(help = "")
+    public static final OptionValue<String> EscapeAnalyzeOnly = new OptionValue<>(null);
+    @Option(help = "")
+    public static final OptionValue<Integer> MaximumEscapeAnalysisArrayLength = new OptionValue<>(32);
+    @Option(help = "")
+    public static final OptionValue<Boolean> PEAInliningHints = new OptionValue<>(false);
+
+    @Option(help = "")
+    public static final OptionValue<Double> TailDuplicationProbability = new OptionValue<>(0.5);
+    @Option(help = "")
+    public static final OptionValue<Integer> TailDuplicationTrivialSize = new OptionValue<>(1);
+
+    // profiling information
+    @Option(help = "")
+    public static final OptionValue<Integer> DeoptsToDisableOptimisticOptimization = new OptionValue<>(40);
+
+    // graph caching
+    @Option(help = "")
+    public static final OptionValue<Boolean> CacheGraphs = new OptionValue<>(true);
+
+    //loop transform settings TODO (gd) tune
+    @Option(help = "")
+    public static final OptionValue<Boolean> LoopPeeling = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> ReassociateInvariants = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> FullUnroll = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> LoopUnswitch = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Integer> FullUnrollMaxNodes = new OptionValue<>(300);
+    @Option(help = "")
+    public static final OptionValue<Integer> ExactFullUnrollMaxNodes = new OptionValue<>(1200);
+    @Option(help = "")
+    public static final OptionValue<Float> MinimumPeelProbability = new OptionValue<>(0.35f);
+    @Option(help = "")
+    public static final OptionValue<Integer> LoopMaxUnswitch = new OptionValue<>(3);
+    @Option(help = "")
+    public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(50);
+    @Option(help = "")
+    public static final OptionValue<Integer> LoopUnswitchUncertaintyBoost = new OptionValue<>(5);
+    @Option(help = "")
+    public static final OptionValue<Boolean> UseLoopLimitChecks = new OptionValue<>(true);
+
+    // debugging settings
+    @Option(help = "")
+    public static final OptionValue<Boolean> ZapStackOnMethodEntry = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> DeoptALot = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> VerifyPhases = new OptionValue<>(false);
+
+    @Option(help = "")
+    public static final OptionValue<String> PrintFilter = new OptionValue<>(null);
+
+    // Debug settings:
+    @Option(help = "")
+    public static final OptionValue<Boolean> BootstrapReplacements = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Integer> GCDebugStartCycle = new OptionValue<>(-1);
+    // Ideal graph visualizer output settings
+    @Option(help = "Dump IdealGraphVisualizer output in binary format")
+    public static final OptionValue<Boolean> PrintBinaryGraphs = new OptionValue<>(true);
+    @Option(help = "Output probabilities for fixed nodes during binary graph dumping")
+    public static final OptionValue<Boolean> PrintGraphProbabilities = new OptionValue<>(false);
+    @Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.")
+    public static final OptionValue<Boolean> PrintCFG = new OptionValue<>(false);
+    @Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.")
+    public static final OptionValue<Boolean> PrintBackendCFG = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> PrintIdealGraphFile = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<String> PrintIdealGraphAddress = new OptionValue<>("127.0.0.1");
+    @Option(help = "")
+    public static final OptionValue<Integer> PrintIdealGraphPort = new OptionValue<>(4444);
+    @Option(help = "")
+    public static final OptionValue<Integer> PrintBinaryGraphPort = new OptionValue<>(4445);
+
+    // Other printing settings
+    @Option(help = "")
+    public static final OptionValue<Boolean> PrintCompilation = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> PrintAfterCompilation = new OptionValue<>(false);
+    @Option(help = "Print profiling information when parsing a method's bytecode")
+    public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> PrintCodeBytes = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> PrintBailout = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> TraceEscapeAnalysis = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> ExitVMOnBailout = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> ExitVMOnException = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> PrintStackTraceOnException = new OptionValue<>(false);
+    @Option(help = "Set a phase after which the decompiler dumps the graph, -G:Dump= required")
+    public static final OptionValue<String> DecompileAfterPhase = new OptionValue<>(null);
+
+    // HotSpot command line options
+    @Option(help = "")
+    public static final OptionValue<Boolean> HotSpotPrintCompilation = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> HotSpotCIPrintCompilerName = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> HotSpotPrintInlining = new OptionValue<>(false);
+
+    // Register allocator debugging
+    @Option(help = "")
+    public static final OptionValue<String> RegisterPressure = new OptionValue<>(null);
+
+    // Code generator settings
+    @Option(help = "")
+    public static final OptionValue<Boolean> FlowSensitiveReduction = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> UseProfilingInformation = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> RemoveNeverExecutedCode = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> UseExceptionProbability = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> UseExceptionProbabilityForOperations = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OmitHotExceptionStacktrace = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> GenSafepoints = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> GenLoopSafepoints = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> UseTypeCheckHints = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> InlineVTableStubs = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> AlwaysInlineVTableStubs = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> GenAssertionCode = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> AlignCallsForPatching = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> ResolveClassBeforeStaticInvoke = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> CanOmitFrame = new OptionValue<>(true);
+
+    @Option(help = "")
+    public static final OptionValue<Boolean> MemoryAwareScheduling = new OptionValue<>(true);
+
+    // Translating tableswitch instructions
+    @Option(help = "")
+    public static final OptionValue<Integer> MinimumJumpTableSize = new OptionValue<>(5);
+    @Option(help = "")
+    public static final OptionValue<Integer> RangeTestsSwitchDensity = new OptionValue<>(5);
+    @Option(help = "")
+    public static final OptionValue<Double> MinTableSwitchDensity = new OptionValue<>(0.5);
+
+    // Ahead of time compilation
+    @Option(help = "Try to avoid emitting code where patching is required")
+    public static final OptionValue<Boolean> ImmutableCode = new OptionValue<>(false);
+
+    @Option(help = "")
+    public static final OptionValue<Boolean> CallArrayCopy = new OptionValue<>(true);
+
+    // Runtime settings
+    @Option(help = "")
+    public static final OptionValue<Boolean> SupportJsrBytecodes = new OptionValue<>(true);
+
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptAssumptions = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptConvertDeoptsToGuards = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptReadElimination = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptCanonicalizer = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptDeoptimizationGrouping = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptEliminateGuards = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptImplicitNullChecks = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptLivenessAnalysis = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptLoopTransform = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptFloatingReads = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptTailDuplication = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptEliminatePartiallyRedundantGuards = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptFilterProfiledTypes = new OptionValue<>(true);
+    @Option(help = "")
+    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<>(false);
+    @Option(help = "Allow backend to match complex expressions.")
+    public static final OptionValue<Boolean> MatchExpressions = new OptionValue<>(true);
+
+
+    /**
+     * Counts the various paths taken through snippets.
+     */
+    @Option(help = "")
+    public static final OptionValue<Boolean> SnippetCounters = new OptionValue<>(false);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/UnsafeAccess.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common;
+
+import java.lang.reflect.*;
+
+import sun.misc.*;
+
+public class UnsafeAccess {
+
+    /**
+     * An instance of {@link Unsafe} for use within Graal.
+     */
+    public static final Unsafe unsafe = getUnsafe();
+
+    private static Unsafe getUnsafe() {
+        try {
+            // this will fail if Graal is not part of the boot class path
+            return Unsafe.getUnsafe();
+        } catch (SecurityException e) {
+            // nothing to do
+        }
+        try {
+            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafeInstance.setAccessible(true);
+            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
+        } catch (Exception e) {
+            // currently we rely on being able to use Unsafe...
+            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
+        }
+    }
+
+    /**
+     * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'}
+     * terminated C string. The native memory buffer is allocated via
+     * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when
+     * it is no longer needed via {@link Unsafe#freeMemory(long)}.
+     * 
+     * @return the native memory pointer of the C string created from {@code s}
+     */
+    public static long createCString(String s) {
+        return writeCString(s, unsafe.allocateMemory(s.length() + 1));
+    }
+
+    /**
+     * Reads a {@code '\0'} terminated C string from native memory and converts it to a
+     * {@link String}.
+     * 
+     * @return a Java string
+     */
+    public static String readCString(long address) {
+        if (address == 0) {
+            return null;
+        }
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0;; i++) {
+            char c = (char) unsafe.getByte(address + i);
+            if (c == 0) {
+                break;
+            }
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'}
+     * terminated C string. The caller is responsible for ensuring the buffer is at least
+     * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer
+     * when it is no longer.
+     * 
+     * @return the value of {@code buf}
+     */
+    public static long writeCString(String s, long buf) {
+        int size = s.length();
+        for (int i = 0; i < size; i++) {
+            unsafe.putByte(buf + i, (byte) s.charAt(i));
+        }
+        unsafe.putByte(buf + size, (byte) '\0');
+        return buf;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/calc/FloatConvert.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.calc;
+
+import com.oracle.graal.compiler.common.*;
+
+public enum FloatConvert {
+    F2I,
+    D2I,
+    F2L,
+    D2L,
+    I2F,
+    L2F,
+    D2F,
+    I2D,
+    L2D,
+    F2D;
+
+    public FloatConvert reverse() {
+        switch (this) {
+            case D2F:
+                return F2D;
+            case D2I:
+                return I2D;
+            case D2L:
+                return L2D;
+            case F2D:
+                return D2F;
+            case F2I:
+                return I2F;
+            case F2L:
+                return L2F;
+            case I2D:
+                return D2I;
+            case I2F:
+                return F2I;
+            case L2D:
+                return D2L;
+            case L2F:
+                return F2L;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java	Fri May 30 15:09:09 2014 +0200
@@ -30,6 +30,8 @@
 
     Loop<T> getLoop();
 
+    void setLoop(Loop<T> loop);
+
     int getLoopDepth();
 
     boolean isLoopHeader();
@@ -55,4 +57,6 @@
     void setAlign(boolean align);
 
     T getDominator();
+
+    double probability();
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,7 @@
     static final int BLOCK_ID_INITIAL = -1;
     static final int BLOCK_ID_VISITED = -2;
 
-    T[] getBlocks();
+    List<T> getBlocks();
 
     Collection<Loop<T>> getLoops();
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/BlockMap.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/BlockMap.java	Fri May 30 15:09:09 2014 +0200
@@ -28,7 +28,7 @@
 
     @SuppressWarnings("unchecked")
     public BlockMap(AbstractControlFlowGraph<?> cfg) {
-        data = (T[]) new Object[cfg.getBlocks().length];
+        data = (T[]) new Object[cfg.getBlocks().size()];
     }
 
     public T get(AbstractBlock<?> block) {
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/Loop.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/Loop.java	Fri May 30 15:09:09 2014 +0200
@@ -27,20 +27,20 @@
 
 public abstract class Loop<T extends AbstractBlock<T>> {
 
-    public final Loop<T> parent;
-    public final List<Loop<T>> children;
+    private final Loop<T> parent;
+    private final List<Loop<T>> children;
 
-    public final int depth;
-    public final int index;
-    public final T header;
-    public final List<T> blocks;
-    public final List<T> exits;
+    private final int depth;
+    private final int index;
+    private final T header;
+    private final List<T> blocks;
+    private final List<T> exits;
 
     protected Loop(Loop<T> parent, int index, T header) {
         this.parent = parent;
         if (parent != null) {
-            this.depth = parent.depth + 1;
-            parent.children.add(this);
+            this.depth = parent.getDepth() + 1;
+            parent.getChildren().add(this);
         } else {
             this.depth = 1;
         }
@@ -55,6 +55,34 @@
 
     @Override
     public String toString() {
-        return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : "");
+        return "loop " + index + " depth " + getDepth() + (parent != null ? " outer " + parent.index : "");
+    }
+
+    public Loop<T> getParent() {
+        return parent;
+    }
+
+    public List<Loop<T>> getChildren() {
+        return children;
+    }
+
+    public int getDepth() {
+        return depth;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public T getHeader() {
+        return header;
+    }
+
+    public List<T> getBlocks() {
+        return blocks;
+    }
+
+    public List<T> getExits() {
+        return exits;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/CodeGenProviders.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.spi;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+
+/**
+ * A set of providers which are required for LIR and/or code generation. Some may not be present
+ * (i.e., null).
+ */
+public interface CodeGenProviders {
+
+    MetaAccessProvider getMetaAccess();
+
+    CodeCacheProvider getCodeCache();
+
+    ForeignCallsProvider getForeignCalls();
+
+    ConstantReflectionProvider getConstantReflection();
+
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/LIRTypeTool.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.common.spi;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * This interface can be used to access platform and VM specific kinds.
- */
-public interface LIRTypeTool {
-
-    PlatformKind getIntegerKind(int bits);
-
-    PlatformKind getFloatingKind(int bits);
-
-    PlatformKind getObjectKind();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/PlatformKindTool.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.spi;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * This interface can be used to access platform and VM specific kinds.
+ */
+public interface PlatformKindTool {
+
+    PlatformKind getIntegerKind(int bits);
+
+    PlatformKind getFloatingKind(int bits);
+
+    PlatformKind getObjectKind();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,288 @@
+/*
+ * 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.common.type;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+
+public abstract class AbstractObjectStamp extends Stamp {
+
+    private final ResolvedJavaType type;
+    private final boolean exactType;
+    private final boolean nonNull;
+    private final boolean alwaysNull;
+
+    protected AbstractObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        this.type = type;
+        this.exactType = exactType;
+        this.nonNull = nonNull;
+        this.alwaysNull = alwaysNull;
+    }
+
+    protected abstract AbstractObjectStamp copyWith(ResolvedJavaType newType, boolean newExactType, boolean newNonNull, boolean newAlwaysNull);
+
+    @Override
+    public Stamp unrestricted() {
+        return copyWith(null, false, false, false);
+    }
+
+    @Override
+    public Stamp illegal() {
+        return copyWith(null, true, true, false);
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        ResolvedJavaType constType = c.isNull() ? null : meta.lookupJavaType(c);
+        return copyWith(constType, c.isNonNull(), c.isNonNull(), c.isNull());
+    }
+
+    @Override
+    public boolean isLegal() {
+        return !exactType || (type != null && (isConcreteType(type)));
+    }
+
+    @Override
+    public Kind getStackKind() {
+        return Kind.Object;
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        if (type != null) {
+            return type;
+        }
+        return metaAccess.lookupJavaType(Object.class);
+    }
+
+    public boolean nonNull() {
+        return nonNull;
+    }
+
+    public boolean alwaysNull() {
+        return alwaysNull;
+    }
+
+    public ResolvedJavaType type() {
+        return type;
+    }
+
+    public boolean isExactType() {
+        return exactType;
+    }
+
+    protected void appendString(StringBuilder str) {
+        str.append(nonNull ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.getName()).append(alwaysNull ? " NULL" : "");
+    }
+
+    @Override
+    public Stamp meet(Stamp otherStamp) {
+        if (this == otherStamp) {
+            return this;
+        }
+        if (!isCompatible(otherStamp)) {
+            return StampFactory.illegal(Kind.Illegal);
+        }
+        AbstractObjectStamp other = (AbstractObjectStamp) otherStamp;
+        if (!isLegal()) {
+            return other;
+        } else if (!other.isLegal()) {
+            return this;
+        }
+        ResolvedJavaType meetType;
+        boolean meetExactType;
+        boolean meetNonNull;
+        boolean meetAlwaysNull;
+        if (other.alwaysNull) {
+            meetType = type();
+            meetExactType = exactType;
+            meetNonNull = false;
+            meetAlwaysNull = alwaysNull;
+        } else if (alwaysNull) {
+            meetType = other.type();
+            meetExactType = other.exactType;
+            meetNonNull = false;
+            meetAlwaysNull = other.alwaysNull;
+        } else {
+            meetType = meetTypes(type(), other.type());
+            meetExactType = exactType && other.exactType;
+            if (meetExactType && type != null && other.type != null) {
+                // meeting two valid exact types may result in a non-exact type
+                meetExactType = Objects.equals(meetType, type) && Objects.equals(meetType, other.type);
+            }
+            meetNonNull = nonNull && other.nonNull;
+            meetAlwaysNull = false;
+        }
+
+        if (Objects.equals(meetType, type) && meetExactType == exactType && meetNonNull == nonNull && meetAlwaysNull == alwaysNull) {
+            return this;
+        } else if (Objects.equals(meetType, other.type) && meetExactType == other.exactType && meetNonNull == other.nonNull && meetAlwaysNull == other.alwaysNull) {
+            return other;
+        } else {
+            return copyWith(meetType, meetExactType, meetNonNull, meetAlwaysNull);
+        }
+    }
+
+    @Override
+    public Stamp join(Stamp otherStamp) {
+        return join0(otherStamp, false);
+    }
+
+    /**
+     * Returns the stamp representing the type of this stamp after a cast to the type represented by
+     * the {@code to} stamp. While this is very similar to a {@link #join} operation, in the case
+     * where both types are not obviously related, the cast operation will prefer the type of the
+     * {@code to} stamp. This is necessary as long as ObjectStamps are not able to accurately
+     * represent intersection types.
+     *
+     * For example when joining the {@link RandomAccess} type with the {@link AbstractList} type,
+     * without intersection types, this would result in the most generic type ({@link Object} ). For
+     * this reason, in some cases a {@code castTo} operation is preferable in order to keep at least
+     * the {@link AbstractList} type.
+     *
+     * @param to the stamp this stamp should be casted to
+     * @return This stamp casted to the {@code to} stamp
+     */
+    public Stamp castTo(ObjectStamp to) {
+        return join0(to, true);
+    }
+
+    private Stamp join0(Stamp otherStamp, boolean castToOther) {
+        if (this == otherStamp) {
+            return this;
+        }
+        if (!isCompatible(otherStamp)) {
+            return StampFactory.illegal(Kind.Illegal);
+        }
+        AbstractObjectStamp other = (AbstractObjectStamp) otherStamp;
+        if (!isLegal()) {
+            return this;
+        } else if (!other.isLegal()) {
+            return other;
+        }
+
+        ResolvedJavaType joinType;
+        boolean joinAlwaysNull = alwaysNull || other.alwaysNull;
+        boolean joinNonNull = nonNull || other.nonNull;
+        boolean joinExactType = exactType || other.exactType;
+        if (Objects.equals(type, other.type)) {
+            joinType = type;
+        } else if (type == null && other.type == null) {
+            joinType = null;
+        } else if (type == null) {
+            joinType = other.type;
+        } else if (other.type == null) {
+            joinType = type;
+        } else {
+            // both types are != null and different
+            if (type.isAssignableFrom(other.type)) {
+                joinType = other.type;
+                if (exactType) {
+                    joinAlwaysNull = true;
+                }
+            } else if (other.type.isAssignableFrom(type)) {
+                joinType = type;
+                if (other.exactType) {
+                    joinAlwaysNull = true;
+                }
+            } else {
+                if (castToOther) {
+                    joinType = other.type;
+                    joinExactType = other.exactType;
+                } else {
+                    joinType = null;
+                }
+                if (joinExactType || (!type.isInterface() && !other.type.isInterface())) {
+                    joinAlwaysNull = true;
+                }
+            }
+        }
+        if (joinAlwaysNull) {
+            joinType = null;
+            joinExactType = false;
+        }
+        if (joinExactType && joinType == null) {
+            return StampFactory.illegal(Kind.Object);
+        }
+        if (joinAlwaysNull && joinNonNull) {
+            return StampFactory.illegal(Kind.Object);
+        } else if (joinExactType && !isConcreteType(joinType)) {
+            return StampFactory.illegal(Kind.Object);
+        }
+        if (Objects.equals(joinType, type) && joinExactType == exactType && joinNonNull == nonNull && joinAlwaysNull == alwaysNull) {
+            return this;
+        } else if (Objects.equals(joinType, other.type) && joinExactType == other.exactType && joinNonNull == other.nonNull && joinAlwaysNull == other.alwaysNull) {
+            return other;
+        } else {
+            return copyWith(joinType, joinExactType, joinNonNull, joinAlwaysNull);
+        }
+    }
+
+    public static boolean isConcreteType(ResolvedJavaType type) {
+        return !(type.isAbstract() && !type.isArray());
+    }
+
+    private static ResolvedJavaType meetTypes(ResolvedJavaType a, ResolvedJavaType b) {
+        if (Objects.equals(a, b)) {
+            return a;
+        } else if (a == null || b == null) {
+            return null;
+        } else {
+            return a.findLeastCommonAncestor(b);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (exactType ? 1231 : 1237);
+        result = prime * result + (nonNull ? 1231 : 1237);
+        result = prime * result + (alwaysNull ? 1231 : 1237);
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        AbstractObjectStamp other = (AbstractObjectStamp) obj;
+        if (exactType != other.exactType || nonNull != other.nonNull || alwaysNull != other.alwaysNull) {
+            return false;
+        }
+        if (type == null) {
+            if (other.type != null) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
+            return false;
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,240 @@
+/*
+ * 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.common.type;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.spi.*;
+
+public class FloatStamp extends PrimitiveStamp {
+
+    private final double lowerBound;
+    private final double upperBound;
+    private final boolean nonNaN;
+
+    protected FloatStamp(int bits) {
+        this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false);
+    }
+
+    public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) {
+        super(bits);
+        this.lowerBound = lowerBound;
+        this.upperBound = upperBound;
+        this.nonNaN = nonNaN;
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return new FloatStamp(getBits());
+    }
+
+    @Override
+    public Stamp illegal() {
+        return new FloatStamp(getBits(), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, true);
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        assert c.getKind().isNumericFloat() && c.getKind().getBitCount() == getBits();
+        return StampFactory.forConstant(c);
+    }
+
+    @Override
+    public boolean isLegal() {
+        return lowerBound <= upperBound || !nonNaN;
+    }
+
+    @Override
+    public Kind getStackKind() {
+        if (getBits() > 32) {
+            return Kind.Double;
+        } else {
+            return Kind.Float;
+        }
+    }
+
+    @Override
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+        return tool.getFloatingKind(getBits());
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        switch (getBits()) {
+            case 32:
+                return metaAccess.lookupJavaType(Float.TYPE);
+            case 64:
+                return metaAccess.lookupJavaType(Double.TYPE);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * The (inclusive) lower bound on the value described by this stamp.
+     */
+    public double lowerBound() {
+        return lowerBound;
+    }
+
+    /**
+     * The (inclusive) upper bound on the value described by this stamp.
+     */
+    public double upperBound() {
+        return upperBound;
+    }
+
+    public boolean isNonNaN() {
+        return nonNaN;
+    }
+
+    public boolean isUnrestricted() {
+        return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN;
+    }
+
+    public boolean contains(double value) {
+        if (Double.isNaN(value)) {
+            return !nonNaN;
+        } else {
+            return value >= lowerBound && value <= upperBound;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('f');
+        str.append(getBits());
+        str.append(nonNaN ? "!" : "");
+        if (lowerBound == upperBound) {
+            str.append(" [").append(lowerBound).append(']');
+        } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
+            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
+        }
+        return str.toString();
+    }
+
+    @Override
+    public Stamp meet(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        if (!(otherStamp instanceof FloatStamp)) {
+            return StampFactory.illegal(Kind.Illegal);
+        }
+        FloatStamp other = (FloatStamp) otherStamp;
+        assert getBits() == other.getBits();
+        double meetUpperBound = Math.max(upperBound, other.upperBound);
+        double meetLowerBound = Math.min(lowerBound, other.lowerBound);
+        boolean meetNonNaN = nonNaN && other.nonNaN;
+        if (meetLowerBound == lowerBound && meetUpperBound == upperBound && meetNonNaN == nonNaN) {
+            return this;
+        } else if (meetLowerBound == other.lowerBound && meetUpperBound == other.upperBound && meetNonNaN == other.nonNaN) {
+            return other;
+        } else {
+            return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN);
+        }
+    }
+
+    @Override
+    public Stamp join(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        if (!(otherStamp instanceof FloatStamp)) {
+            return StampFactory.illegal(Kind.Illegal);
+        }
+        FloatStamp other = (FloatStamp) otherStamp;
+        assert getBits() == other.getBits();
+        double joinUpperBound = Math.min(upperBound, other.upperBound);
+        double joinLowerBound = Math.max(lowerBound, other.lowerBound);
+        boolean joinNonNaN = nonNaN || other.nonNaN;
+        if (joinLowerBound == lowerBound && joinUpperBound == upperBound && joinNonNaN == nonNaN) {
+            return this;
+        } else if (joinLowerBound == other.lowerBound && joinUpperBound == other.upperBound && joinNonNaN == other.nonNaN) {
+            return other;
+        } else {
+            return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        long temp;
+        result = prime * result + super.hashCode();
+        temp = Double.doubleToLongBits(lowerBound);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        result = prime * result + (nonNaN ? 1231 : 1237);
+        temp = Double.doubleToLongBits(upperBound);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        if (this == stamp) {
+            return true;
+        }
+        if (stamp instanceof FloatStamp) {
+            FloatStamp other = (FloatStamp) stamp;
+            return getBits() == other.getBits();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
+            return false;
+        }
+        FloatStamp other = (FloatStamp) obj;
+        if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) {
+            return false;
+        }
+        if (Double.doubleToLongBits(upperBound) != Double.doubleToLongBits(other.upperBound)) {
+            return false;
+        }
+        if (nonNaN != other.nonNaN) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public Constant asConstant() {
+        if (nonNaN && lowerBound == upperBound) {
+            switch (getBits()) {
+                case 32:
+                    return Constant.forFloat((float) lowerBound);
+                case 64:
+                    return Constant.forDouble(lowerBound);
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,97 @@
+/*
+ * 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.common.type;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.spi.*;
+
+/**
+ * This stamp represents the illegal type. Values with this type can not exist at run time.
+ */
+public final class IllegalStamp extends Stamp {
+
+    private IllegalStamp() {
+    }
+
+    @Override
+    public Kind getStackKind() {
+        return Kind.Illegal;
+    }
+
+    @Override
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+        throw GraalInternalError.shouldNotReachHere("illegal stamp should not reach backend");
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return this;
+    }
+
+    @Override
+    public Stamp illegal() {
+        return this;
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        throw GraalInternalError.shouldNotReachHere("illegal stamp has no value");
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        throw GraalInternalError.shouldNotReachHere("illegal stamp has no Java type");
+    }
+
+    @Override
+    public Stamp meet(Stamp other) {
+        return this;
+    }
+
+    @Override
+    public Stamp join(Stamp other) {
+        return this;
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "ILLEGAL";
+    }
+
+    @Override
+    public boolean isLegal() {
+        return false;
+    }
+
+    private static IllegalStamp instance = new IllegalStamp();
+
+    static IllegalStamp getInstance() {
+        return instance;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,326 @@
+/*
+ * 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.common.type;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.spi.*;
+
+/**
+ * Describes the possible values of a node that produces an int or long result.
+ *
+ * The description consists of (inclusive) lower and upper bounds and up (may be set) and down
+ * (always set) bit-masks.
+ */
+public class IntegerStamp extends PrimitiveStamp {
+
+    private final long lowerBound;
+    private final long upperBound;
+    private final long downMask;
+    private final long upMask;
+
+    public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
+        super(bits);
+        this.lowerBound = lowerBound;
+        this.upperBound = upperBound;
+        this.downMask = downMask;
+        this.upMask = upMask;
+        assert lowerBound >= defaultMinValue(bits) : this;
+        assert upperBound <= defaultMaxValue(bits) : this;
+        assert (downMask & defaultMask(bits)) == downMask : this;
+        assert (upMask & defaultMask(bits)) == upMask : this;
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return new IntegerStamp(getBits(), defaultMinValue(getBits()), defaultMaxValue(getBits()), 0, defaultMask(getBits()));
+    }
+
+    @Override
+    public Stamp illegal() {
+        return new IntegerStamp(getBits(), defaultMaxValue(getBits()), defaultMinValue(getBits()), defaultMask(getBits()), 0);
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        long value = c.asLong();
+        return StampFactory.forInteger(getBits(), value, value);
+    }
+
+    @Override
+    public boolean isLegal() {
+        return lowerBound <= upperBound;
+    }
+
+    @Override
+    public Kind getStackKind() {
+        if (getBits() > 32) {
+            return Kind.Long;
+        } else {
+            return Kind.Int;
+        }
+    }
+
+    @Override
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+        return tool.getIntegerKind(getBits());
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        switch (getBits()) {
+            case 1:
+                return metaAccess.lookupJavaType(Boolean.TYPE);
+            case 8:
+                return metaAccess.lookupJavaType(Byte.TYPE);
+            case 16:
+                return metaAccess.lookupJavaType(Short.TYPE);
+            case 32:
+                return metaAccess.lookupJavaType(Integer.TYPE);
+            case 64:
+                return metaAccess.lookupJavaType(Long.TYPE);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * The signed inclusive lower bound on the value described by this stamp.
+     */
+    public long lowerBound() {
+        return lowerBound;
+    }
+
+    /**
+     * The signed inclusive upper bound on the value described by this stamp.
+     */
+    public long upperBound() {
+        return upperBound;
+    }
+
+    /**
+     * This bit-mask describes the bits that are always set in the value described by this stamp.
+     */
+    public long downMask() {
+        return downMask;
+    }
+
+    /**
+     * This bit-mask describes the bits that can be set in the value described by this stamp.
+     */
+    public long upMask() {
+        return upMask;
+    }
+
+    public boolean isUnrestricted() {
+        return lowerBound == defaultMinValue(getBits()) && upperBound == defaultMaxValue(getBits()) && downMask == 0 && upMask == defaultMask(getBits());
+    }
+
+    public boolean contains(long value) {
+        return value >= lowerBound && value <= upperBound && (value & downMask) == downMask && (value & upMask) == (value & defaultMask(getBits()));
+    }
+
+    public boolean isPositive() {
+        return lowerBound() >= 0;
+    }
+
+    public boolean isNegative() {
+        return upperBound() <= 0;
+    }
+
+    public boolean isStrictlyPositive() {
+        return lowerBound() > 0;
+    }
+
+    public boolean isStrictlyNegative() {
+        return upperBound() < 0;
+    }
+
+    public boolean canBePositive() {
+        return upperBound() > 0;
+    }
+
+    public boolean canBeNegative() {
+        return lowerBound() < 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('i');
+        str.append(getBits());
+        if (lowerBound == upperBound) {
+            str.append(" [").append(lowerBound).append(']');
+        } else if (lowerBound != defaultMinValue(getBits()) || upperBound != defaultMaxValue(getBits())) {
+            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
+        }
+        if (downMask != 0) {
+            str.append(" \u21ca");
+            new Formatter(str).format("%016x", downMask);
+        }
+        if (upMask != defaultMask(getBits())) {
+            str.append(" \u21c8");
+            new Formatter(str).format("%016x", upMask);
+        }
+        return str.toString();
+    }
+
+    private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
+        assert getBits() == other.getBits();
+        if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0 || (newUpMask == 0 && (newLowerBound > 0 || newUpperBound < 0))) {
+            return illegal();
+        } else if (newLowerBound == lowerBound && newUpperBound == upperBound && newDownMask == downMask && newUpMask == upMask) {
+            return this;
+        } else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) {
+            return other;
+        } else {
+            return new IntegerStamp(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
+        }
+    }
+
+    @Override
+    public Stamp meet(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        if (!(otherStamp instanceof IntegerStamp)) {
+            return StampFactory.illegal(Kind.Illegal);
+        }
+        if (equals(otherStamp)) {
+            return this;
+        }
+        IntegerStamp other = (IntegerStamp) otherStamp;
+        return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
+    }
+
+    @Override
+    public Stamp join(Stamp otherStamp) {
+        if (otherStamp == this) {
+            return this;
+        }
+        if (!(otherStamp instanceof IntegerStamp)) {
+            return StampFactory.illegal(Kind.Illegal);
+        }
+        IntegerStamp other = (IntegerStamp) otherStamp;
+        long newDownMask = downMask | other.downMask;
+        long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask;
+        return createStamp(other, Math.min(upperBound, other.upperBound), newLowerBound, newDownMask, upMask & other.upMask);
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        if (this == stamp) {
+            return true;
+        }
+        if (stamp instanceof IntegerStamp) {
+            IntegerStamp other = (IntegerStamp) stamp;
+            return getBits() == other.getBits();
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + super.hashCode();
+        result = prime * result + (int) (lowerBound ^ (lowerBound >>> 32));
+        result = prime * result + (int) (upperBound ^ (upperBound >>> 32));
+        result = prime * result + (int) (downMask ^ (downMask >>> 32));
+        result = prime * result + (int) (upMask ^ (upMask >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
+            return false;
+        }
+        IntegerStamp other = (IntegerStamp) obj;
+        if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask) {
+            return false;
+        }
+        return true;
+    }
+
+    public static long defaultMask(int bits) {
+        assert 0 <= bits && bits <= 64;
+        if (bits == 64) {
+            return 0xffffffffffffffffL;
+        } else {
+            return (1L << bits) - 1;
+        }
+    }
+
+    public static long defaultMinValue(int bits) {
+        return -1L << (bits - 1);
+    }
+
+    public static long defaultMaxValue(int bits) {
+        return defaultMask(bits - 1);
+    }
+
+    public static long upMaskFor(int bits, long lowerBound, long upperBound) {
+        long mask = lowerBound | upperBound;
+        if (mask == 0) {
+            return 0;
+        } else {
+            return ((-1L) >>> Long.numberOfLeadingZeros(mask)) & defaultMask(bits);
+        }
+    }
+
+    /**
+     * Checks if the 2 stamps represent values of the same sign. Returns true if the two stamps are
+     * both positive of null or if they are both strictly negative
+     *
+     * @return true if the two stamps are both positive of null or if they are both strictly
+     *         negative
+     */
+    public static boolean sameSign(IntegerStamp s1, IntegerStamp s2) {
+        return s1.isPositive() && s2.isPositive() || s1.isStrictlyNegative() && s2.isStrictlyNegative();
+    }
+
+    @Override
+    public Constant asConstant() {
+        if (lowerBound == upperBound) {
+            switch (getBits()) {
+                case 1:
+                    return Constant.forBoolean(lowerBound != 0);
+                case 8:
+                    return Constant.forByte((byte) lowerBound);
+                case 16:
+                    return Constant.forShort((short) lowerBound);
+                case 32:
+                    return Constant.forInt((int) lowerBound);
+                case 64:
+                    return Constant.forLong(lowerBound);
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * 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.common.type;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.spi.*;
+
+public class ObjectStamp extends AbstractObjectStamp {
+
+    public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        super(type, exactType, nonNull, alwaysNull);
+    }
+
+    @Override
+    protected AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        return new ObjectStamp(type, exactType, nonNull, alwaysNull);
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return StampFactory.object();
+    }
+
+    @Override
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+        return tool.getObjectKind();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('a');
+        appendString(str);
+        return str.toString();
+    }
+
+    @Override
+    public boolean isCompatible(Stamp other) {
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof ObjectStamp) {
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.type;
+
+/**
+ * Type describing primitive values.
+ */
+public abstract class PrimitiveStamp extends Stamp {
+
+    private final int bits;
+
+    protected PrimitiveStamp(int bits) {
+        this.bits = bits;
+    }
+
+    /**
+     * The width in bits of the value described by this stamp.
+     */
+    public int getBits() {
+        return bits;
+    }
+
+    public static int getBits(Stamp stamp) {
+        if (stamp instanceof PrimitiveStamp) {
+            return ((PrimitiveStamp) stamp).getBits();
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + bits;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof PrimitiveStamp) {
+            PrimitiveStamp other = (PrimitiveStamp) obj;
+            return bits == other.bits;
+        }
+        return false;
+    }
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.compiler.common.spi.*;
 
 /**
- * A stamp is the basis for a type system over the nodes in a graph.
+ * A stamp is the basis for a type system.
  */
 public abstract class Stamp {
 
@@ -54,16 +54,15 @@
      * Gets a platform dependent {@link PlatformKind} that can be used to store a value of this
      * stamp.
      */
-    public abstract PlatformKind getPlatformKind(LIRTypeTool tool);
+    public abstract PlatformKind getPlatformKind(PlatformKindTool tool);
 
     /**
-     * Returns the union of this stamp and the given stamp. Typically used to create stamps for
-     * {@link ValuePhiNode}s.
+     * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi
+     * nodes.
      *
      * @param other The stamp that will enlarge this stamp.
      * @return The union of this stamp and the given stamp.
      */
-    @SuppressWarnings("javadoc")
     public abstract Stamp meet(Stamp other);
 
     /**
@@ -89,6 +88,15 @@
     public abstract Stamp illegal();
 
     /**
+     * If it is possible to represent single value stamps of this kind, this method returns the
+     * stamp representing the single value c. stamp.constant(c).asConstant() should be equal to c.
+     * <p>
+     * If it is not possible to represent single value stamps, this method returns a stamp that
+     * includes c, and is otherwise as narrow as possible.
+     */
+    public abstract Stamp constant(Constant c, MetaAccessProvider meta);
+
+    /**
      * Test whether two stamps have the same base type.
      */
     public abstract boolean isCompatible(Stamp other);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,253 @@
+/*
+ * 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.common.type;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+
+public class StampFactory {
+
+    // JaCoCo Exclude
+
+    private static final Stamp[] stampCache = new Stamp[Kind.values().length];
+    private static final Stamp[] illegalStampCache = new Stamp[Kind.values().length];
+    private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
+    private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
+    private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
+    private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false);
+    private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
+
+    private static void setCache(Kind kind, Stamp stamp) {
+        stampCache[kind.ordinal()] = stamp;
+    }
+
+    private static void setIntCache(Kind kind) {
+        int bits = kind.getStackKind().getBitCount();
+        long mask;
+        if (kind.isUnsigned()) {
+            mask = IntegerStamp.defaultMask(kind.getBitCount());
+        } else {
+            mask = IntegerStamp.defaultMask(bits);
+        }
+        setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
+    }
+
+    private static void setFloatCache(Kind kind) {
+        setCache(kind, new FloatStamp(kind.getBitCount()));
+    }
+
+    static {
+        setIntCache(Kind.Boolean);
+        setIntCache(Kind.Byte);
+        setIntCache(Kind.Short);
+        setIntCache(Kind.Char);
+        setIntCache(Kind.Int);
+        setIntCache(Kind.Long);
+
+        setFloatCache(Kind.Float);
+        setFloatCache(Kind.Double);
+
+        setCache(Kind.Object, objectStamp);
+        setCache(Kind.Void, VoidStamp.getInstance());
+
+        for (Kind k : Kind.values()) {
+            if (stampCache[k.ordinal()] != null) {
+                illegalStampCache[k.ordinal()] = stampCache[k.ordinal()].illegal();
+            } else {
+                illegalStampCache[k.ordinal()] = IllegalStamp.getInstance();
+            }
+        }
+    }
+
+    /**
+     * Return a stamp for a Java kind, as it would be represented on the bytecode stack.
+     */
+    public static Stamp forKind(Kind kind) {
+        assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")";
+        return stampCache[kind.ordinal()];
+    }
+
+    /**
+     * Return the stamp for the {@code void} type. This will return a singleton instance than can be
+     * compared using {@code ==}.
+     */
+    public static Stamp forVoid() {
+        return VoidStamp.getInstance();
+    }
+
+    /**
+     * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an
+     * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated.
+     */
+    public static Stamp forNodeIntrinsic() {
+        return nodeIntrinsicStamp;
+    }
+
+    public static Stamp intValue() {
+        return forKind(Kind.Int);
+    }
+
+    public static Stamp positiveInt() {
+        return positiveInt;
+    }
+
+    public static Stamp illegal() {
+        return illegal(Kind.Illegal);
+    }
+
+    public static Stamp illegal(Kind kind) {
+        return illegalStampCache[kind.ordinal()];
+    }
+
+    public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound, long downMask, long upMask) {
+        return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
+    }
+
+    public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound) {
+        return forInteger(kind.getBitCount(), lowerBound, upperBound);
+    }
+
+    public static IntegerStamp forInteger(int bits) {
+        return new IntegerStamp(bits, IntegerStamp.defaultMinValue(bits), IntegerStamp.defaultMaxValue(bits), 0, IntegerStamp.defaultMask(bits));
+    }
+
+    public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
+        long defaultMask = IntegerStamp.defaultMask(bits);
+        if (lowerBound == upperBound) {
+            return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask);
+        }
+        final long downMask;
+        final long upMask;
+        if (lowerBound >= 0) {
+            int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound);
+            long differentBits = lowerBound ^ upperBound;
+            int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
+
+            upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount);
+            downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
+        } else {
+            if (upperBound >= 0) {
+                upMask = defaultMask;
+                downMask = 0;
+            } else {
+                int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound);
+                long differentBits = lowerBound ^ upperBound;
+                int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
+
+                upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
+                downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
+            }
+        }
+        return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask);
+    }
+
+    public static FloatStamp forFloat(Kind kind, double lowerBound, double upperBound, boolean nonNaN) {
+        assert kind.isNumericFloat();
+        return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN);
+    }
+
+    public static Stamp forConstant(Constant value) {
+        Kind kind = value.getKind();
+        switch (kind) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+            case Long:
+                long mask = value.asLong() & IntegerStamp.defaultMask(kind.getBitCount());
+                return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask);
+            case Float:
+                return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
+            case Double:
+                return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
+            case Illegal:
+                return illegal(Kind.Illegal);
+            case Object:
+                if (value.isNull()) {
+                    return alwaysNull();
+                } else {
+                    return objectNonNull();
+                }
+            default:
+                throw new GraalInternalError("unexpected kind: %s", kind);
+        }
+    }
+
+    public static Stamp forConstant(Constant value, MetaAccessProvider metaAccess) {
+        if (value.getKind() == Kind.Object) {
+            ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value);
+            return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
+        } else {
+            return forConstant(value);
+        }
+    }
+
+    public static Stamp object() {
+        return objectStamp;
+    }
+
+    public static Stamp objectNonNull() {
+        return objectNonNullStamp;
+    }
+
+    public static Stamp alwaysNull() {
+        return objectAlwaysNullStamp;
+    }
+
+    public static Stamp declared(ResolvedJavaType type) {
+        return declared(type, false);
+    }
+
+    public static Stamp declaredNonNull(ResolvedJavaType type) {
+        return declared(type, true);
+    }
+
+    public static Stamp declared(ResolvedJavaType type, boolean nonNull) {
+        return object(type, false, nonNull);
+    }
+
+    public static Stamp object(ResolvedJavaType type, boolean exactType, boolean nonNull) {
+        assert type != null;
+        assert type.getKind() == Kind.Object;
+        ResolvedJavaType exact = type.asExactType();
+        if (exact != null) {
+            assert !exactType || type.equals(exact);
+            return new ObjectStamp(exact, true, nonNull, false);
+        } else {
+            return new ObjectStamp(type, exactType, nonNull, false);
+        }
+    }
+
+    public static Stamp exactNonNull(ResolvedJavaType type) {
+        if (ObjectStamp.isConcreteType(type)) {
+            return new ObjectStamp(type, true, true, false);
+        } else {
+            return illegal(Kind.Object);
+        }
+    }
+
+    public static Stamp exact(ResolvedJavaType type) {
+        return new ObjectStamp(type, true, false, false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,28 @@
+/*
+ * 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.common.type;
+
+public interface StampProvider {
+
+    Stamp stamp();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.type;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.spi.*;
+
+/**
+ * Singleton stamp representing the value of type {@code void}.
+ */
+public final class VoidStamp extends Stamp {
+
+    private VoidStamp() {
+    }
+
+    @Override
+    public Stamp unrestricted() {
+        return this;
+    }
+
+    @Override
+    public Kind getStackKind() {
+        return Kind.Void;
+    }
+
+    @Override
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
+        throw GraalInternalError.shouldNotReachHere("void stamp has no value");
+    }
+
+    @Override
+    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
+        return metaAccess.lookupJavaType(Void.TYPE);
+    }
+
+    @Override
+    public String toString() {
+        return "void";
+    }
+
+    @Override
+    public boolean alwaysDistinct(Stamp other) {
+        return this != other;
+    }
+
+    @Override
+    public Stamp meet(Stamp other) {
+        if (other instanceof IllegalStamp) {
+            return other.join(this);
+        }
+        if (this == other) {
+            return this;
+        }
+        return StampFactory.illegal(Kind.Illegal);
+    }
+
+    @Override
+    public Stamp join(Stamp other) {
+        if (other instanceof IllegalStamp) {
+            return other.join(this);
+        }
+        if (this == other) {
+            return this;
+        }
+        return StampFactory.illegal(Kind.Illegal);
+    }
+
+    @Override
+    public boolean isCompatible(Stamp stamp) {
+        return this == stamp;
+    }
+
+    @Override
+    public Stamp illegal() {
+        // there is no illegal void stamp
+        return this;
+    }
+
+    @Override
+    public boolean isLegal() {
+        return true;
+    }
+
+    @Override
+    public Stamp constant(Constant c, MetaAccessProvider meta) {
+        throw GraalInternalError.shouldNotReachHere("void stamp has no value");
+    }
+
+    private static VoidStamp instance = new VoidStamp();
+
+    static VoidStamp getInstance() {
+        return instance;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/ForceDeoptSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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.hsail.test.infra;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.api.meta.*;
+
+@ClassSubstitution(GraalKernelTester.class)
+class ForceDeoptSubstitutions {
+
+    /**
+     * Allows us to force a non-exception throwing deopt from java code.
+     */
+    @MethodSubstitution
+    public static int forceDeopt(int x) {
+        DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        // will never get here but keep the compiler happy
+        return x * x;
+    }
+
+    @MethodSubstitution
+    public static double forceDeopt(double x) {
+        DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        // will never get here but keep the compiler happy
+        return x * x;
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Fri May 30 15:09:09 2014 +0200
@@ -27,8 +27,8 @@
  * This class extends KernelTester and provides a base class
  * for which the HSAIL code comes from the Graal compiler.
  */
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 import static org.junit.Assume.*;
 
 import java.io.*;
@@ -47,12 +47,21 @@
 import com.oracle.graal.hsail.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.OptionValue.OverrideScope;
-import com.oracle.graal.phases.*;
 
 public abstract class GraalKernelTester extends KernelTester {
 
+    private static boolean substitutionsInstalled;
+
+    private static synchronized void installSubstitutions() {
+        if (!substitutionsInstalled) {
+            getHSAILBackend().getProviders().getReplacements().registerSubstitutions(GraalKernelTester.class, ForceDeoptSubstitutions.class);
+            substitutionsInstalled = true;
+        }
+    }
+
     public GraalKernelTester() {
         super(getHSAILBackend().isDeviceInitialized());
+        installSubstitutions();
     }
 
     protected static HSAILHotSpotBackend getHSAILBackend() {
@@ -122,19 +131,18 @@
     }
 
     /**
+     * Determines if the JVM supports the required typeProfileWidth.
+     */
+    public boolean typeProfileWidthAtLeast(int val) {
+        return (getHSAILBackend().getRuntime().getConfig().typeProfileWidth >= val);
+    }
+
+    /**
      * Determines if the runtime supports {@link VirtualObject}s in {@link DebugInfo} associated
      * with HSAIL code.
      */
     public boolean canHandleDeoptVirtualObjects() {
-        return false;
-    }
-
-    /**
-     * Determines if the runtime supports {@link StackSlot}s in {@link DebugInfo} associated with
-     * HSAIL code.
-     */
-    public boolean canHandleDeoptStackSlots() {
-        return false;
+        return true;
     }
 
     /**
@@ -182,7 +190,7 @@
     @Override
     public void testGeneratedHsail() {
         try (OverrideScope s = getOverrideScope()) {
-            assumeTrue(supportsRequiredCapabilities());
+            assumeTrue(supportsRequiredCapabilities() && okraEnvIsInitialized());
             super.testGeneratedHsail();
         }
     }
@@ -190,8 +198,18 @@
     @Override
     public void testGeneratedHsailUsingLambdaMethod() {
         try (OverrideScope s = getOverrideScope()) {
-            assumeTrue(supportsRequiredCapabilities());
+            assumeTrue(supportsRequiredCapabilities() && okraEnvIsInitialized());
             super.testGeneratedHsailUsingLambdaMethod();
         }
     }
+
+    // used for forcing a deoptimization
+    public static int forceDeopt(int x) {
+        return x * x;
+    }
+
+    public static double forceDeopt(double x) {
+        return x * x;
+    }
+
 }
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java	Fri May 30 15:09:09 2014 +0200
@@ -34,16 +34,19 @@
 import java.util.logging.*;
 
 import com.amd.okra.*;
+import com.oracle.graal.test.*;
 
 /**
  * Abstract class on which the HSAIL unit tests are built. Executes a method or lambda on both the
  * Java side and the Okra side and compares the results for fields that are annotated with
- * {@link KernelTester.Result}.
+ * {@link Result}.
  */
-public abstract class KernelTester {
+public abstract class KernelTester extends GraalTest {
 
     /**
-     * Denotes a field whose value is to be compared as part of computing the result of a test.
+     * Denotes a field whose value is to be
+     * {@linkplain KernelTester#assertResultFieldsEqual(KernelTester) compared} as part of computing
+     * the result of a test.
      */
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
@@ -118,10 +121,27 @@
         return onSimulator;
     }
 
+    public boolean okraEnvIsInitialized() {
+        return this.okraLibExists;
+    }
+
     public KernelTester(boolean okraLibExists) {
         dispatchMode = DispatchMode.SEQ;
         hsailMode = HsailMode.COMPILED;
         useLambdaMethod = false;
+
+        if (okraLibExists == false) {
+            // The okra native lib is not loaded yet, try to load the OkraContext
+            // explicitly and report a more useful error if there is a problem
+            try {
+                Class.forName("OkraContext");
+            } catch (Exception e) {
+                logger.info("Okra native library cannot be found or loaded while running" + this.getClass().getSimpleName());
+                this.okraLibExists = false;
+                return;
+            }
+        }
+
         // Control which okra instances can run the tests (is Simulator is static).
         onSimulator = OkraContext.isSimulator();
         this.okraLibExists = okraLibExists;
@@ -129,171 +149,27 @@
 
     public abstract void runTest();
 
-    // Default comparison is to compare all things marked @Result.
-    public boolean compareResults(KernelTester base) {
+    /**
+     * Asserts that the value of all {@link Result} annotated fields in this object and
+     * {@code other} are {@linkplain #assertDeepEquals(Object, Object) equal}.
+     *
+     * @throws AssertionError if the value of a result field in this and {@code other} are not equal
+     */
+    public void assertResultFieldsEqual(KernelTester other) {
         Class<?> clazz = this.getClass();
         while (clazz != null && clazz != KernelTester.class) {
             for (Field f : clazz.getDeclaredFields()) {
                 if (!Modifier.isStatic(f.getModifiers())) {
                     Result annos = f.getAnnotation(Result.class);
                     if (annos != null) {
-                        logger.fine("@Result field = " + f);
-                        Object myResult = getFieldFromObject(f, this);
-                        Object otherResult = getFieldFromObject(f, base);
-                        boolean same = compareObjects(myResult, otherResult);
-                        logger.fine("comparing " + myResult + ", " + otherResult + ", match=" + same);
-                        if (!same) {
-                            logger.severe("mismatch comparing " + f + ", " + myResult + " vs. " + otherResult);
-                            logSevere("FAILED!!! " + this.getClass());
-                            return false;
-                        }
+                        Object actualResult = getFieldFromObject(f, this);
+                        Object expectedResult = getFieldFromObject(f, other);
+                        assertDeepEquals(f.toString(), expectedResult, actualResult);
                     }
                 }
             }
             clazz = clazz.getSuperclass();
         }
-        logInfo("PASSED: " + this.getClass());
-        return true;
-    }
-
-    private boolean compareObjects(Object first, Object second) {
-        if (first == null) {
-            return (second == null);
-        }
-        if (second == null) {
-            return (first == null);
-        }
-        Class<?> clazz = first.getClass();
-        if (clazz != second.getClass()) {
-            return false;
-        }
-        if (!clazz.isArray()) {
-            // Non arrays.
-            if (clazz.equals(float.class) || clazz.equals(double.class)) {
-                return isEqualsFP((double) first, (double) second);
-            } else {
-                return first.equals(second);
-            }
-        } else {
-            // Handle the case where Objects are arrays.
-            ArrayComparer comparer;
-            if (clazz.equals(float[].class) || clazz.equals(double[].class)) {
-                comparer = new FPArrayComparer();
-            } else if (clazz.equals(long[].class) || clazz.equals(int[].class) || clazz.equals(byte[].class)) {
-                comparer = new IntArrayComparer();
-            } else if (clazz.equals(boolean[].class)) {
-                comparer = new BooleanArrayComparer();
-            } else {
-                comparer = new ObjArrayComparer();
-            }
-            return comparer.compareArrays(first, second);
-        }
-    }
-
-    static final int MISMATCHLIMIT = 10;
-    static final int ELEMENTDISPLAYLIMIT = 20;
-
-    public int getMisMatchLimit() {
-        return MISMATCHLIMIT;
-    }
-
-    public int getElementDisplayLimit() {
-        return ELEMENTDISPLAYLIMIT;
-    }
-
-    abstract class ArrayComparer {
-
-        abstract Object getElement(Object ary, int index);
-
-        // Equality test, can be overridden
-        boolean isEquals(Object firstElement, Object secondElement) {
-            return firstElement.equals(secondElement);
-        }
-
-        boolean compareArrays(Object first, Object second) {
-            int len = Array.getLength(first);
-            if (len != Array.getLength(second)) {
-                return false;
-            }
-            // If info logLevel, build string of first few elements from first array.
-            if (logLevel.intValue() <= Level.INFO.intValue()) {
-                StringBuilder sb = new StringBuilder();
-                for (int i = 0; i < Math.min(len, getElementDisplayLimit()); i++) {
-                    sb.append(getElement(first, i));
-                    sb.append(", ");
-                }
-                logger.info(sb.toString());
-            }
-            boolean success = true;
-            int mismatches = 0;
-            for (int i = 0; i < len; i++) {
-                Object firstElement = getElement(first, i);
-                Object secondElement = getElement(second, i);
-                if (!isEquals(firstElement, secondElement)) {
-                    logSevere("mismatch at index " + i + ", expected " + secondElement + ", saw " + firstElement);
-                    success = false;
-                    mismatches++;
-                    if (mismatches >= getMisMatchLimit()) {
-                        logSevere("...Truncated");
-                        break;
-                    }
-                }
-            }
-            return success;
-        }
-    }
-
-    class FPArrayComparer extends ArrayComparer {
-
-        @Override
-        Object getElement(Object ary, int index) {
-            return Array.getDouble(ary, index);
-        }
-
-        @Override
-        boolean isEquals(Object firstElement, Object secondElement) {
-            return isEqualsFP((double) firstElement, (double) secondElement);
-        }
-    }
-
-    class IntArrayComparer extends ArrayComparer {
-
-        @Override
-        Object getElement(Object ary, int index) {
-            return Array.getLong(ary, index);
-        }
-    }
-
-    class BooleanArrayComparer extends ArrayComparer {
-
-        @Override
-        Object getElement(Object ary, int index) {
-            return Array.getBoolean(ary, index);
-        }
-    }
-
-    class ObjArrayComparer extends ArrayComparer {
-
-        @Override
-        Object getElement(Object ary, int index) {
-            return Array.get(ary, index);
-        }
-
-        @Override
-        boolean isEquals(Object firstElement, Object secondElement) {
-            return compareObjects(firstElement, secondElement);
-        }
-    }
-
-    /**
-     * Tests two floating point values for equality.
-     */
-    public boolean isEqualsFP(double first, double second) {
-        // Special case for checking whether expected and actual values are both NaNs.
-        if (Double.isNaN(first) && Double.isNaN(second)) {
-            return true;
-        }
-        return first == second;
     }
 
     public void setDispatchMode(DispatchMode dispatchMode) {
@@ -761,8 +637,8 @@
         }
     }
 
-    private void compareOkraToSeq(HsailMode hsailModeToUse) {
-        compareOkraToSeq(hsailModeToUse, false);
+    private void assertOkraEqualsSeq(HsailMode hsailModeToUse) {
+        assertOkraEqualsSeq(hsailModeToUse, false);
     }
 
     /**
@@ -770,7 +646,7 @@
      * runOkraFirst flag controls which order they are done in. Note the compiler must use eager
      * resolving if Okra is done first.
      */
-    private void compareOkraToSeq(HsailMode hsailModeToUse, boolean useLambda) {
+    private void assertOkraEqualsSeq(HsailMode hsailModeToUse, boolean useLambda) {
         KernelTester testerSeq;
         if (runOkraFirst) {
             runOkraInstance(hsailModeToUse, useLambda);
@@ -779,7 +655,7 @@
             testerSeq = runSeqInstance();
             runOkraInstance(hsailModeToUse, useLambda);
         }
-        assertTrue("failed comparison to SEQ", compareResults(testerSeq));
+        assertResultFieldsEqual(testerSeq);
     }
 
     private void runOkraInstance(HsailMode hsailModeToUse, boolean useLambda) {
@@ -800,19 +676,19 @@
     }
 
     public void testGeneratedHsail() {
-        compareOkraToSeq(HsailMode.COMPILED);
+        assertOkraEqualsSeq(HsailMode.COMPILED);
     }
 
     public void testGeneratedHsailUsingLambdaMethod() {
-        compareOkraToSeq(HsailMode.COMPILED, true);
+        assertOkraEqualsSeq(HsailMode.COMPILED, true);
     }
 
     public void testInjectedHsail() {
-        newInstance().compareOkraToSeq(HsailMode.INJECT_HSAIL);
+        newInstance().assertOkraEqualsSeq(HsailMode.INJECT_HSAIL);
     }
 
     public void testInjectedOpencl() {
-        newInstance().compareOkraToSeq(HsailMode.INJECT_OCL);
+        newInstance().assertOkraEqualsSeq(HsailMode.INJECT_OCL);
     }
 
     protected static Object getFieldFromObject(Field f, Object fromObj) {
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Fri May 30 15:09:09 2014 +0200
@@ -27,13 +27,10 @@
 
 import org.junit.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.compiler.hsail.test.infra.*;
 
 /**
- * Tests {@link AtomicInteger#getAndAdd(int)} which indirectly tests
- * {@link Unsafe#compareAndSwapInt(Object, long, int, int)}.
+ * Tests {@link AtomicInteger#getAndAdd(int)} which tests HSAIL atomic_add codegen.
  */
 public class AtomicIntGetAndAddTest extends GraalKernelTester {
 
@@ -48,6 +45,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndSetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests {@link AtomicInteger#getAndSet(int)} which tests HSAIL atomic_exch codegen.
+ */
+public class AtomicIntGetAndSetTest extends GraalKernelTester {
+
+    static final int NUM = 1000;
+    @Result public int[] outArray = new int[NUM];
+    AtomicInteger atomicInt = new AtomicInteger(Integer.MAX_VALUE);
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+        }
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchMethodKernel(NUM);
+        // to complete the circle, replace the initial get value with that of the last executor
+        for (int i = 0; i < NUM; i++) {
+            if (outArray[i] == Integer.MAX_VALUE) {
+                outArray[i] = atomicInt.get();
+            }
+        }
+
+        // note: the actual order of entries in outArray is not predictable
+        // thus we sort before we compare results
+        Arrays.sort(outArray);
+    }
+
+    public void run(int gid) {
+        outArray[gid] = atomicInt.getAndSet(gid);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Fri May 30 15:09:09 2014 +0200
@@ -27,13 +27,10 @@
 
 import org.junit.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.compiler.hsail.test.infra.*;
 
 /**
- * Tests {@link AtomicLong#getAndAdd(long)} which indirectly tests
- * {@link Unsafe#compareAndSwapLong(Object, long, long, long)}.
+ * Tests {@link AtomicLong#getAndAdd(long)} which tests HSAIL atomic_add codegen.
  */
 public class AtomicLongGetAndAddTest extends GraalKernelTester {
 
@@ -48,6 +45,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndSetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests {@link AtomicLong#getAndSet(long)} which tests HSAIL atomic_exch codegen.
+ */
+public class AtomicLongGetAndSetTest extends GraalKernelTester {
+
+    static final int NUM = 1000;
+    @Result public long[] outArray = new long[NUM];
+    AtomicLong atomicLong = new AtomicLong(Long.MAX_VALUE);
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+        }
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchMethodKernel(NUM);
+        // to complete the circle, replace the initial get value with that of the last executor
+        for (int i = 0; i < NUM; i++) {
+            if (outArray[i] == Long.MAX_VALUE) {
+                outArray[i] = atomicLong.get();
+            }
+        }
+
+        // note: the actual order of entries in outArray is not predictable
+        // thus we sort before we compare results
+        Arrays.sort(outArray);
+    }
+
+    public void run(int gid) {
+        outArray[gid] = atomicLong.getAndSet(gid);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java	Fri May 30 15:09:09 2014 +0200
@@ -33,11 +33,6 @@
         return (gid < 4096 && gid % 512 == 1);
     }
 
-    @Override
-    public int getMisMatchLimit() {
-        return 1000;
-    }
-
     public void run(int gid) {
         int outval = getOutval(gid);
         try {
--- /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/DVec3.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+/**
+ * A simple 3 element Vector object used in some junit tests.
+ */
+public class DVec3 {
+
+    public DVec3(double x, double y, double z) {
+        this.x = x;
+        this.y = y;
+        this.z = z;
+    }
+
+    public double x;
+    public double y;
+    public double z;
+
+    public static DVec3 add(DVec3 a, DVec3 b) {
+        return new DVec3(a.x + b.x, a.y + b.y, a.z + b.z);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof DVec3)) {
+            return false;
+        }
+        DVec3 oth = (DVec3) other;
+        return (oth.x == x && oth.y == y && oth.z == z);
+    }
+
+    @Override
+    public String toString() {
+        return ("DVec3[" + x + ", " + y + ", " + z + "]");
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) (x + y + z);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewFloatStringTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewFloatStringTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.compiler.hsail.test;
 
+import org.junit.*;
+
 /**
  * Tests creating a new String from a float.
  */
@@ -35,8 +37,8 @@
         myOutArray[gid] = Float.toString(gid * 2.22f);
     }
 
-    // problems runs out of memory space while inlining
-    // @Test
+    @Ignore("problems runs out of memory space while inlining")
+    @Test
     public void test() {
         testGeneratedHsail();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewStringConcatTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/EscapingNewStringConcatTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,7 +24,7 @@
 
 import static com.oracle.graal.debug.Debug.*;
 
-import org.junit.Test;
+import org.junit.*;
 
 import com.oracle.graal.debug.*;
 
@@ -51,7 +51,8 @@
     }
 
     // Node implementing Lowerable not handled in HSAIL Backend: 6274|MonitorEnter
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsail();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/FloatDivPrecisionTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/FloatDivPrecisionTest.java	Fri May 30 15:09:09 2014 +0200
@@ -49,8 +49,8 @@
     }
 
     @Override
-    public boolean isEqualsFP(double first, double second) {
-        return Math.abs(first - second) == 0;
+    protected double equalFloatsOrDoublesDelta() {
+        return 0.0D;
     }
 
     @Test
--- /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/ObjSpillDeoptBase.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,93 @@
+/*
+ * 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 java.util.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Base class for testing deopt when objects are in stack slots.
+ */
+public abstract class ObjSpillDeoptBase extends GraalKernelTester {
+
+    abstract int getSize();
+
+    int loopcount = 5;
+    int objcount = 20;
+    @Result double[] out = new double[getSize()];
+    @Result double[] aux = new double[getSize()];
+    DVec3[] in = new DVec3[objcount];
+
+    public void doCompute(int gid, boolean causeDeopt) {
+        int idx = gid * 2 + 7;
+        DVec3 v0 = in[(idx++) % objcount];
+        DVec3 v1 = in[(idx++) % objcount];
+        DVec3 v2 = in[(idx++) % objcount];
+        DVec3 v3 = in[(idx++) % objcount];
+        DVec3 v4 = in[(idx++) % objcount];
+        DVec3 v5 = in[(idx++) % objcount];
+        DVec3 v6 = in[(idx++) % objcount];
+        DVec3 v7 = in[(idx++) % objcount];
+        DVec3 v8 = in[(idx++) % objcount];
+        DVec3 v9 = in[(idx++) % objcount];
+        idx += gid;
+        DVec3 v10 = in[(idx++) % objcount];
+        DVec3 v11 = in[(idx++) % objcount];
+        DVec3 v12 = in[(idx++) % objcount];
+        DVec3 v13 = in[(idx++) % objcount];
+        DVec3 v14 = in[(idx++) % objcount];
+        DVec3 v15 = in[(idx++) % objcount];
+        DVec3 v16 = in[(idx++) % objcount];
+        DVec3 v17 = in[(idx++) % objcount];
+        DVec3 v18 = in[(idx++) % objcount];
+        DVec3 v19 = in[(idx++) % objcount];
+        double sum = 0.0;
+        double sum1 = 0.0;
+        double sum2 = 0.0;
+        for (int i = 0; i < loopcount; i++) {
+            sum1 += v0.x + v1.y + v2.z + v3.x + v4.y + v5.z + v6.x + v7.y + v8.z + v9.x + i;
+            sum2 += v10.y + v11.z + v12.x + v13.y + v14.z + v15.x + v16.y + v17.z + v18.x + v19.y - i;
+            sum += sum1 - sum2 + i;
+            aux[gid] += sum1 + 1.2345;
+        }
+        if (causeDeopt) {
+            aux[gid] += forceDeopt(sum1);
+        }
+        out[gid] += sum;
+    }
+
+    @Override
+    public void runTest() {
+        Arrays.fill(out, -1.0);
+        for (int i = 0; i < objcount; i++) {
+            in[i] = new DVec3(i / 10f, (i + 1) / 10f, (i + 2) / 10f);
+        }
+        dispatchMethodKernel(getSize());
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return canDeoptimize();
+    }
+}
--- /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/ObjSpillDeoptMany20000Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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 deopt with objects in stack slots, with many items deopting.
+ */
+public class ObjSpillDeoptMany20000Test extends ObjSpillDeoptManyBase {
+
+    @Override
+    int getSize() {
+        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/ObjSpillDeoptMany5000Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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 deopt with objects in stack slots, with many items deopting.
+ */
+public class ObjSpillDeoptMany5000Test extends ObjSpillDeoptManyBase {
+
+    @Override
+    int getSize() {
+        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/ObjSpillDeoptMany99999Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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 deopt with objects in stack slots, with many items deopting.
+ */
+public class ObjSpillDeoptMany99999Test extends ObjSpillDeoptManyBase {
+
+    @Override
+    int getSize() {
+        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/ObjSpillDeoptManyBase.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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 testing deopt with objects in stack slots, with many items deopting.
+ */
+public abstract class ObjSpillDeoptManyBase extends ObjSpillDeoptBase {
+
+    public void run(int gid) {
+        boolean causeDeopt = (gid < 4096 && gid % 512 == 1);
+        doCompute(gid, causeDeopt);
+    }
+}
--- /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/ObjSpillDeoptMost20000Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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 deopt with objects in stack slots, with most items deopting.
+ */
+public class ObjSpillDeoptMost20000Test extends ObjSpillDeoptMostBase {
+
+    @Override
+    int getSize() {
+        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/ObjSpillDeoptMost5000Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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 deopt with objects in stack slots, with most items deopting.
+ */
+public class ObjSpillDeoptMost5000Test extends ObjSpillDeoptMostBase {
+
+    @Override
+    int getSize() {
+        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/ObjSpillDeoptMost99999Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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 deopt with objects in stack slots, with most items deopting.
+ */
+public class ObjSpillDeoptMost99999Test extends ObjSpillDeoptMostBase {
+
+    @Override
+    int getSize() {
+        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/ObjSpillDeoptMostBase.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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 testing deopt with objects in stack slots.
+ */
+public abstract class ObjSpillDeoptMostBase extends ObjSpillDeoptBase {
+
+    public void run(int gid) {
+        boolean causeDeopt = (gid % 500 != 1);
+        doCompute(gid, causeDeopt);
+    }
+}
--- /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/ObjSpillDeoptSingle100Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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 deopt with objects in stack slots, one item deopting.
+ */
+public class ObjSpillDeoptSingle100Test extends ObjSpillDeoptBase {
+
+    final int size = 100;
+
+    @Override
+    int getSize() {
+        return size;
+    }
+
+    public void run(int gid) {
+        boolean causeDeopt = (gid == size / 2);
+        doCompute(gid, causeDeopt);
+    }
+
+    @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/ObjSpillDeoptSingle20000Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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 deopt with objects in stack slots, one item deopting.
+ */
+public class ObjSpillDeoptSingle20000Test extends ObjSpillDeoptBase {
+
+    final int size = 20000;
+
+    @Override
+    int getSize() {
+        return size;
+    }
+
+    public void run(int gid) {
+        boolean causeDeopt = (gid == size / 2);
+        doCompute(gid, causeDeopt);
+    }
+
+    @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/StaticDoubleSpillBoundsCatchOneTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,142 @@
+/*
+ * 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 java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests the spilling of double variables into memory with deopt
+ */
+public class StaticDoubleSpillBoundsCatchOneTest extends GraalKernelTester {
+
+    static final int size = 100;
+    private double[] in = new double[size * 400];
+    @Result public double[] out = new double[size * 400];
+    @Result public double[] aux = new double[2];
+
+    public static void run(double[] out, double[] in, double[] aux, int gid) {
+        int id = gid;
+        int step = 20;
+        double sum0;
+        double sum1;
+        double sum2;
+        double sum3;
+        double sum4;
+        double sum5;
+        double sum6;
+        double sum7;
+        double sum8;
+        double sum9;
+        double sum10;
+        double sum11;
+        double sum12;
+        double sum13;
+        double sum14;
+        double sum15;
+        double sum16;
+        double sum17;
+        double sum18;
+        double sum19;
+        sum0 = sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = sum7 = sum8 = sum9 = 0;
+        sum10 = sum11 = sum12 = sum13 = sum14 = sum15 = sum16 = sum17 = sum18 = sum19 = 0;
+        try {
+            for (int i = 0; i < size; i += step) {
+                sum0 += in[i + 0];
+                sum1 += in[i + 1];
+                sum2 += in[i + 2];
+                sum3 += in[i + 3];
+                sum4 += in[i + 4];
+                sum5 += in[i + 5];
+                sum6 += in[i + 6];
+                sum7 += in[i + 7];
+                sum8 += in[i + 8];
+                sum9 += in[i + 9];
+                sum10 += in[i + 0];
+                sum11 += in[i + 1];
+                sum12 += in[i + 2];
+                sum13 += in[i + 3];
+                sum14 += in[i + 4];
+                sum15 += in[i + 5];
+                sum16 += in[i + 6];
+                sum17 += in[i + 7];
+                sum18 += in[i + 8];
+                sum19 += in[i + 9];
+
+                if (id == size / 2) {
+                    aux[id] = sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7 + sum8 + sum9 + sum10 + sum11 + sum12 + sum13 + sum14 + sum15 + sum16;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            aux[0] += sum1 + sum2;
+        }
+
+        out[id * step + 0] = sum0;
+        out[id * step + 1] = sum1;
+        out[id * step + 2] = sum2;
+        out[id * step + 3] = sum3;
+        out[id * step + 4] = sum4;
+        out[id * step + 5] = sum5;
+        out[id * step + 6] = sum6;
+        out[id * step + 7] = sum7;
+        out[id * step + 8] = sum8;
+        out[id * step + 9] = sum9;
+        out[id * step + 10] = sum10;
+        out[id * step + 11] = sum11;
+        out[id * step + 12] = sum12;
+        out[id * step + 13] = sum13;
+        out[id * step + 14] = sum14;
+        out[id * step + 15] = sum15;
+        out[id * step + 16] = sum16;
+        out[id * step + 17] = sum17;
+        out[id * step + 18] = sum18;
+        out[id * step + 19] = sum19;
+    }
+
+    @Override
+    public void runTest() {
+        /**
+         * Call it for a range, specifying testmethod args (but not the fields it uses or the gid
+         * argument).
+         * 
+         */
+        Arrays.fill(out, -1f);
+        for (int i = 0; i < size; i++) {
+            in[i] = i + 1;
+        }
+        dispatchMethodKernel(size, out, in, aux);
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return canDeoptimize();
+    }
+
+    @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/StaticDoubleSpillBoundsCatchTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,146 @@
+/*
+ * 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 java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests the spilling of double variables into memory with deopt
+ */
+public class StaticDoubleSpillBoundsCatchTest extends GraalKernelTester {
+
+    static final int size = 100;
+    private double[] in = new double[size * 400];
+    @Result public double[] out = new double[size * 400];
+    @Result public double[] aux = new double[size];
+
+    public static void run(double[] out, double[] in, double[] aux, int gid) {
+        int id = gid;
+        int step = 20;
+        double sum0;
+        double sum1;
+        double sum2;
+        double sum3;
+        double sum4;
+        double sum5;
+        double sum6;
+        double sum7;
+        double sum8;
+        double sum9;
+        double sum10;
+        double sum11;
+        double sum12;
+        double sum13;
+        double sum14;
+        double sum15;
+        double sum16;
+        double sum17;
+        double sum18;
+        double sum19;
+        sum0 = sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = sum7 = sum8 = sum9 = 0;
+        sum10 = sum11 = sum12 = sum13 = sum14 = sum15 = sum16 = sum17 = sum18 = sum19 = 0;
+        try {
+            for (int i = 0; i < size; i += step) {
+                sum0 += in[i + 0];
+                sum1 += in[i + 1];
+                sum2 += in[i + 2];
+                sum3 += in[i + 3];
+                sum4 += in[i + 4];
+                sum5 += in[i + 5];
+                sum6 += in[i + 6];
+                sum7 += in[i + 7];
+                sum8 += in[i + 8];
+                sum9 += in[i + 9];
+                sum10 += in[i + 0];
+                sum11 += in[i + 1];
+                sum12 += in[i + 2];
+                sum13 += in[i + 3];
+                sum14 += in[i + 4];
+                sum15 += in[i + 5];
+                sum16 += in[i + 6];
+                sum17 += in[i + 7];
+                sum18 += in[i + 8];
+                sum19 += in[i + 9];
+
+                if (id > size / 2) {
+                    aux[id + 10] += sum1 + sum2;
+                    // + sum3 + sum4 + sum5 + sum6 + sum7 + sum8 + sum9 + sum10 + sum11 + sum12 +
+                    // sum13 + sum14 + sum15 + sum16;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            aux[id] += sum1 + sum2;
+        }
+
+        out[id * step + 0] = sum0;
+        out[id * step + 1] = sum1;
+        out[id * step + 2] = sum2;
+        out[id * step + 3] = sum3;
+        out[id * step + 4] = sum4;
+        out[id * step + 5] = sum5;
+        out[id * step + 6] = sum6;
+        out[id * step + 7] = sum7;
+        out[id * step + 8] = sum8;
+        out[id * step + 9] = sum9;
+        out[id * step + 10] = sum10;
+        out[id * step + 11] = sum11;
+        out[id * step + 12] = sum12;
+        out[id * step + 13] = sum13;
+        out[id * step + 14] = sum14;
+        out[id * step + 15] = sum15;
+        out[id * step + 16] = sum16;
+        out[id * step + 17] = sum17;
+        out[id * step + 18] = sum18;
+        out[id * step + 19] = sum19;
+    }
+
+    @Override
+    public void runTest() {
+        /**
+         * Call it for a range, specifying testmethod args (but not the fields it uses or the gid
+         * argument).
+         * 
+         */
+        Arrays.fill(out, -1f);
+        Arrays.fill(aux, 0f);
+        for (int i = 0; i < size; i++) {
+            in[i] = i + 1;
+        }
+        dispatchMethodKernel(size, out, in, aux);
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return canDeoptimize();
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Fri May 30 15:09:09 2014 +0200
@@ -113,13 +113,13 @@
          * argument).
          * 
          */
-        Arrays.fill(out, 0f);
-        Arrays.fill(in, 0f);
+        Arrays.fill(out, -1f);
+        for (int i = 0; i < size; i++) {
+            in[i] = i + 1;
+        }
         dispatchMethodKernel(size, out, in);
     }
 
-    // Marked to only run on hardware until simulator spill bug is fixed.
-    @Ignore
     @Test
     public void test() {
         testGeneratedHsail();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Fri May 30 15:09:09 2014 +0200
@@ -87,8 +87,6 @@
         dispatchMethodKernel(size, out, in);
     }
 
-    // Marked to only run on hardware until simulator spill bug is fixed.
-    @Ignore
     @Test
     public void test() {
         testGeneratedHsail();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListGetTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListGetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -25,12 +25,12 @@
 
 import static com.oracle.graal.debug.Debug.*;
 
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import com.oracle.graal.debug.*;
+import java.util.*;
 
-import org.junit.Test;
+import org.junit.*;
 
-import java.util.ArrayList;
+import com.oracle.graal.compiler.hsail.test.infra.*;
+import com.oracle.graal.debug.*;
 
 /**
  * Tests calling ArrayList.get().
@@ -60,6 +60,7 @@
 
     // NYI emitForeignCall charAlignedDisjointArraycopy
     @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
     public void testUsingLambdaMethod() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetGidTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetGidTest.java	Fri May 30 15:09:09 2014 +0200
@@ -47,6 +47,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntAddAndGetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntDecAndGetTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntDecAndGetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndAddTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndAddTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndDecTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndDecTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndIncTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntGetAndIncTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntIncAndGetTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicIntIncAndGetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongAddAndGetTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongAddAndGetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -46,6 +46,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndAddTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndAddTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndIncTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongGetAndIncTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongIncAndGetTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/AtomicLongIncAndGetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,11 @@
     }
 
     @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canDeoptimize());
+    }
+
+    @Override
     public void runTest() {
         setupArrays();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ForEachToGraalTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ForEachToGraalTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,12 +23,13 @@
 
 package com.oracle.graal.compiler.hsail.test.lambda;
 
-import java.util.stream.IntStream;
-
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static org.junit.Assert.*;
-import org.junit.Test;
-import java.util.Arrays;
-import java.util.ArrayList;
+
+import java.util.*;
+import java.util.stream.*;
+
+import org.junit.*;
 
 /**
  * Several tests for the Sumatra APIs.
@@ -266,6 +267,10 @@
     // Graal throws NYI
     @Test
     public void testForEachIntRangeNoCapturesUseEscapingNew() {
+        if (runtime().getConfig().useHSAILDeoptimization == false) {
+            return;
+        }
+
         MyPoint[] dest = new MyPoint[size];
         IntStream range = IntStream.range(0, dest.length).parallel();
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Fri May 30 15:09:09 2014 +0200
@@ -25,11 +25,11 @@
 
 import static com.oracle.graal.debug.Debug.*;
 
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
 import com.oracle.graal.debug.*;
 
-import org.junit.Test;
-
 /**
  * Tests creating a String and calling .equals() on it.
  */
@@ -64,14 +64,16 @@
     }
 
     // NYI emitForeignCall charAlignedDisjointArraycopy
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsail();
         }
     }
 
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void testUsingLambdaMethod() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java	Fri May 30 15:09:09 2014 +0200
@@ -26,12 +26,12 @@
 import static com.oracle.graal.debug.Debug.*;
 import static com.oracle.graal.debug.DelegatingDebugConfig.Feature.*;
 
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import com.oracle.graal.debug.*;
+import java.util.*;
 
-import org.junit.Test;
+import org.junit.*;
 
-import java.util.Arrays;
+import com.oracle.graal.compiler.hsail.test.infra.*;
+import com.oracle.graal.debug.*;
 
 /**
  * Tests non-escaping object creation and calling a method on it.
@@ -78,14 +78,16 @@
     }
 
     // NYI emitForeignCall floatArraycopy
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsail();
         }
     }
 
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void testUsingLambdaMethod() {
         try (DebugConfigScope dcs = setConfig(new DelegatingDebugConfig().disable(INTERCEPT))) {
             testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ObjectArrayInstanceDerivedTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ObjectArrayInstanceDerivedTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,8 @@
 
 package com.oracle.graal.compiler.hsail.test.lambda;
 
+import org.junit.*;
+
 import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
 
 /**
@@ -69,12 +71,14 @@
         });
     }
 
-    // @Test
+    @Ignore
+    @Test
     public void test() {
         testGeneratedHsail();
     }
 
-    // @Test
+    @Ignore
+    @Test
     public void testUsingLambdaMethod() {
         testGeneratedHsailUsingLambdaMethod();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ObjectArrayInstanceTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ObjectArrayInstanceTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,7 +24,8 @@
 package com.oracle.graal.compiler.hsail.test.lambda;
 
 import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import org.junit.Test;
+
+import org.junit.*;
 
 /**
  * Tests calling a method on an object when there are no derived types of that object.
@@ -53,11 +54,13 @@
         });
     }
 
+    @Ignore
     @Test
     public void test() {
         testGeneratedHsail();
     }
 
+    @Ignore
     @Test
     public void testUsingLambdaMethod() {
         testGeneratedHsailUsingLambdaMethod();
--- /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/lambda/VecmathNBodyDeoptTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,138 @@
+/*
+ * 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.lambda;
+
+import java.util.*;
+import org.junit.*;
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import javax.vecmath.*;
+
+/**
+ * Tests NBody algorithm using the javax.vecmath package (all objects non-escaping).
+ */
+public class VecmathNBodyDeoptTest extends GraalKernelTester {
+    static final int bodies = 1024;
+    static final float delT = .005f;
+    static final float espSqr = 1.0f;
+    static final float mass = 5f;
+    static final int width = 768;
+    static final int height = 768;
+
+    static class Body extends Vector3f {
+
+        /**
+         *
+         */
+        private static final long serialVersionUID = 1L;
+
+        public Body(float _x, float _y, float _z, float _m) {
+            super(_x, _y, _z);
+            m = _m;
+            v = new Vector3f(0, 0, 0);
+        }
+
+        float m;
+        Vector3f v;
+
+        public float getM() {
+            return m;
+        }
+
+        public Vector3f computeAcc(Body[] in_bodies, float espSqr1, float delT1) {
+            Vector3f acc = new Vector3f();
+
+            for (Body b : in_bodies) {
+                Vector3f d = new Vector3f();
+                d.sub(b, this);
+                float invDist = 1.0f / (float) Math.sqrt(d.lengthSquared() + espSqr1);
+                float s = b.getM() * invDist * invDist * invDist;
+                acc.scaleAdd(s, d, acc);
+            }
+
+            // now return acc scaled by delT
+            acc.scale(delT1);
+            return acc;
+        }
+    }
+
+    @Result Body[] in_bodies = new Body[bodies];
+    @Result Body[] out_bodies = new Body[bodies];
+
+    static Body[] seed_bodies = new Body[bodies];
+
+    static {
+        java.util.Random randgen = new Random(0);
+        final float maxDist = width / 4;
+        for (int body = 0; body < bodies; body++) {
+            final float theta = (float) (randgen.nextFloat() * Math.PI * 2);
+            final float phi = (float) (randgen.nextFloat() * Math.PI * 2);
+            final float radius = randgen.nextFloat() * maxDist;
+            float x = (float) (radius * Math.cos(theta) * Math.sin(phi)) + width / 2;
+            float y = (float) (radius * Math.sin(theta) * Math.sin(phi)) + height / 2;
+            float z = (float) (radius * Math.cos(phi));
+            seed_bodies[body] = new Body(x, y, z, mass);
+        }
+    }
+
+    @Override
+    public void runTest() {
+        System.arraycopy(seed_bodies, 0, in_bodies, 0, seed_bodies.length);
+        for (int b = 0; b < bodies; b++) {
+            out_bodies[b] = new Body(0, 0, 0, mass);
+        }
+        // no local copies of arrays so we make it an instance lambda
+
+        dispatchLambdaKernel(bodies, (gid) -> {
+            Body inb = in_bodies[gid];
+            Body outb = out_bodies[gid];
+            Vector3f acc = inb.computeAcc(in_bodies, espSqr, delT);
+
+            Vector3f tmpPos = new Vector3f();
+            tmpPos.scaleAdd(delT, inb.v, inb);
+            if (gid == bodies / 2) {
+                tmpPos.x += forceDeopt(gid);
+            }
+            tmpPos.scaleAdd(0.5f * delT, acc, tmpPos);
+            outb.set(tmpPos);
+
+            outb.v.add(inb.v, acc);
+        });
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return (canHandleDeoptVirtualObjects() && canDeoptimize());
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+
+}
--- /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/lambda/VirtualCall3Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * 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.lambda;
+
+import org.junit.Test;
+
+/**
+ * Tests a true virtual method call with 3 targets.
+ */
+public class VirtualCall3Test extends VirtualCallBase {
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+            inShapeArray[i] = createShape(i % 3, i + 1);
+        }
+    }
+
+    // although runTest is the same in each class derived from VirtualCallBase
+    // we duplicate the logic in each derived test so as to have different lambda call sites
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchLambdaKernel(NUM, (gid) -> {
+            Shape shape = inShapeArray[gid];
+            outArray[gid] = shape.getArea();
+        });
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return typeProfileWidthAtLeast(3);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+
+}
--- /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/lambda/VirtualCall4Test.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * 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.lambda;
+
+import org.junit.Test;
+
+/**
+ * Tests a true virtual method call with 4 targets.
+ */
+public class VirtualCall4Test extends VirtualCallBase {
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+            inShapeArray[i] = createShape(i % 4, i + 1);
+        }
+    }
+
+    // although runTest is the same in each class derived from VirtualCallBase
+    // we duplicate the logic in each derived test so as to have different lambda call sites
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchLambdaKernel(NUM, (gid) -> {
+            Shape shape = inShapeArray[gid];
+            outArray[gid] = shape.getArea();
+        });
+    }
+
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return typeProfileWidthAtLeast(4);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+    @Test
+    public void testUsingLambdaMethod() {
+        testGeneratedHsailUsingLambdaMethod();
+    }
+
+}
--- /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/lambda/VirtualCallBase.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,117 @@
+/*
+ * 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.lambda;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+
+/**
+ * Base class for testing virtual method calls.
+ */
+abstract public class VirtualCallBase extends GraalKernelTester {
+
+    static final int NUM = 20000;
+
+    @Result public float[] outArray = new float[NUM];
+    public Shape[] inShapeArray = new Shape[NUM];
+
+    static abstract class Shape {
+
+        abstract public float getArea();
+    }
+
+    static class Circle extends Shape {
+
+        private float radius;
+
+        Circle(float r) {
+            radius = r;
+        }
+
+        @Override
+        public float getArea() {
+            return (float) (Math.PI * radius * radius);
+        }
+    }
+
+    static class Square extends Shape {
+
+        private float len;
+
+        Square(float _len) {
+            len = _len;
+        }
+
+        @Override
+        public float getArea() {
+            return len * len;
+        }
+    }
+
+    static class Triangle extends Shape {
+
+        private float base;
+        private float height;
+
+        Triangle(float base, float height) {
+            this.base = base;
+            this.height = height;
+        }
+
+        @Override
+        public float getArea() {
+            return (base * height / 2.0f);
+        }
+    }
+
+    static class Rectangle extends Shape {
+
+        private float base;
+        private float height;
+
+        Rectangle(float base, float height) {
+            this.base = base;
+            this.height = height;
+        }
+
+        @Override
+        public float getArea() {
+            return (base * height);
+        }
+    }
+
+    Shape createShape(int kind, int size) {
+        switch (kind) {
+            case 0:
+                return new Circle(size);
+            case 1:
+                return new Square(size);
+            case 2:
+                return new Triangle(size, size + 1);
+            case 3:
+                return new Rectangle(size, size + 1);
+            default:
+                return null;
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/VirtualCallTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,66 +23,23 @@
 
 package com.oracle.graal.compiler.hsail.test.lambda;
 
-import static com.oracle.graal.debug.Debug.*;
-
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import com.oracle.graal.debug.*;
-
 import org.junit.Test;
 
 /**
- * Tests a true virtual method call.
+ * Tests a true virtual method call with 2 targets.
  */
-public class VirtualCallTest extends GraalKernelTester {
-
-    static final int NUM = 20;
-
-    static abstract class Shape {
-
-        abstract public float getArea();
-    }
+public class VirtualCallTest extends VirtualCallBase {
 
-    static class Circle extends Shape {
-
-        private float radius;
-
-        Circle(float r) {
-            radius = r;
-        }
-
-        @Override
-        public float getArea() {
-            return (float) (Math.PI * radius * radius);
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+            int kind = i % 3 == 0 ? 0 : 1;
+            inShapeArray[i] = createShape(kind, i + 1);
         }
     }
 
-    static class Square extends Shape {
-
-        private float len;
-
-        Square(float _len) {
-            len = _len;
-        }
-
-        @Override
-        public float getArea() {
-            return len * len;
-        }
-    }
-
-    @Result public float[] outArray = new float[NUM];
-    public Shape[] inShapeArray = new Shape[NUM];
-
-    void setupArrays() {
-        for (int i = 0; i < NUM; i++) {
-            if (i % 2 == 0)
-                inShapeArray[i] = new Circle(i + 1);
-            else
-                inShapeArray[i] = new Square(i + 1);
-            outArray[i] = -i;
-        }
-    }
-
+    // although runTest is the same in each class derived from VirtualCallBase
+    // we duplicate the logic in each derived test so as to have different lambda call sites
     @Override
     public void runTest() {
         setupArrays();
@@ -93,19 +50,19 @@
         });
     }
 
-    // graal says not inlining getArea():float (0 bytes): no type profile exists
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
-    public void test() {
-        try (DebugConfigScope s = disableIntercept()) {
-            testGeneratedHsail();
-        }
+    @Override
+    protected boolean supportsRequiredCapabilities() {
+        return typeProfileWidthAtLeast(2);
     }
 
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+    @Test
     public void testUsingLambdaMethod() {
-        try (DebugConfigScope s = disableIntercept()) {
-            testGeneratedHsailUsingLambdaMethod();
-        }
+        testGeneratedHsailUsingLambdaMethod();
     }
 
 }
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -33,26 +33,14 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.ConvertOp;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.Op1Stack;
+import com.oracle.graal.lir.hsail.HSAILArithmetic.Op1Reg;
 import com.oracle.graal.lir.hsail.HSAILArithmetic.Op2Reg;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.Op2Stack;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.ShiftOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.CompareBranchOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCondMoveOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.ReturnOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.StrategySwitchOp;
-import com.oracle.graal.lir.hsail.HSAILMove.LeaOp;
-import com.oracle.graal.lir.hsail.HSAILMove.MembarOp;
-import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
-import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.*;
+import com.oracle.graal.lir.hsail.HSAILMove.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -74,7 +62,7 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c, boolean isCompressed) {
+    public boolean canStoreConstant(Constant c) {
         // Operand b must be in the .reg state space.
         return false;
     }
@@ -148,8 +136,7 @@
                 finalDisp += asConstant(index).asLong() * scale;
             } else {
                 Value indexRegister;
-                Value convertedIndex;
-                convertedIndex = this.emitSignExtend(index, 32, 64);
+                Value convertedIndex = index.getKind() == Kind.Long ? index : this.emitSignExtend(index, 32, 64);
                 if (scale != 1) {
                     indexRegister = emitUMul(convertedIndex, Constant.forInt(scale));
                 } else {
@@ -265,16 +252,16 @@
             case Int:
                 // Note: The Int case also handles the negation of shorts, bytes, and chars because
                 // Java treats these types as ints at the bytecode level.
-                append(new Op1Stack(INEG, result, input));
+                append(new Op1Reg(INEG, result, input));
                 break;
             case Long:
-                append(new Op1Stack(LNEG, result, input));
+                append(new Op1Reg(LNEG, result, input));
                 break;
             case Double:
-                append(new Op1Stack(DNEG, result, input));
+                append(new Op1Reg(DNEG, result, input));
                 break;
             case Float:
-                append(new Op1Stack(FNEG, result, input));
+                append(new Op1Reg(FNEG, result, input));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -296,10 +283,10 @@
             case Int:
                 // Note: The Int case also covers other primitive integral types smaller than an int
                 // (char, byte, short) because Java treats these types as ints.
-                append(new Op1Stack(INOT, result, input));
+                append(new Op1Reg(INOT, result, input));
                 break;
             case Long:
-                append(new Op1Stack(LNOT, result, input));
+                append(new Op1Reg(LNOT, result, input));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -312,16 +299,16 @@
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(IADD, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(LADD, result, a, loadNonConst(b)));
                 break;
             case Float:
-                append(new Op2Stack(FADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(FADD, result, a, loadNonConst(b)));
                 break;
             case Double:
-                append(new Op2Stack(DADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(DADD, result, a, loadNonConst(b)));
                 break;
             case Object:
                 throw GraalInternalError.shouldNotReachHere();
@@ -337,19 +324,19 @@
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(IADD, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(LADD, result, a, loadNonConst(b)));
                 break;
             case Float:
-                append(new Op2Stack(FADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(FADD, result, a, loadNonConst(b)));
                 break;
             case Double:
-                append(new Op2Stack(DADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(DADD, result, a, loadNonConst(b)));
                 break;
             case Object:
-                append(new Op2Stack(OADD, result, a, loadNonConst(b)));
+                append(new Op2Reg(OADD, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -362,16 +349,16 @@
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
+                append(new Op2Reg(ISUB, result, a, loadNonConst(b)));
                 break;
             case Float:
-                append(new Op2Stack(FSUB, result, a, loadNonConst(b)));
+                append(new Op2Reg(FSUB, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LSUB, result, a, loadNonConst(b)));
+                append(new Op2Reg(LSUB, result, a, loadNonConst(b)));
                 break;
             case Double:
-                append(new Op2Stack(DSUB, result, a, loadNonConst(b)));
+                append(new Op2Reg(DSUB, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -417,20 +404,30 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitMulHigh(Value a, Value b) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IDIV, result, a, loadNonConst(b)));
+                append(new Op2Reg(IDIV, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LDIV, result, a, loadNonConst(b)));
+                append(new Op2Reg(LDIV, result, a, loadNonConst(b)));
                 break;
             case Float:
-                append(new Op2Stack(FDIV, result, a, loadNonConst(b)));
+                append(new Op2Reg(FDIV, result, a, loadNonConst(b)));
                 break;
             case Double:
-                append(new Op2Stack(DDIV, result, a, loadNonConst(b)));
+                append(new Op2Reg(DDIV, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -440,20 +437,20 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IREM, result, a, loadNonConst(b)));
+                append(new Op2Reg(IREM, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LREM, result, a, loadNonConst(b)));
+                append(new Op2Reg(LREM, result, a, loadNonConst(b)));
                 break;
             case Float:
-                append(new Op2Stack(FREM, result, a, loadNonConst(b)));
+                append(new Op2Reg(FREM, result, a, loadNonConst(b)));
                 break;
             case Double:
-                append(new Op2Stack(DREM, result, a, loadNonConst(b)));
+                append(new Op2Reg(DREM, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -462,12 +459,12 @@
     }
 
     @Override
-    public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented();
     }
 
     @Override
-    public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitURem(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented();
     }
 
@@ -476,10 +473,10 @@
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IAND, result, a, loadNonConst(b)));
+                append(new Op2Reg(IAND, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LAND, result, a, loadNonConst(b)));
+                append(new Op2Reg(LAND, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -492,10 +489,10 @@
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IOR, result, a, loadNonConst(b)));
+                append(new Op2Reg(IOR, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LOR, result, a, loadNonConst(b)));
+                append(new Op2Reg(LOR, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -508,10 +505,10 @@
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IXOR, result, a, loadNonConst(b)));
+                append(new Op2Reg(IXOR, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op2Stack(LXOR, result, a, loadNonConst(b)));
+                append(new Op2Reg(LXOR, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -685,7 +682,7 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
@@ -723,7 +720,7 @@
     @Override
     public Value emitMathAbs(Value input) {
         Variable result = newVariable(input.getPlatformKind());
-        append(new Op1Stack(ABS, result, input));
+        append(new Op1Reg(ABS, result, input));
         return result;
     }
 
@@ -735,7 +732,7 @@
      */
     public Value emitMathCeil(Value input) {
         Variable result = newVariable(input.getPlatformKind());
-        append(new Op1Stack(CEIL, result, input));
+        append(new Op1Reg(CEIL, result, input));
         return result;
     }
 
@@ -747,7 +744,7 @@
      */
     public Value emitMathFloor(Value input) {
         Variable result = newVariable(input.getPlatformKind());
-        append(new Op1Stack(FLOOR, result, input));
+        append(new Op1Reg(FLOOR, result, input));
         return result;
     }
 
@@ -759,7 +756,7 @@
      */
     public Value emitMathRint(Value input) {
         Variable result = newVariable(input.getPlatformKind());
-        append(new Op1Stack(RINT, result, input));
+        append(new Op1Reg(RINT, result, input));
         return result;
     }
 
@@ -772,7 +769,7 @@
     @Override
     public Value emitMathSqrt(Value input) {
         Variable result = newVariable(input.getPlatformKind());
-        append(new Op1Stack(SQRT, result, input));
+        append(new Op1Reg(SQRT, result, input));
         return result;
     }
 
@@ -832,7 +829,7 @@
      * Graal generates for any switch construct appearing in Java bytecode.
      */
     @Override
-    protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
+    public void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
         emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget);
     }
 
@@ -841,29 +838,23 @@
      * 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.
      * @param key the key that is compared against the key constants in the case statements.
      */
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
-        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 or long, not " + key.getKind());
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        switch (key.getKind()) {
+            case Int:
+            case Long:
+            case Object:
+                // Append the LIR instruction for generating compare and branch instructions.
+                append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key));
+                break;
+            default:
+                // Throw an exception if the key kind is anything else.
+                throw GraalInternalError.unimplemented("Switch statements not supported for keys of type " + key.getKind());
         }
     }
 
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -27,16 +27,15 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.hsail.*;
+import com.oracle.graal.lir.gen.*;
 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 HSAILNodeLIRBuilder extends NodeLIRBuilder {
 
-    public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
@@ -62,15 +61,8 @@
     }
 
     @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) {
+        // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented();
     }
 }
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -34,9 +34,10 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXArithmetic.ConvertOp;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op1Stack;
@@ -58,10 +59,6 @@
 import com.oracle.graal.lir.ptx.PTXMemOp.StoreReturnValOp;
 import com.oracle.graal.lir.ptx.PTXMove.MoveFromRegOp;
 import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -98,7 +95,7 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c, boolean isCompressed) {
+    public boolean canStoreConstant(Constant c) {
         // Operand b must be in the .reg state space.
         return false;
     }
@@ -232,25 +229,17 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         PTXAddressValue loadAddress = asAddress(address);
         Variable result = newVariable(kind);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
         append(new LoadOp((Kind) kind, result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         PTXAddressValue storeAddress = asAddress(address);
         Variable input = load(inputVal);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
         append(new StoreOp((Kind) kind, storeAddress, input, state));
     }
 
@@ -376,7 +365,6 @@
 
     @Override
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
-
         emitIntegerTest(left, right);
         Variable result = newVariable(trueValue.getKind());
         append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue), nextPredRegNum));
@@ -386,7 +374,6 @@
     }
 
     private void emitIntegerTest(Value a, Value b) {
-
         assert a.getKind().isNumericInteger();
 
         if (LIRValueUtil.isVariable(b)) {
@@ -498,7 +485,17 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitMulHigh(Value a, Value b) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
@@ -520,7 +517,7 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
@@ -536,12 +533,12 @@
     }
 
     @Override
-    public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUDiv()");
     }
 
     @Override
-    public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
+    public Variable emitURem(Value a, Value b, LIRFrameState state) {
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitURem()");
     }
 
@@ -555,7 +552,6 @@
             case Long:
                 append(new Op2Stack(LAND, result, a, loadNonConst(b)));
                 break;
-
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
         }
@@ -754,7 +750,7 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
@@ -845,7 +841,7 @@
     }
 
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         boolean needsTemp = key.getKind() == Kind.Object;
         append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL, nextPredRegNum++));
     }
@@ -863,17 +859,16 @@
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUnwind()");
     }
 
-    public Variable emitLoadParam(Kind kind, Value address, DeoptimizingNode deopting) {
+    public Variable emitLoadParam(Kind kind, Value address, LIRFrameState state) {
 
         PTXAddressValue loadAddress = asAddress(address);
         Variable result = newVariable(kind);
-        append(new LoadParamOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
+        append(new LoadParamOp(kind, result, loadAddress, state));
 
         return result;
     }
 
-    public Variable emitLoadReturnAddress(Kind kind, Value address, DeoptimizingNode deopting) {
-
+    public Variable emitLoadReturnAddress(Kind kind, Value address, LIRFrameState state) {
         PTXAddressValue loadAddress = asAddress(address);
         Variable result;
         switch (kind) {
@@ -885,18 +880,16 @@
                 break;
             default:
                 result = newVariable(kind);
-
         }
-        append(new LoadReturnAddrOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
+        append(new LoadReturnAddrOp(kind, result, loadAddress, state));
 
         return result;
     }
 
-    public void emitStoreReturnValue(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
-
+    public void emitStoreReturnValue(Kind kind, Value address, Value inputVal, LIRFrameState state) {
         PTXAddressValue storeAddress = asAddress(address);
         Variable input = load(inputVal);
-        append(new StoreReturnValOp(kind, storeAddress, input, deopting != null ? state(deopting) : null));
+        append(new StoreReturnValOp(kind, storeAddress, input, state));
     }
 
     @Override
@@ -908,6 +901,12 @@
     }
 
     public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
-        throw GraalInternalError.unimplemented("PTXLIRGenerator.emitCompareAndSwap()");
+        throw GraalInternalError.unimplemented();
     }
+
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        assert address.getKind() == Kind.Object : address + " - " + address.getKind() + " not an object!";
+        append(new PTXMove.NullCheckOp(load(address), state));
+    }
+
 }
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.nodes.*;
 
@@ -39,11 +40,6 @@
  */
 public class PTXNodeLIRBuilder extends NodeLIRBuilder {
 
-    // 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);
 
@@ -55,14 +51,10 @@
         }
     }
 
-    public PTXNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public PTXNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
-    public int getNextPredRegNumber() {
-        return nextPredRegNum;
-    }
-
     @Override
     public void emitPrologue(StructuredGraph graph) {
         // Need to emit .param directives based on incoming arguments and return value
@@ -133,12 +125,6 @@
     }
 
     @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()");
     }
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -27,42 +27,21 @@
 import static com.oracle.graal.lir.sparc.SPARCArithmetic.*;
 import static com.oracle.graal.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.sparc.SPARCCompare.*;
+import static com.oracle.graal.lir.sparc.SPARCControlFlow.*;
 import static com.oracle.graal.lir.sparc.SPARCMathIntrinsicOp.IntrinsicOpcode.*;
+import static com.oracle.graal.lir.sparc.SPARCMove.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.CC;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.debug.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryCommutative;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegConst;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegReg;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Op1Stack;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Op2Stack;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.RemOp;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op;
-import com.oracle.graal.lir.sparc.SPARCCompare.CompareOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.BranchOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.FloatCondMoveOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
-import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -84,7 +63,7 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c, boolean isCompressed) {
+    public boolean canStoreConstant(Constant c) {
         // SPARC can only store integer null constants (via g0)
         switch (c.getKind()) {
             case Float:
@@ -133,8 +112,7 @@
 
     @Override
     public void emitData(AllocatableValue dst, byte[] data) {
-        // throw GraalInternalError.unimplemented();
-        append(new SPARCConstDataOp(dst, data));
+        append(new LoadDataAddressOp(dst, data));
     }
 
     @Override
@@ -161,7 +139,7 @@
                 indexRegister = Value.ILLEGAL;
             } else {
                 if (scale != 1) {
-                    Value longIndex = emitSignExtend(index, 32, 64);
+                    Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64);
                     if (CodeUtil.isPowerOf2(scale)) {
                         indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale)));
                     } else {
@@ -189,16 +167,20 @@
         // If we don't have an index register we can use a displacement, otherwise load the
         // displacement into a register and add it to the base.
         if (indexRegister.equals(Value.ILLEGAL)) {
-            // TODO What if displacement if too big?
             displacementInt = (int) finalDisp;
+            assert SPARCAssembler.isSimm13(displacementInt) : displacementInt;
         } else {
             displacementInt = 0;
             if (baseRegister.equals(Value.ILLEGAL)) {
                 baseRegister = load(Constant.forLong(finalDisp));
             } else {
-                Variable longBaseRegister = newVariable(Kind.Long);
-                emitMove(longBaseRegister, baseRegister);  // FIXME get rid of this move
-                baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp));
+                if (finalDisp == 0) {
+                    // Nothing to do. Just use the base register.
+                } else {
+                    Variable longBaseRegister = newVariable(Kind.Long);
+                    emitMove(longBaseRegister, baseRegister);
+                    baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp));
+                }
             }
         }
 
@@ -284,21 +266,19 @@
     @Override
     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
         boolean mirrored = emitCompare(left, right);
-        // TTY.print(String.format("Cond: l: %s r: %s cond: %s, mirrored: %b\n", left, right, cond,
-// mirrored));
         Condition finalCondition = mirrored ? cond.mirror() : cond;
-        CC cCode = getCCodeForKind(left.getKind());
 
         Variable result = newVariable(trueValue.getKind());
-        switch (left.getKind().getStackKind()) {
+        Kind kind = left.getKind().getStackKind();
+        switch (kind) {
             case Int:
             case Long:
             case Object:
-                append(new CondMoveOp(result, finalCondition, cCode, load(trueValue), loadNonConst(falseValue)));
+                append(new CondMoveOp(kind, result, finalCondition, load(trueValue), loadNonConst(falseValue)));
                 break;
             case Float:
             case Double:
-                append(new FloatCondMoveOp(result, finalCondition, cCode, unorderedIsTrue, load(trueValue), load(falseValue)));
+                append(new FloatCondMoveOp(kind, result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere("" + left.getKind());
@@ -306,18 +286,6 @@
         return result;
     }
 
-    private static CC getCCodeForKind(Kind kind) {
-        switch (kind) {
-            case Int:
-                return CC.Icc;
-            case Long:
-                return CC.Xcc;
-            case Float:
-                return CC.Fcc0;
-        }
-        throw GraalInternalError.shouldNotReachHere("" + kind);
-    }
-
     /**
      * This method emits the compare instruction, and may reorder the operands. It returns true if
      * it did so.
@@ -365,8 +333,8 @@
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
         emitIntegerTest(left, right);
         Variable result = newVariable(trueValue.getKind());
-        CC cCode = getCCodeForKind(left.getKind());
-        append(new CondMoveOp(result, Condition.EQ, cCode, load(trueValue), loadNonConst(falseValue)));
+        Kind kind = left.getKind().getStackKind();
+        append(new CondMoveOp(kind, result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
         return result;
     }
 
@@ -381,7 +349,7 @@
     }
 
     @Override
-    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         // a temp is needed for loading long and object constants
         boolean needsTemp = key.getKind() == Kind.Long || key.getKind() == Kind.Object;
         append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
@@ -478,9 +446,6 @@
             case Int:
                 append(new Op1Stack(INEG, result, input));
                 break;
-            case Long:
-                append(new Op1Stack(LNEG, result, input));
-                break;
             case Float:
                 append(new Op1Stack(FNEG, result, input));
                 break;
@@ -615,7 +580,17 @@
     }
 
     @Override
-    public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitMulHigh(Value a, Value b) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -637,8 +612,7 @@
     }
 
     @Override
-    public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
-        LIRFrameState state = state(deopting);
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -654,7 +628,7 @@
     }
 
     @Override
-    public Value emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
         // LIRFrameState state = state(deopting);
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -669,7 +643,7 @@
     }
 
     @Override
-    public Value emitURem(Value a, Value b, DeoptimizingNode deopting) {
+    public Value emitURem(Value a, Value b, LIRFrameState state) {
         // LIRFrameState state = state(deopting);
         switch (a.getKind().getStackKind()) {
             case Int:
@@ -836,22 +810,23 @@
             return inputVal;
         } else if (toBits > 32) {
             // sign extend to 64 bits
-            if (fromBits == 32) {
-                return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
-            } else if (fromBits < 32) {
-                // TODO implement direct x2L sign extension conversions
-                Value intVal = emitSignExtend(inputVal, fromBits, 32);
-                return emitSignExtend(intVal, 32, toBits);
-            } else {
-                throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            switch (fromBits) {
+                case 8:
+                    return emitConvert2Op(Kind.Long, B2L, asAllocatable(inputVal));
+                case 16:
+                    return emitConvert2Op(Kind.Long, S2L, asAllocatable(inputVal));
+                case 32:
+                    return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
         } else {
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(Kind.Int, I2B, asAllocatable(inputVal));
+                    return emitConvert2Op(Kind.Int, B2I, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(Kind.Int, I2S, asAllocatable(inputVal));
+                    return emitConvert2Op(Kind.Int, S2I, asAllocatable(inputVal));
                 case 32:
                     return inputVal;
                 default:
@@ -939,7 +914,7 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         append(new ReturnOp(Value.ILLEGAL));
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -25,9 +25,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -35,7 +36,7 @@
  */
 public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder {
 
-    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
@@ -57,13 +58,8 @@
     }
 
     @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");
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
@@ -299,7 +300,7 @@
 
     final ValueNode getResult(String snippet) {
         processMethod(snippet);
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
         return graph.getNodes(ReturnNode.class).first().result();
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri May 30 15:09:09 2014 +0200
@@ -43,13 +43,14 @@
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.phases.verify.*;
 import com.oracle.graal.runtime.*;
+import com.oracle.graal.test.*;
 
 /**
  * Checks that all classes in graal.jar (which must be on the class path) comply with global
  * invariants such as using {@link Object#equals(Object)} to compare certain types instead of
  * identity comparisons.
  */
-public class CheckGraalInvariants {
+public class CheckGraalInvariants extends GraalTest {
 
     @Test
     public void test() {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Fri May 30 15:09:09 2014 +0200
@@ -132,7 +132,7 @@
         result = getResult(getCanonicalizedGraph("integerTestCanonicalization2"));
         assertTrue(result.isConstant() && result.asConstant().asLong() == 1);
         StructuredGraph graph = getCanonicalizedGraph("integerTestCanonicalization3");
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
         assertTrue(graph.getNodes(ReturnNode.class).first().result() instanceof ConditionalNode);
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,23 +22,16 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.nodes.ConstantNode.*;
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static org.junit.Assert.*;
-
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
- * Collection of tests for {@link ConditionalEliminationPhase} including those that triggered bugs
- * in this phase.
+ * Collection of tests for {@link com.oracle.graal.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest extends GraalCompilerTest {
 
@@ -88,174 +81,6 @@
         } while (true);
     }
 
-    /**
-     * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast
-     * caused an enclosing instanceof (for the same object and target type) to be incorrectly
-     * eliminated.
-     */
-    @Test
-    public void testReanchoringIssue() {
-        Entry end = new Entry("end");
-        EntryWithNext e1 = new EntryWithNext("e1", end);
-        EntryWithNext e2 = new EntryWithNext("e2", e1);
-
-        test("search", e2, "e3", new Entry("e4"));
-    }
-
-    @SuppressWarnings("unused")
-    public static int testNullnessSnippet(Object a, Object b) {
-        if (a == null) {
-            if (a == b) {
-                if (b == null) {
-                    return 1;
-                } else {
-                    return -2;
-                }
-            } else {
-                if (b == null) {
-                    return -3;
-                } else {
-                    return 4;
-                }
-            }
-        } else {
-            if (a == b) {
-                if (b == null) {
-                    return -5;
-                } else {
-                    return 6;
-                }
-            } else {
-                if (b == null) {
-                    return 7;
-                } else {
-                    return 8;
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testNullness() {
-        test("testNullnessSnippet", null, null);
-        test("testNullnessSnippet", null, new Object());
-        test("testNullnessSnippet", new Object(), null);
-        test("testNullnessSnippet", new Object(), new Object());
-
-        StructuredGraph graph = parse("testNullnessSnippet");
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public static int testDisjunctionSnippet(Object a) {
-        try {
-            if (a instanceof Integer) {
-                if (a == null) {
-                    return -1;
-                } else {
-                    return 2;
-                }
-            } else {
-                return 3;
-            }
-        } finally {
-            field = null;
-        }
-    }
-
-    @Test
-    public void testDisjunction() {
-        StructuredGraph graph = parse("testDisjunctionSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        IfNode ifNode = (IfNode) graph.start().next();
-        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition();
-        IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0)));
-        InstanceOfNode y = instanceOf;
-        ShortCircuitOrNode disjunction = graph.unique(new ShortCircuitOrNode(x, false, y, false, NOT_FREQUENT_PROBABILITY));
-        LogicNegationNode negation = graph.unique(new LogicNegationNode(disjunction));
-        ifNode.setCondition(negation);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
-        }
-    }
-
-    public static int testInvokeSnippet(Number n) {
-        if (n instanceof Integer) {
-            return n.intValue();
-        } else {
-            return 1;
-        }
-    }
-
-    @Test
-    public void testInvoke() {
-        test("testInvokeSnippet", new Integer(16));
-        StructuredGraph graph = parse("testInvokeSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-
-        InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
-        assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
-    }
-
-    public static void testTypeMergingSnippet(Object o, boolean b) {
-        if (b) {
-            if (!(o instanceof Double)) {
-                return;
-            }
-        } else {
-            if (!(o instanceof Integer)) {
-                return;
-            }
-        }
-
-        /*
-         * For this test the conditional elimination has to correctly merge the type information it
-         * has about o, so that it can remove the check on Number.
-         */
-        if (!(o instanceof Number)) {
-            field = o;
-        }
-    }
-
-    @Test
-    public void testTypeMerging() {
-        StructuredGraph graph = parse("testTypeMergingSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-
-        assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
-    }
-
-    public static String testInstanceOfCheckCastSnippet(Object e) {
-        if (e instanceof Entry) {
-            return ((Entry) e).name;
-        }
-        return null;
-    }
-
-    @Test
-    public void testInstanceOfCheckCast() {
-        StructuredGraph graph = parse("testInstanceOfCheckCastSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-
-        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
-    }
-
     public static int testRedundantComparesSnippet(int[] array) {
         if (array == null) {
             return 0;
@@ -272,39 +97,17 @@
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
         new FloatingReadPhase().apply(graph);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
         canonicalizer.apply(graph, context);
 
-        assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
-    }
-
-    public static int testDuplicateNullChecksSnippet(Object a) {
-        if (a == null) {
-            return 2;
-        }
-        try {
-            return ((Integer) a).intValue();
-        } catch (ClassCastException e) {
-            return 0;
-        }
+        assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
     }
 
-    @Test
-    @Ignore
-    public void testDuplicateNullChecks() {
-        // This tests whether explicit null checks properly eliminate later null guards. Currently
-        // it's failing.
-        StructuredGraph graph = parse("testDuplicateNullChecksSnippet");
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        PhaseContext context = new PhaseContext(getProviders(), null);
-
-        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
-        canonicalizer.apply(graph, context);
-        new FloatingReadPhase().apply(graph);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        canonicalizer.apply(graph, context);
-
-        assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+    public static String testInstanceOfCheckCastSnippet(Object e) {
+        if (e instanceof Entry) {
+            return ((Entry) e).name;
+        }
+        return null;
     }
 
     @Test
@@ -317,9 +120,10 @@
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
         canonicalizer.apply(graph, context);
 
-        assertEquals(0, graph.getNodes().filter(GuardNode.class).count());
+        assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());
     }
+
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Fri May 30 15:09:09 2014 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Fri May 30 15:09:09 2014 +0200
@@ -38,6 +38,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class FinalizableSubclassTest extends GraalCompilerTest {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugConfig;
+import com.oracle.graal.debug.DebugConfigScope;
+import com.oracle.graal.debug.internal.DebugScope;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Tests whether {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} actually
+ * performs some graph rewritings that it's supposed to perform.
+ */
+public class FlowSenReduTest extends GraalCompilerTest {
+
+    /*
+     * A previous instanceof makes redundant a follow-up checkcast.
+     */
+    public Object redundantCheckCastSnippet(Number o) {
+        Integer z = null;
+        if (o instanceof Integer) {
+            z = (Integer) o; // this CheckCastNode will be removed
+        }
+        return z;
+    }
+
+    static final Integer i7 = new Integer(7);
+
+    @Test
+    public void redundantCheckCastTest() {
+        assertDeepEquals(i7, redundantCheckCastSnippet(i7));
+        StructuredGraph result = afterFlowSensitiveReduce("redundantCheckCastSnippet");
+        nodeCountEquals(result, CheckCastNode.class, 0);
+        nodeCountEquals(result, InstanceOfNode.class, 1);
+    }
+
+    @SuppressWarnings("unused")
+    public boolean redundantInstanceOfSnippet01(Object o) {
+        if (o != null) {
+            Integer x = (Integer) o;
+            return (o instanceof Number); // this InstanceOfNode will be removed
+        }
+        return false;
+    }
+
+    @Test
+    public void redundantInstanceOfTest01() {
+        String snippet = "redundantInstanceOfSnippet01";
+        assertDeepEquals(true, redundantInstanceOfSnippet01(i7));
+        nodeCountEquals(afterFlowSensitiveReduce(snippet), InstanceOfNode.class, 1);
+    }
+
+    /*
+     * The combination of (previous) non-null-check and checkcast make redundant an instanceof.
+     */
+    @SuppressWarnings("unused")
+    public Object redundantInstanceOfSnippet02(Object o) {
+        Integer x = (Integer) o;
+        if (o != null) {
+            if (o instanceof Number) { // this InstanceOfNode will be removed
+                return o;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void redundantInstanceOfTest02() {
+        String snippet = "redundantInstanceOfSnippet02";
+        assertDeepEquals(i7, redundantInstanceOfSnippet02(i7));
+        int ioAfter = getNodes(afterFlowSensitiveReduce(snippet), InstanceOfNode.class).size();
+        assertDeepEquals(ioAfter, 1);
+    }
+
+    /*
+     * Once an exact-type has been inferred (due to instanceof final-class) a callsite is
+     * devirtualized.
+     */
+    public int devirtualizationSnippet(Object x, Object y) {
+        boolean c = x instanceof Integer;
+        if (c && x == y) {
+            Number z = (Number) y; // this CheckCastNode will be removed
+            return z.intValue(); // devirtualized into InvokeSpecial on Integer.intValue()
+        }
+        return 0;
+    }
+
+    @Test
+    public void devirtualizationTest() {
+        String snippet = "devirtualizationSnippet";
+        assertDeepEquals(i7, devirtualizationSnippet(i7, i7));
+        nodeCountEquals(afterFlowSensitiveReduce(snippet), CheckCastNode.class, 0);
+
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        assertDeepEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+
+        List<InvokeNode> invokeNodes = getNodes(afterFlowSensitiveReduce(snippet), InvokeNode.class);
+        assertDeepEquals(1, invokeNodes.size());
+
+        MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
+        assertDeepEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+        assertDeepEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString());
+    }
+
+    /*
+     * At the return statement, the returned value has been inferred to have type j.l.Number. The
+     * instanceof is deemed to always evaluate to false. The interplay with tail-duplication is also
+     * taken into account (resulting in two return statements, each with "false" as input).
+     */
+    @SuppressWarnings("unused")
+    public boolean t5Snippet(Object o, boolean b) {
+        Number z;
+        if (b) {
+            z = (Number) o; // tail duplication of return stmt, which becomes "return false"
+        } else {
+            z = (Integer) o; // tail duplication of return stmt, which becomes "return false"
+        }
+        return o instanceof String; // unreachable
+    }
+
+    @Test
+    public void t5a() {
+        String snippet = "t5Snippet";
+        assertDeepEquals(false, t5Snippet(null, true));
+        StructuredGraph resultGraph = canonicalize(afterFlowSensitiveReduce(snippet));
+        nodeCountEquals(resultGraph, ReturnNode.class, 2);
+
+        List<ReturnNode> returnNodes = getNodes(resultGraph, ReturnNode.class);
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ConstantNode c1 = (ConstantNode) iter.next().result();
+        ConstantNode c2 = (ConstantNode) iter.next().result();
+
+        assertDeepEquals(c1, c2);
+        assertDeepEquals(0, c1.getValue().asInt());
+    }
+
+    @Test
+    public void t5b() {
+        String snippet = "t5Snippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        nodeCountEquals(graph, InstanceOfNode.class, 2);
+    }
+
+    public boolean t6Snippet(Object x, Object y) {
+        if (!(x instanceof String)) {
+            return false;
+        }
+        if (!(y instanceof Number)) {
+            return false;
+        }
+        return x == y; // two known-not-to-conform reference values can't be ==
+    }
+
+    // TODO: two known-not-to-conform reference values can't be ==
+    // but baseCaseObjectEqualsNode doesn't check that as of now.
+    public void t6() {
+        String snippet = "t6Snippet";
+        // visualize(snippet);
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        nodeCountEquals(graph, ObjectEqualsNode.class, 0);
+    }
+
+    /*
+     * A previous instanceof check causes a follow-up instanceof to be deemed unsatisfiable,
+     * resulting in constant-substitution at that usage.
+     */
+    public Object t7Snippet(Object o) {
+        if (o instanceof Number) {
+            if (o instanceof String) { // condition amounts to false
+                return o; // made unreachable
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void t7() {
+        String snippet = "t7Snippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        graph = dce(canonicalize(graph));
+        // TODO how to simplify IfNode(false)
+        assertDeepEquals(1, getNodes(graph, InstanceOfNode.class).size());
+
+        List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class);
+        assertDeepEquals(2, returnNodes.size());
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ConstantNode c1 = (ConstantNode) iter.next().result();
+        ConstantNode c2 = (ConstantNode) iter.next().result();
+
+        assertDeepEquals(c1, c2);
+        Assert.assertTrue(c1.getValue().isNull());
+    }
+
+    /*
+     * During FlowSensitiveReduction, an unreachable branch doesn't contribute to the merged state.
+     * The resulting ("non-polluted") more precise inferred type after the merge allows
+     * devirtualizing a callsite.
+     */
+    public int devirtualizationSnippet02(Number o) {
+        if (o instanceof Integer) {
+            Number z = o;
+            if (o instanceof Long) {
+                z = o;
+            }
+            /*
+             * devirtualized into InvokeSpecial on Integer.intValue() ie the inferred-type is not
+             * polluted with values from the unreachable branch.
+             */
+            return z.intValue();
+        }
+        return 0;
+    }
+
+    @Test
+    public void devirtualizationTest02() {
+        String snippet = "devirtualizationSnippet02";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+
+        assertDeepEquals(1, getNodes(graph, InvokeNode.class).size());
+
+        List<InvokeNode> invokeNodes = getNodes(graph, InvokeNode.class);
+        assertDeepEquals(1, invokeNodes.size());
+
+        MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
+        assertDeepEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+        assertDeepEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString());
+    }
+
+    /*
+     * TODO ClassCastException known to fail --- either Deopt or throw ObjectGetClassNode The latter
+     * might lead to direct jump to EH if present.
+     */
+    @SuppressWarnings("unused")
+    public int t9Snippet(Object o) {
+        try {
+            if (o instanceof Number) {
+                String s = (String) o;
+                /*
+                 * make a long story short: replace the above with throw new ClassCastException (ok,
+                 * actual type of o unknown).
+                 */
+                return 1;
+            }
+        } catch (ClassCastException e) {
+            return 2;
+        }
+        return 3;
+    }
+
+    /*
+     * "Partial evaluation" via canonicalization of an expression (in the last return statement) one
+     * of whose leaf sub-expressions was determined to be constant.
+     */
+    @SuppressWarnings("unused")
+    public Object partialEvalSnippet01(Object o, boolean b) {
+        if (o == null) {
+            return o; // turned into "return null;"
+        } else {
+            Number z;
+            if (b) {
+                z = (Number) o;
+            } else {
+                z = (Integer) o;
+            }
+            return o instanceof String ? this : null; // turned into "return null;"
+        }
+    }
+
+    @Test
+    public void partialEvalTest01() {
+        String snippet = "partialEvalSnippet01";
+
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        dce(graph);
+
+        List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class);
+        assertDeepEquals(2, returnNodes.size());
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ValueNode c1 = GraphUtil.unproxify(iter.next().result());
+        ValueNode c2 = GraphUtil.unproxify(iter.next().result());
+        assert !iter.hasNext();
+
+        Assert.assertTrue(c1.isNullConstant());
+        Assert.assertTrue(c2.isNullConstant());
+    }
+
+    public static class C {
+        public int f;
+    }
+
+    /*
+     * A previous (assumed successful) instanceof check is reused later on to remove a checkcast.
+     */
+    public void deduplicateInstanceOfSnippet(Object o) {
+        ((C) o).f = ((C) o).f; // boils down to a single instanceof test
+    }
+
+    @Test
+    public void deduplicateInstanceOfTest() {
+        String snippet = "deduplicateInstanceOfSnippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        List<InstanceOfNode> ioNodes = getNodes(graph, InstanceOfNode.class);
+        assertDeepEquals(1, ioNodes.size());
+
+    }
+
+    // ---------------------------------------------
+    // ----------------- UTILITIES -----------------
+    // ---------------------------------------------
+
+    private PhaseContext getPhaseContext() {
+        return new PhaseContext(getProviders(), null);
+    }
+
+    private static StructuredGraph dce(StructuredGraph graph) {
+        new DeadCodeEliminationPhase().apply(graph);
+        return graph;
+    }
+
+    private StructuredGraph canonicalize(StructuredGraph graph) {
+        new CanonicalizerPhase(true).apply(graph, getPhaseContext());
+        return graph;
+    }
+
+    private StructuredGraph flowSensitiveReduce(StructuredGraph graph) {
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, getPhaseContext());
+        return graph;
+    }
+
+    public static <N extends Node> List<N> getNodes(StructuredGraph graph, Class<N> nodeClass) {
+        return graph.getNodes().filter(nodeClass).snapshot();
+    }
+
+    public <N extends Node> void nodeCountEquals(StructuredGraph graph, Class<N> nodeClass, int expected) {
+        assertDeepEquals(expected, getNodes(graph, nodeClass).size());
+    }
+
+    public StructuredGraph afterFlowSensitiveReduce(String snippet) {
+        StructuredGraph before = canonicalize(parse(snippet));
+        // visualize(before, snippet + "-before");
+        StructuredGraph result = flowSensitiveReduce(before);
+        // visualize(result, snippet + "-after");
+        return result;
+    }
+
+    public StructuredGraph visualize(StructuredGraph graph, String title) {
+        DebugConfig debugConfig = DebugScope.getConfig();
+        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+        try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+            Debug.dump(graph, title);
+
+            return graph;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import static com.oracle.graal.nodes.ConstantNode.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
+import static org.junit.Assert.*;
+
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+/**
+ * Collection of tests for {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase}
+ * including those that triggered bugs in this phase.
+ */
+public class FlowSensitiveReductionTest extends GraalCompilerTest {
+
+    public static Object field;
+
+    static class Entry {
+
+        final String name;
+
+        public Entry(String name) {
+            this.name = name;
+        }
+    }
+
+    static class EntryWithNext extends Entry {
+
+        public EntryWithNext(String name, Entry next) {
+            super(name);
+            this.next = next;
+        }
+
+        final Entry next;
+    }
+
+    public static Entry search(Entry start, String name, Entry alternative) {
+        Entry current = start;
+        do {
+            while (current instanceof EntryWithNext) {
+                if (name != null && current.name == name) {
+                    current = null;
+                } else {
+                    Entry next = ((EntryWithNext) current).next;
+                    current = next;
+                }
+            }
+
+            if (current != null) {
+                if (current.name.equals(name)) {
+                    return current;
+                }
+            }
+            if (current == alternative) {
+                return null;
+            }
+            current = alternative;
+
+        } while (true);
+    }
+
+    /**
+     * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast
+     * caused an enclosing instanceof (for the same object and target type) to be incorrectly
+     * eliminated.
+     */
+    @Test
+    public void testReanchoringIssue() {
+        Entry end = new Entry("end");
+        EntryWithNext e1 = new EntryWithNext("e1", end);
+        EntryWithNext e2 = new EntryWithNext("e2", e1);
+
+        test("search", e2, "e3", new Entry("e4"));
+    }
+
+    @SuppressWarnings("unused")
+    public static int testNullnessSnippet(Object a, Object b) {
+        if (a == null) {
+            if (a == b) {
+                if (b == null) {
+                    return 1;
+                } else {
+                    return -2;
+                }
+            } else {
+                if (b == null) {
+                    return -3;
+                } else {
+                    return 4;
+                }
+            }
+        } else {
+            if (a == b) {
+                if (b == null) {
+                    return -5;
+                } else {
+                    return 6;
+                }
+            } else {
+                if (b == null) {
+                    return 7;
+                } else {
+                    return 8;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testNullness() {
+        test("testNullnessSnippet", null, null);
+        test("testNullnessSnippet", null, new Object());
+        test("testNullnessSnippet", new Object(), null);
+        test("testNullnessSnippet", new Object(), new Object());
+
+        StructuredGraph graph = parse("testNullnessSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, context);
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static int testDisjunctionSnippet(Object a) {
+        try {
+            if (a instanceof Integer) {
+                if (a == null) {
+                    return -1;
+                } else {
+                    return 2;
+                }
+            } else {
+                return 3;
+            }
+        } finally {
+            field = null;
+        }
+    }
+
+    @Test
+    public void testDisjunction() {
+        StructuredGraph graph = parse("testDisjunctionSnippet");
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        IfNode ifNode = (IfNode) graph.start().next();
+        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition();
+        IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0)));
+        InstanceOfNode y = instanceOf;
+        ShortCircuitOrNode disjunction = graph.unique(new ShortCircuitOrNode(x, false, y, false, NOT_FREQUENT_PROBABILITY));
+        LogicNegationNode negation = graph.unique(new LogicNegationNode(disjunction));
+        ifNode.setCondition(negation);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), null));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
+        }
+    }
+
+    public static int testInvokeSnippet(Number n) {
+        if (n instanceof Integer) {
+            return n.intValue();
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testInvoke() {
+        test("testInvokeSnippet", new Integer(16));
+        StructuredGraph graph = parse("testInvokeSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+
+        InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
+        assertDeepEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
+    }
+
+    public static void testTypeMergingSnippet(Object o, boolean b) {
+        if (b) {
+            if (!(o instanceof Double)) {
+                return;
+            }
+        } else {
+            if (!(o instanceof Integer)) {
+                return;
+            }
+        }
+
+        /*
+         * For this test the conditional elimination has to correctly merge the type information it
+         * has about o, so that it can remove the check on Number.
+         */
+        if (!(o instanceof Number)) {
+            field = o;
+        }
+    }
+
+    @Test
+    public void testTypeMerging() {
+        StructuredGraph graph = parse("testTypeMergingSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+
+        assertDeepEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
+    }
+
+    public static String testInstanceOfCheckCastSnippet(Object e) {
+        if (e instanceof Entry) {
+            return ((Entry) e).name;
+        }
+        return null;
+    }
+
+    @Test
+    public void testInstanceOfCheckCast() {
+        StructuredGraph graph = parse("testInstanceOfCheckCastSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+
+        assertDeepEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+    }
+
+    public static int testDuplicateNullChecksSnippet(Object a) {
+        if (a == null) {
+            return 2;
+        }
+        try {
+            return ((Integer) a).intValue();
+        } catch (ClassCastException e) {
+            return 0;
+        }
+    }
+
+    @Test
+    @Ignore
+    public void testDuplicateNullChecks() {
+        // This tests whether explicit null checks properly eliminate later null guards. Currently
+        // it's failing.
+        StructuredGraph graph = parse("testDuplicateNullChecksSnippet");
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        PhaseContext context = new PhaseContext(getProviders(), null);
+
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new FloatingReadPhase().apply(graph);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,9 @@
 
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
-import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.atomic.*;
@@ -54,6 +53,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
@@ -86,19 +86,79 @@
     private final Backend backend;
     private final Suites suites;
 
+    /**
+     * Can be overridden by unit tests to verify properties of the graph.
+     *
+     * @param graph the graph at the end of HighTier
+     */
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        return true;
+    }
+
+    /**
+     * Can be overridden by unit tests to verify properties of the graph.
+     *
+     * @param graph the graph at the end of MidTier
+     */
+    protected boolean checkMidTierGraph(StructuredGraph graph) {
+        return true;
+    }
+
+    /**
+     * Can be overridden by unit tests to verify properties of the graph.
+     *
+     * @param graph the graph at the end of LowTier
+     */
+    protected boolean checkLowTierGraph(StructuredGraph graph) {
+        return true;
+    }
+
     private static boolean substitutionsInstalled;
 
     private void installSubstitutions() {
         if (!substitutionsInstalled) {
-            this.providers.getReplacements().registerSubstitutions(InjectProfileDataSubstitutions.class);
+            this.providers.getReplacements().registerSubstitutions(GraalCompilerTest.class, InjectProfileDataSubstitutions.class);
             substitutionsInstalled = true;
         }
     }
 
+    protected Suites createSuites() {
+        Suites ret = backend.getSuites().createSuites();
+        ret.getHighTier().findPhase(InliningPhase.class).add(new Phase("ComputeLoopFrequenciesPhase") {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                ComputeLoopFrequenciesClosure.compute(graph);
+            }
+        });
+        ret.getHighTier().appendPhase(new Phase("CheckGraphPhase") {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                assert checkHighTierGraph(graph);
+            }
+        });
+        ret.getMidTier().appendPhase(new Phase("CheckGraphPhase") {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                assert checkMidTierGraph(graph);
+            }
+        });
+        ret.getLowTier().appendPhase(new Phase("CheckGraphPhase") {
+
+            @Override
+            protected void run(StructuredGraph graph) {
+                assert checkLowTierGraph(graph);
+            }
+        });
+        return ret;
+    }
+
     public GraalCompilerTest() {
         this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
         this.providers = getBackend().getProviders();
-        this.suites = backend.getSuites().createSuites();
+        this.suites = createSuites();
         installSubstitutions();
     }
 
@@ -118,7 +178,7 @@
             this.backend = runtime.getHostBackend();
         }
         this.providers = backend.getProviders();
-        this.suites = backend.getSuites().createSuites();
+        this.suites = createSuites();
         installSubstitutions();
     }
 
@@ -277,76 +337,6 @@
 
     private static AtomicInteger compilationId = new AtomicInteger();
 
-    /**
-     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
-     * Does a deep copy equality comparison if {@code expected} is an array.
-     */
-    protected void assertEquals(Object expected, Object actual) {
-        if (expected != null && expected.getClass().isArray()) {
-            Assert.assertTrue(expected != null);
-            Assert.assertTrue(actual != null);
-            Assert.assertEquals(expected.getClass(), actual.getClass());
-            if (expected instanceof int[]) {
-                Assert.assertArrayEquals((int[]) expected, (int[]) actual);
-            } else if (expected instanceof byte[]) {
-                Assert.assertArrayEquals((byte[]) expected, (byte[]) actual);
-            } else if (expected instanceof char[]) {
-                Assert.assertArrayEquals((char[]) expected, (char[]) actual);
-            } else if (expected instanceof short[]) {
-                Assert.assertArrayEquals((short[]) expected, (short[]) actual);
-            } else if (expected instanceof float[]) {
-                Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f);
-            } else if (expected instanceof long[]) {
-                Assert.assertArrayEquals((long[]) expected, (long[]) actual);
-            } else if (expected instanceof double[]) {
-                Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d);
-            } else if (expected instanceof boolean[]) {
-                new ExactComparisonCriteria().arrayEquals(null, expected, actual);
-            } else if (expected instanceof Object[]) {
-                Assert.assertArrayEquals((Object[]) expected, (Object[]) actual);
-            } else {
-                Assert.fail("non-array value encountered: " + expected);
-            }
-        } else {
-            Assert.assertEquals(expected, actual);
-        }
-    }
-
-    @SuppressWarnings("serial")
-    public static class MultiCauseAssertionError extends AssertionError {
-
-        private Throwable[] causes;
-
-        public MultiCauseAssertionError(String message, Throwable... causes) {
-            super(message);
-            this.causes = causes;
-        }
-
-        @Override
-        public void printStackTrace(PrintStream out) {
-            super.printStackTrace(out);
-            int num = 0;
-            for (Throwable cause : causes) {
-                if (cause != null) {
-                    out.print("cause " + (num++));
-                    cause.printStackTrace(out);
-                }
-            }
-        }
-
-        @Override
-        public void printStackTrace(PrintWriter out) {
-            super.printStackTrace(out);
-            int num = 0;
-            for (Throwable cause : causes) {
-                if (cause != null) {
-                    out.print("cause " + (num++) + ": ");
-                    cause.printStackTrace(out);
-                }
-            }
-        }
-    }
-
     protected void testN(int n, final String name, final Object... args) {
         final List<Throwable> errors = new ArrayList<>(n);
         Thread[] threads = new Thread[n];
@@ -599,7 +589,7 @@
                 actual.exception.printStackTrace();
                 Assert.fail("expected " + expect.returnValue + " but got an exception");
             }
-            assertEquals(expect.returnValue, actual.returnValue);
+            assertDeepEquals(expect.returnValue, actual.returnValue);
         }
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Fri May 30 15:09:09 2014 +0200
@@ -30,6 +30,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -137,6 +139,59 @@
         return 1;
     }
 
+    @Test
+    public void test6() {
+        testCombinedIf("test6Snippet", 3);
+        test("test6Snippet", new int[]{0});
+    }
+
+    public static int test6Snippet(int[] a) {
+        int i = a[0];
+        if (i >= 0 && i < a.length) {
+            return a[i];
+        }
+        return 1;
+    }
+
+    @Test
+    public void test7() {
+        testCombinedIf("test7Snippet", 1);
+        test("test7Snippet", -1);
+    }
+
+    public static int test7Snippet(int v) {
+        if (v >= 0 && v < 1024) {
+            return v + 1;
+        }
+        return v - 1;
+    }
+
+    @Test
+    public void test8() {
+        testCombinedIf("test8Snippet", 1);
+        test("test8Snippet", -1);
+    }
+
+    public static int test8Snippet(int v) {
+        if (v >= 0 && v <= 1024) {
+            return v + 1;
+        }
+        return v - 1;
+    }
+
+    private void testCombinedIf(String snippet, int count) {
+        StructuredGraph graph = parse(snippet);
+        PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+        new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new FloatingReadPhase().apply(graph);
+        MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+        new GuardLoweringPhase().apply(graph, midContext);
+        new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+        new ValueAnchorCleanupPhase().apply(graph);
+        new CanonicalizerPhase(true).apply(graph, context);
+        assertDeepEquals(count, graph.getNodes().filter(IfNode.class).count());
+    }
+
     private void test(String snippet) {
         StructuredGraph graph = parse(snippet);
         ParameterNode param = graph.getNodes(ParameterNode.class).iterator().next();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Fri May 30 15:09:09 2014 +0200
@@ -39,7 +39,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 /**
  * Test that infopoints in {@link CompilationResult}s have correctly assigned reasons.
@@ -67,12 +66,12 @@
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
             if (sp instanceof Call) {
-                assertEquals(InfopointReason.CALL, sp.reason);
+                assertDeepEquals(InfopointReason.CALL, sp.reason);
             }
         }
     }
 
-    @LongTest
+    @Test
     public void lineInfopoints() {
         final Method method = getMethod("testMethod");
         final StructuredGraph graph = parseDebug(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Fri May 30 15:09:09 2014 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class InvokeExceptionTest extends GraalCompilerTest {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Fri May 30 15:09:09 2014 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class InvokeHintsTest extends GraalCompilerTest {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class LockEliminationTest extends GraalCompilerTest {
@@ -64,8 +65,8 @@
         StructuredGraph graph = getGraph("testSynchronizedSnippet");
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
         new LockEliminationPhase().apply(graph);
-        assertEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
-        assertEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
     }
 
     public static void testSynchronizedMethodSnippet(A x) {
@@ -82,8 +83,8 @@
         StructuredGraph graph = getGraph("testSynchronizedMethodSnippet");
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
         new LockEliminationPhase().apply(graph);
-        assertEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
-        assertEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
     }
 
     private StructuredGraph getGraph(String snippet) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,8 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static org.junit.Assert.*;
-
 import java.util.*;
 
 import org.junit.*;
@@ -43,6 +42,7 @@
 import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.schedule.SchedulePhase.MemoryScheduling;
 import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
@@ -53,7 +53,7 @@
  * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the
  * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the
  * right thing.
- * 
+ *
  * The scheduling shouldn't depend on FrameStates, which is tested by this class.
  */
 public class MemoryScheduleTest extends GraphScheduleTest {
@@ -164,7 +164,7 @@
     @Test
     public void testLoop1() {
         SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(6, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -189,7 +189,7 @@
     @Test
     public void testLoop2() {
         SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(6, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -211,7 +211,7 @@
     @Test
     public void testLoop3() {
         SchedulePhase schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(6, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -247,7 +247,7 @@
     @Test
     public void testLoop5() {
         SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -264,10 +264,10 @@
     public void testArrayCopy() {
         SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
         ReturnNode ret = graph.getNodes(ReturnNode.class).first();
-        assertTrue(ret.result() instanceof FloatingReadNode);
-        assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
+        assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode);
+        assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
         assertReadWithinAllReturnBlocks(schedule, true);
     }
 
@@ -285,7 +285,7 @@
     @Test
     public void testIfRead1() {
         SchedulePhase schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(3, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
     }
@@ -306,8 +306,8 @@
     @Test
     public void testIfRead2() {
         SchedulePhase schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(3, schedule.getCFG().getBlocks().length);
-        assertEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(3, schedule.getCFG().getBlocks().size());
+        assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
         assertReadAndWriteInSameBlock(schedule, false);
@@ -328,7 +328,7 @@
     @Test
     public void testIfRead3() {
         SchedulePhase schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(4, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -349,7 +349,7 @@
     @Test
     public void testIfRead4() {
         SchedulePhase schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(3, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
         assertReadAndWriteInSameBlock(schedule, true);
@@ -368,12 +368,36 @@
     @Test
     public void testIfRead5() {
         SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(4, schedule.getCFG().getBlocks().length);
+        assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
     }
 
+    public static int testAntiDependencySnippet(int a) {
+        /*
+         * This read must not be scheduled after the following write.
+         */
+        int res = container.a;
+        container.a = 10;
+
+        /*
+         * Add some more basic blocks.
+         */
+        if (a < 0) {
+            container.b = 20;
+        }
+        container.c = 30;
+        return res;
+    }
+
+    @Test
+    public void testAntiDependency() {
+        SchedulePhase schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(4, schedule.getCFG().getBlocks().size());
+        assertReadBeforeAllWritesInStartBlock(schedule);
+    }
+
     /**
      * testing scheduling within a block.
      */
@@ -397,9 +421,9 @@
         StructuredGraph graph = schedule.getCFG().graph;
         NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class);
 
-        assertEquals(1, schedule.getCFG().getBlocks().length);
-        assertEquals(8, writeNodes.count());
-        assertEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
+        assertDeepEquals(1, schedule.getCFG().getBlocks().size());
+        assertDeepEquals(8, writeNodes.count());
+        assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
 
         FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
 
@@ -554,7 +578,7 @@
             }
             returnBlocks++;
         }
-        assertEquals(withRead == returnBlocks, withinReturnBlock);
+        assertDeepEquals(withRead == returnBlocks, withinReturnBlock);
     }
 
     private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) {
@@ -564,7 +588,7 @@
                 readEncountered = true;
             }
         }
-        assertEquals(withinStartBlock, readEncountered);
+        assertDeepEquals(withinStartBlock, readEncountered);
     }
 
     private static void assertReadAndWriteInSameBlock(SchedulePhase schedule, boolean inSame) {
@@ -574,6 +598,20 @@
         assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write)));
     }
 
+    private static void assertReadBeforeAllWritesInStartBlock(SchedulePhase schedule) {
+        boolean writeNodeFound = false;
+        boolean readNodeFound = false;
+        for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) {
+            if (node instanceof FloatingReadNode) {
+                assertTrue(!writeNodeFound);
+                readNodeFound = true;
+            } else if (node instanceof WriteNode) {
+                writeNodeFound = true;
+            }
+        }
+        assertTrue(readNodeFound);
+    }
+
     private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode) {
         return getFinalSchedule(snippet, mode, MemoryScheduling.OPTIMAL);
     }
@@ -585,7 +623,7 @@
     private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final MemoryScheduling memsched, final SchedulingStrategy schedulingStrategy) {
         final StructuredGraph graph = parse(snippet);
         try (Scope d = Debug.scope("FloatingReadTest", graph)) {
-            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS)) {
+            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
                 Assumptions assumptions = new Assumptions(false);
                 HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
@@ -617,7 +655,7 @@
 
                 SchedulePhase schedule = new SchedulePhase(schedulingStrategy, memsched);
                 schedule.apply(graph);
-                assertEquals(1, graph.getNodes().filter(StartNode.class).count());
+                assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count());
                 return schedule;
             }
         } catch (Throwable e) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Fri May 30 15:09:09 2014 +0200
@@ -61,6 +61,6 @@
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
         Debug.dump(graph, "Graph");
-        assertEquals(returnCount, graph.getNodes(ReturnNode.class).count());
+        assertDeepEquals(returnCount, graph.getNodes(ReturnNode.class).count());
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.compiler.test;
 
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
 import java.util.*;
 
 import org.junit.*;
@@ -35,6 +34,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Fri May 30 15:09:09 2014 +0200
@@ -163,20 +163,20 @@
         Assert.assertTrue(containsDirect(innerMostLoop, d, cfg));
         Assert.assertTrue(contains(rootLoop, d, cfg));
         Assert.assertTrue(contains(nestedLoop, d, cfg));
-        Assert.assertEquals(rootExits, rootLoop.exits.size());
-        Assert.assertEquals(nestedExits, nestedLoop.exits.size());
-        Assert.assertEquals(innerExits, innerMostLoop.exits.size());
+        Assert.assertEquals(rootExits, rootLoop.getExits().size());
+        Assert.assertEquals(nestedExits, nestedLoop.getExits().size());
+        Assert.assertEquals(innerExits, innerMostLoop.getExits().size());
         Debug.dump(graph, "Graph");
     }
 
     private static boolean contains(Loop<Block> loop, Invoke node, ControlFlowGraph cfg) {
         Block block = cfg.blockFor((Node) node);
         Assert.assertNotNull(block);
-        return loop.blocks.contains(block);
+        return loop.getBlocks().contains(block);
     }
 
     private static boolean containsDirect(Loop<Block> loop, Invoke node, ControlFlowGraph cfg) {
-        for (Loop<Block> child : loop.children) {
+        for (Loop<Block> child : loop.getChildren()) {
             if (contains(child, node, cfg)) {
                 return false;
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
@@ -71,7 +72,7 @@
             for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) {
                 if (rn.location() instanceof ConstantLocationNode && rn.object().stamp() instanceof ObjectStamp) {
                     long disp = ((ConstantLocationNode) rn.location()).getDisplacement();
-                    ResolvedJavaType receiverType = ObjectStamp.typeOrNull(rn.object());
+                    ResolvedJavaType receiverType = StampTool.typeOrNull(rn.object());
                     ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(disp);
 
                     assert field != null : "Node " + rn + " tries to access a field which doesn't exists for this type";
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Fri May 30 15:09:09 2014 +0200
@@ -84,11 +84,11 @@
             // structure changes significantly
             StructuredGraph graph = parse(snippet);
             PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
-            new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
             new OptimizeGuardAnchorsPhase().apply(graph);
-            new ReadEliminationPhase().apply(graph);
-            new CanonicalizerPhase(true).apply(graph, context);
+            canonicalizer.apply(graph, context);
 
             Debug.dump(graph, "After lowering");
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.test;
 
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -167,8 +168,9 @@
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        PhaseContext context = new PhaseContext(getProviders(), assumptions);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, context);
         StructuredGraph referenceGraph = parse(referenceSnippet);
         assertEquals(referenceGraph, graph);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,10 @@
  */
 package com.oracle.graal.compiler.test;
 
+import static org.junit.Assert.assertTrue;
+
+import java.util.*;
+
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
@@ -59,37 +63,45 @@
 
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
 
-        Block[] blocks = cfg.getBlocks();
+        List<Block> blocks = cfg.getBlocks();
         // check number of blocks
-        assertEquals(4, blocks.length);
+        assertDeepEquals(4, blocks.size());
 
         // check block - node assignment
-        assertEquals(blocks[0], cfg.blockFor(graph.start()));
-        assertEquals(blocks[0], cfg.blockFor(ifNode));
-        assertEquals(blocks[1], cfg.blockFor(trueBegin));
-        assertEquals(blocks[1], cfg.blockFor(trueEnd));
-        assertEquals(blocks[2], cfg.blockFor(falseBegin));
-        assertEquals(blocks[2], cfg.blockFor(falseEnd));
-        assertEquals(blocks[3], cfg.blockFor(merge));
-        assertEquals(blocks[3], cfg.blockFor(returnNode));
+        assertDeepEquals(blocks.get(0), cfg.blockFor(graph.start()));
+        assertDeepEquals(blocks.get(0), cfg.blockFor(ifNode));
+        assertDeepEquals(blocks.get(1), cfg.blockFor(trueBegin));
+        assertDeepEquals(blocks.get(1), cfg.blockFor(trueEnd));
+        assertDeepEquals(blocks.get(2), cfg.blockFor(falseBegin));
+        assertDeepEquals(blocks.get(2), cfg.blockFor(falseEnd));
+        assertDeepEquals(blocks.get(3), cfg.blockFor(merge));
+        assertDeepEquals(blocks.get(3), cfg.blockFor(returnNode));
+
+        // check postOrder
+        Iterator<Block> it = cfg.postOrder().iterator();
+        for (int i = blocks.size() - 1; i >= 0; i--) {
+            assertTrue(it.hasNext());
+            Block b = it.next();
+            assertDeepEquals(blocks.get(i), b);
+        }
 
         // check dominators
-        assertDominator(blocks[0], null);
-        assertDominator(blocks[1], blocks[0]);
-        assertDominator(blocks[2], blocks[0]);
-        assertDominator(blocks[3], blocks[0]);
+        assertDominator(blocks.get(0), null);
+        assertDominator(blocks.get(1), blocks.get(0));
+        assertDominator(blocks.get(2), blocks.get(0));
+        assertDominator(blocks.get(3), blocks.get(0));
 
         // check dominated
-        assertDominatedSize(blocks[0], 3);
-        assertDominatedSize(blocks[1], 0);
-        assertDominatedSize(blocks[2], 0);
-        assertDominatedSize(blocks[3], 0);
+        assertDominatedSize(blocks.get(0), 3);
+        assertDominatedSize(blocks.get(1), 0);
+        assertDominatedSize(blocks.get(2), 0);
+        assertDominatedSize(blocks.get(3), 0);
 
         // check postdominators
-        assertPostdominator(blocks[0], blocks[3]);
-        assertPostdominator(blocks[1], blocks[3]);
-        assertPostdominator(blocks[2], blocks[3]);
-        assertPostdominator(blocks[3], null);
+        assertPostdominator(blocks.get(0), blocks.get(3));
+        assertPostdominator(blocks.get(1), blocks.get(3));
+        assertPostdominator(blocks.get(2), blocks.get(3));
+        assertPostdominator(blocks.get(3), null);
     }
 
     public static void assertDominator(Block block, Block expectedDominator) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Fri May 30 15:09:09 2014 +0200
@@ -25,8 +25,8 @@
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,8 @@
 
 import java.io.*;
 
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -180,11 +182,29 @@
         return ((InputStream) o).available();
     }
 
+    @Test
+    public void test7() {
+        test("test7Snippet", "referenceSnippet7");
+    }
+
+    public static int test7Snippet(int x) {
+        return ((x & 0xff) << 10) == ((x & 0x1f) + 1) ? 0 : x;
+    }
+
+    public static int referenceSnippet7(int x) {
+        return x;
+    }
+
     private void test(String snippet, String referenceSnippet) {
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        /*
+         * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase,
+         * tail-duplication gets activated thus resulting in a graph with more nodes than the
+         * reference graph.
+         */
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
         // a second canonicalizer is needed to process nested MaterializeNodes
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
@@ -239,7 +259,7 @@
         StructuredGraph graph = parse(snippet);
         Assumptions assumptions = new Assumptions(false);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
         Debug.dump(graph, "Graph " + snippet);
         Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.compiler.test.backend;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
@@ -34,13 +34,13 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.schedule.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri May 30 15:09:09 2014 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant
@@ -51,7 +50,7 @@
         return f1 + " " + arg1 + " " + arg2 + " " + arg3;
     }
 
-    @LongTest
+    @Test
     public void test1() {
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
@@ -74,7 +73,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test3() {
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
@@ -88,7 +87,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test4() {
         Method method = getMethod("testMethodVirtual");
         final StructuredGraph graph = parse(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java	Fri May 30 15:09:09 2014 +0200
@@ -33,7 +33,7 @@
     @Test
     public void testSimpleMerge() {
         testEscapeAnalysis("simpleMergeSnippet", null, false);
-        assertEquals(1, returnNodes.size());
+        assertDeepEquals(1, returnNodes.size());
         assertTrue(returnNodes.get(0).result() instanceof ValuePhiNode);
         PhiNode phi = (PhiNode) returnNodes.get(0).result();
         assertTrue(phi.valueAt(0) instanceof ParameterNode);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Fri May 30 15:09:09 2014 +0200
@@ -37,6 +37,7 @@
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
@@ -126,7 +127,7 @@
     /**
      * Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the
      * graph.
-     * 
+     *
      * @param snippet the name of the method whose graph should be processed
      * @param expectedConstantResult if this is non-null, the resulting graph needs to have the
      *            given constant return value
@@ -156,7 +157,7 @@
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
             new CanonicalizerPhase(true).apply(graph, context);
-            new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true)).apply(graph, context);
+            new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true), null).apply(graph, context);
             returnNodes = graph.getNodes(ReturnNode.class).snapshot();
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri May 30 15:09:09 2014 +0200
@@ -25,10 +25,10 @@
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Fri May 30 15:09:09 2014 +0200
@@ -74,12 +74,12 @@
     public void testSimple() {
         ValueNode result = getReturn("testSimpleSnippet").result();
         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getParameter(0), result);
+        assertDeepEquals(graph.getParameter(0), result);
     }
 
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
         return graph.getNodes(ReturnNode.class).first();
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.compiler.test.ea;
 
 import static org.junit.Assert.*;
-
 import java.util.*;
 
 import org.junit.*;
@@ -34,6 +33,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
@@ -87,7 +87,7 @@
         ValueNode result = getReturn("testSimpleSnippet").result();
         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
         assertTrue(result.isConstant());
-        assertEquals(2, result.asConstant().asInt());
+        assertDeepEquals(2, result.asConstant().asInt());
     }
 
     @SuppressWarnings("all")
@@ -115,7 +115,7 @@
     public void testParam() {
         ValueNode result = getReturn("testParamSnippet").result();
         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getParameter(1), result);
+        assertDeepEquals(graph.getParameter(1), result);
     }
 
     @SuppressWarnings("all")
@@ -129,7 +129,7 @@
     public void testMaterialized() {
         ValueNode result = getReturn("testMaterializedSnippet").result();
         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getParameter(0), result);
+        assertDeepEquals(graph.getParameter(0), result);
     }
 
     @SuppressWarnings("all")
@@ -145,7 +145,7 @@
     public void testSimpleLoop() {
         ValueNode result = getReturn("testSimpleLoopSnippet").result();
         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getParameter(1), result);
+        assertDeepEquals(graph.getParameter(1), result);
     }
 
     @SuppressWarnings("all")
@@ -162,7 +162,7 @@
     @Test
     public void testBadLoop() {
         ValueNode result = getReturn("testBadLoopSnippet").result();
-        assertEquals(0, graph.getNodes().filter(LoadFieldNode.class).count());
+        assertDeepEquals(0, graph.getNodes().filter(LoadFieldNode.class).count());
         assertTrue(result instanceof ProxyNode);
         assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode);
     }
@@ -180,7 +180,7 @@
     @Test
     public void testBadLoop2() {
         ValueNode result = getReturn("testBadLoop2Snippet").result();
-        assertEquals(1, graph.getNodes().filter(LoadFieldNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(LoadFieldNode.class).count());
         assertTrue(result instanceof LoadFieldNode);
     }
 
@@ -199,7 +199,7 @@
         processMethod("testPhiSnippet");
         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
         List<ReturnNode> returnNodes = graph.getNodes(ReturnNode.class).snapshot();
-        assertEquals(2, returnNodes.size());
+        assertDeepEquals(2, returnNodes.size());
         assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode);
         assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode);
         assertTrue(returnNodes.get(0).result().isConstant());
@@ -215,7 +215,7 @@
     @Test
     public void testSimpleStore() {
         processMethod("testSimpleStoreSnippet");
-        assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
     }
 
     public static int testValueProxySnippet(boolean b, TestObject o) {
@@ -233,12 +233,12 @@
     @Test
     public void testValueProxy() {
         processMethod("testValueProxySnippet");
-        assertEquals(2, graph.getNodes().filter(LoadFieldNode.class).count());
+        assertDeepEquals(2, graph.getNodes().filter(LoadFieldNode.class).count());
     }
 
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
         return graph.getNodes(ReturnNode.class).first();
     }
 
@@ -247,6 +247,6 @@
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
-        new PartialEscapePhase(false, true, new CanonicalizerPhase(true)).apply(graph, context);
+        new PartialEscapePhase(false, true, new CanonicalizerPhase(true), null).apply(graph, context);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.test.ea;
 
 import java.lang.ref.*;
+import java.util.function.*;
 
 import org.junit.*;
 
@@ -30,7 +31,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.graph.*;
@@ -171,7 +171,7 @@
     @Test
     public void testReference1() {
         prepareGraph("testReference1Snippet", false);
-        assertEquals(1, graph.getNodes().filter(NewInstanceNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(NewInstanceNode.class).count());
     }
 
     @SafeVarargs
@@ -186,11 +186,11 @@
             Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", graph.getNodes().filter(NewInstanceNode.class).isEmpty());
             Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty());
 
-            NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
+            ToDoubleFunction<FixedNode> nodeProbabilities = new FixedNodeProbabilityCache();
             double probabilitySum = 0;
             int materializeCount = 0;
             for (CommitAllocationNode materialize : graph.getNodes().filter(CommitAllocationNode.class)) {
-                probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size();
+                probabilitySum += nodeProbabilities.applyAsDouble(materialize) * materialize.getVirtualObjects().size();
                 materializeCount += materialize.getVirtualObjects().size();
             }
             Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Fri May 30 15:09:09 2014 +0200
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java	Fri May 30 15:09:09 2014 +0200
@@ -27,7 +27,7 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.compiler.test.inlining;
 
 import static org.junit.Assert.*;
-
 import java.lang.reflect.*;
 
 import org.junit.*;
@@ -37,8 +36,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 public class InliningTest extends GraalCompilerTest {
 
@@ -73,7 +72,7 @@
         assertInlined(getGraph("invokeMethodOnFieldSnippet", false));
     }
 
-    @LongTest
+    @Test
     public void testStaticBindableInliningIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true)));
@@ -82,7 +81,7 @@
     }
 
     @Ignore("would need read elimination/EA before inlining")
-    @LongTest
+    @Test
     public void testDependentStaticBindableInliningIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFieldSnippet", true)));
@@ -180,7 +179,7 @@
         assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false));
     }
 
-    @LongTest
+    @Test
     public void testClassHierarchyAnalysisIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true)));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/nfi/NativeFunctionInterfaceTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/nfi/NativeFunctionInterfaceTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.compiler.test.nfi;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static java.io.File.*;
 import static java.lang.System.*;
 import static org.junit.Assert.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/META-INF/services/javax.annotation.processing.Processor	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,1 @@
+com.oracle.graal.compiler.match.MatchProcessor
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 30 15:09:09 2014 +0200
@@ -24,7 +24,7 @@
 
 import static com.oracle.graal.compiler.GraalCompiler.Options.*;
 import static com.oracle.graal.compiler.MethodFilter.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
@@ -35,20 +35,19 @@
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
+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.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
@@ -207,7 +206,7 @@
         }
     }
 
-    private static void emitBlock(NodeLIRBuilder nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
+    private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
         if (lirGenRes.getLIR().getLIRforBlock(b) == null) {
             for (Block pred : b.getPredecessors()) {
                 if (!b.isLoopHeader() || !pred.isLoopEnd()) {
@@ -219,7 +218,7 @@
     }
 
     public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig) {
-        Block[] blocks = schedule.getCFG().getBlocks();
+        List<Block> blocks = schedule.getCFG().getBlocks();
         Block startBlock = schedule.getCFG().getStartBlock();
         assert startBlock != null;
         assert startBlock.getPredecessorCount() == 0;
@@ -229,10 +228,8 @@
         List<Block> linearScanOrder = null;
         try (Scope ds = Debug.scope("MidEnd")) {
             try (Scope s = Debug.scope("ComputeLinearScanOrder")) {
-                NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
-                BlocksToDoubles blockProbabilities = BlocksToDoubles.createFromNodeProbability(nodeProbabilities, schedule.getCFG());
-                codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, blockProbabilities);
-                linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, blockProbabilities);
+                codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.size(), startBlock);
+                linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.size(), startBlock);
 
                 lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder);
                 Debug.dump(lir, "After linear scan order");
@@ -244,9 +241,9 @@
         }
         try (Scope ds = Debug.scope("BackEnd", lir)) {
             FrameMap frameMap = backend.newFrameMap(registerConfig);
-            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMap, stub);
-            LIRGenerator lirGen = backend.newLIRGenerator(cc, lirGenRes);
-            NodeLIRBuilder nodeLirGen = backend.newNodeLIRGenerator(graph, lirGen);
+            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMap, graph.method(), stub);
+            LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes);
+            NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
 
             try (Scope s = Debug.scope("LIRGen", lirGen)) {
                 for (Block b : linearScanOrder) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri May 30 15:09:09 2014 +0200
@@ -42,6 +42,8 @@
     public static final OptionValue<String> Dump = new OptionValue<>(null);
     @Option(help = "Pattern for scope(s) to in which metering is enabled (see DebugFilter and Debug.metric)")
     public static final OptionValue<String> Meter = new OptionValue<>(null);
+    @Option(help = "Pattern for scope(s) to in which memory use tracking is enabled (see DebugFilter and Debug.metric)")
+    public static final OptionValue<String> TrackMemUse = new OptionValue<>(null);
     @Option(help = "Pattern for scope(s) to in which timing is enabled (see DebugFilter and Debug.timer)")
     public static final OptionValue<String> Time = new OptionValue<>(null);
     @Option(help = "Pattern for scope(s) to in which logging is enabled (see DebugFilter and Debug.log)")
@@ -70,6 +72,8 @@
             return enabled;
         }
     };
+    @Option(help = "Enable more verbose log output when available")
+    public static final OptionValue<Boolean> LogVerbose = new OptionValue<>(false);
     // @formatter:on
 
     public static boolean areDebugScopePatternsEnabled() {
@@ -77,11 +81,12 @@
     }
 
     public static boolean areMetricsOrTimersEnabled() {
-        return Meter.getValue() != null || Time.getValue() != null;
+        return Meter.getValue() != null || Time.getValue() != null || TrackMemUse.getValue() != null;
     }
 
     private final DebugFilter logFilter;
     private final DebugFilter meterFilter;
+    private final DebugFilter trackMemUseFilter;
     private final DebugFilter timerFilter;
     private final DebugFilter dumpFilter;
     private final MethodFilter[] methodFilter;
@@ -89,9 +94,11 @@
     private final PrintStream output;
     private final Set<Object> extraFilters = new HashSet<>();
 
-    public GraalDebugConfig(String logFilter, String meterFilter, String timerFilter, String dumpFilter, String methodFilter, PrintStream output, List<DebugDumpHandler> dumpHandlers) {
+    public GraalDebugConfig(String logFilter, String meterFilter, String trackMemUseFilter, String timerFilter, String dumpFilter, String methodFilter, PrintStream output,
+                    List<DebugDumpHandler> dumpHandlers) {
         this.logFilter = DebugFilter.parse(logFilter);
         this.meterFilter = DebugFilter.parse(meterFilter);
+        this.trackMemUseFilter = DebugFilter.parse(trackMemUseFilter);
         this.timerFilter = DebugFilter.parse(timerFilter);
         this.dumpFilter = DebugFilter.parse(dumpFilter);
         if (methodFilter == null || methodFilter.isEmpty()) {
@@ -120,6 +127,14 @@
         return isEnabled(meterFilter);
     }
 
+    public boolean isMetderEnabled() {
+        return isEnabled(meterFilter);
+    }
+
+    public boolean isMemUseTrackingEnabled() {
+        return isEnabled(trackMemUseFilter);
+    }
+
     public boolean isDumpEnabled() {
         return isEnabled(dumpFilter);
     }
@@ -150,7 +165,7 @@
 
     /**
      * Extracts a {@link JavaMethod} from an opaque debug context.
-     * 
+     *
      * @return the {@link JavaMethod} represented by {@code context} or null
      */
     public static JavaMethod asJavaMethod(Object context) {
@@ -216,7 +231,7 @@
         if (e instanceof BailoutException) {
             return null;
         }
-        Debug.setConfig(Debug.fixedConfig(true, true, false, false, dumpHandlers, output));
+        Debug.setConfig(Debug.fixedConfig(true, true, false, false, false, dumpHandlers, output));
         Debug.log(String.format("Exception occurred in scope: %s", Debug.currentScope()));
         for (Object o : Debug.context()) {
             if (o instanceof Graph) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Fri May 30 15:09:09 2014 +0200
@@ -69,45 +69,60 @@
          */
         public Interval any;
 
-        public RegisterBindingLists(Interval fixed, Interval any) {
+        /**
+         * List of intervals whose binding is currently {@link RegisterBinding#Stack}.
+         */
+        public Interval stack;
+
+        public RegisterBindingLists(Interval fixed, Interval any, Interval stack) {
             this.fixed = fixed;
             this.any = any;
+            this.stack = stack;
         }
 
         /**
          * Gets the list for a specified binding.
-         * 
+         *
          * @param binding specifies the list to be returned
          * @return the list of intervals whose binding is {@code binding}
          */
         public Interval get(RegisterBinding binding) {
-            if (binding == RegisterBinding.Any) {
-                return any;
+            switch (binding) {
+                case Any:
+                    return any;
+                case Fixed:
+                    return fixed;
+                case Stack:
+                    return stack;
             }
-            assert binding == RegisterBinding.Fixed;
-            return fixed;
+            throw GraalInternalError.shouldNotReachHere();
         }
 
         /**
          * Sets the list for a specified binding.
-         * 
+         *
          * @param binding specifies the list to be replaced
          * @param list a list of intervals whose binding is {@code binding}
          */
         public void set(RegisterBinding binding, Interval list) {
             assert list != null;
-            if (binding == RegisterBinding.Any) {
-                any = list;
-            } else {
-                assert binding == RegisterBinding.Fixed;
-                fixed = list;
+            switch (binding) {
+                case Any:
+                    any = list;
+                    break;
+                case Fixed:
+                    fixed = list;
+                    break;
+                case Stack:
+                    stack = list;
+                    break;
             }
         }
 
         /**
          * Adds an interval to a list sorted by {@linkplain Interval#currentFrom() current from}
          * positions.
-         * 
+         *
          * @param binding specifies the list to be updated
          * @param interval the interval to add
          */
@@ -134,7 +149,7 @@
         /**
          * Adds an interval to a list sorted by {@linkplain Interval#from() start} positions and
          * {@linkplain Interval#firstUsage(RegisterPriority) first usage} positions.
-         * 
+         *
          * @param binding specifies the list to be updated
          * @param interval the interval to add
          */
@@ -157,7 +172,7 @@
 
         /**
          * Removes an interval from a list.
-         * 
+         *
          * @param binding specifies the list to be updated
          * @param i the interval to remove
          */
@@ -234,7 +249,12 @@
         /**
          * Interval has no specific register requirements.
          */
-        Any;
+        Any,
+
+        /**
+         * Interval is bound to a stack slot.
+         */
+        Stack;
 
         public static final RegisterBinding[] VALUES = values();
     }
@@ -310,7 +330,7 @@
      * List of use positions. Each entry in the list records the use position and register priority
      * associated with the use position. The entries in the list are in descending order of use
      * position.
-     * 
+     *
      */
     public static final class UsePosList {
 
@@ -318,7 +338,7 @@
 
         /**
          * Creates a use list.
-         * 
+         *
          * @param initialCapacity the initial capacity of the list in terms of entries
          */
         public UsePosList(int initialCapacity) {
@@ -333,7 +353,7 @@
          * Splits this list around a given position. All entries in this list with a use position
          * greater or equal than {@code splitPos} are removed from this list and added to the
          * returned list.
-         * 
+         *
          * @param splitPos the position for the split
          * @return a use position list containing all entries removed from this list that have a use
          *         position greater or equal than {@code splitPos}
@@ -355,7 +375,7 @@
 
         /**
          * Gets the use position at a specified index in this list.
-         * 
+         *
          * @param index the index of the entry for which the use position is returned
          * @return the use position of entry {@code index} in this list
          */
@@ -365,7 +385,7 @@
 
         /**
          * Gets the register priority for the use position at a specified index in this list.
-         * 
+         *
          * @param index the index of the entry for which the register priority is returned
          * @return the register priority of entry {@code index} in this list
          */
@@ -863,6 +883,32 @@
         return true;
     }
 
+    // returns the interval that covers the given opId or null if there is none
+    Interval getIntervalCoveringOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+        assert opId < to() : "can only look into the past";
+
+        if (opId >= from()) {
+            return this;
+        }
+
+        Interval parent = splitParent();
+        Interval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            Interval cur = parent.splitChildren.get(i);
+            if (cur.from() <= opId && opId < cur.to()) {
+                assert result == null : "covered by multiple split children " + result + " and " + cur;
+                result = cur;
+            }
+        }
+
+        return result;
+    }
+
     // returns the last split child that ends before the given opId
     Interval getSplitChildBeforeOpId(int opId) {
         assert opId >= 0 : "invalid opId";
@@ -1044,7 +1090,7 @@
      * When a split child is split again, the new created interval is a direct child of the original
      * parent. That is, there is no tree of split children stored, just a flat list. All split
      * children are spilled to the same {@linkplain #spillSlot spill slot}.
-     * 
+     *
      * @param splitPos the position at which to split this interval
      * @param allocator the register allocator context
      * @return the child interval split off from this interval
@@ -1094,7 +1140,7 @@
     /**
      * Splits this interval at a specified position and returns the head as a new interval (this
      * interval is the tail).
-     * 
+     *
      * Currently, only the first range can be split, and the new interval must not have split
      * positions
      */
@@ -1196,7 +1242,7 @@
 
     /**
      * Gets a single line string for logging the details of this interval to a log stream.
-     * 
+     *
      * @param allocator the register allocator context
      */
     public String logString(LinearScan allocator) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/IntervalWalker.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/IntervalWalker.java	Fri May 30 15:09:09 2014 +0200
@@ -36,22 +36,17 @@
     /**
      * Sorted list of intervals, not live before the current position.
      */
-    RegisterBindingLists unhandledLists;
+    protected RegisterBindingLists unhandledLists;
 
     /**
      * Sorted list of intervals, live at the current position.
      */
-    RegisterBindingLists activeLists;
+    protected RegisterBindingLists activeLists;
 
     /**
      * Sorted list of intervals in a life time hole at the current position.
      */
-    RegisterBindingLists inactiveLists;
-
-    /**
-     * The current interval (taken from the unhandled list) being processed.
-     */
-    protected Interval currentInterval;
+    protected RegisterBindingLists inactiveLists;
 
     /**
      * The current position (intercept point through the intervals).
@@ -64,14 +59,12 @@
     protected RegisterBinding currentBinding;
 
     /**
-     * Processes the {@linkplain #currentInterval} interval in an attempt to allocate a physical
-     * register to it and thus allow it to be moved to a list of {@linkplain #activeLists active}
-     * intervals.
-     * 
-     * @return {@code true} if a register was allocated to the {@linkplain #currentInterval}
-     *         interval
+     * Processes the {@code currentInterval} interval in an attempt to allocate a physical register
+     * to it and thus allow it to be moved to a list of {@linkplain #activeLists active} intervals.
+     *
+     * @return {@code true} if a register was allocated to the {@code currentInterval} interval
      */
-    boolean activateCurrent() {
+    protected boolean activateCurrent(@SuppressWarnings({"unused"}) Interval currentInterval) {
         return true;
     }
 
@@ -85,7 +78,7 @@
 
     /**
      * Creates a new interval walker.
-     * 
+     *
      * @param allocator the register allocator context
      * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed}
      *            intervals
@@ -95,15 +88,13 @@
     IntervalWalker(LinearScan allocator, Interval unhandledFixed, Interval unhandledAny) {
         this.allocator = allocator;
 
-        unhandledLists = new RegisterBindingLists(unhandledFixed, unhandledAny);
-        activeLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker);
-        inactiveLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker);
+        unhandledLists = new RegisterBindingLists(unhandledFixed, unhandledAny, Interval.EndMarker);
+        activeLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker, Interval.EndMarker);
+        inactiveLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker, Interval.EndMarker);
         currentPosition = -1;
-        currentInterval = null;
-        nextInterval();
     }
 
-    void removeFromList(Interval interval) {
+    protected void removeFromList(Interval interval) {
         if (interval.state == State.Active) {
             activeLists.remove(RegisterBinding.Any, interval);
         } else {
@@ -112,7 +103,7 @@
         }
     }
 
-    void walkTo(State state, int from) {
+    private void walkTo(State state, int from) {
         assert state == State.Active || state == State.Inactive : "wrong state";
         for (RegisterBinding binding : RegisterBinding.VALUES) {
             Interval prevprev = null;
@@ -176,7 +167,16 @@
         }
     }
 
-    void nextInterval() {
+    /**
+     * Get the next interval from {@linkplain #unhandledLists} which starts before or at
+     * {@code toOpId}. The returned interval is removed and {@link #currentBinding} is set.
+     *
+     * @postcondition all intervals in {@linkplain #unhandledLists} start after {@code toOpId}.
+     *
+     * @return The next interval or null if there is no {@linkplain #unhandledLists unhandled}
+     *         interval at position {@code toOpId}.
+     */
+    private Interval nextInterval(int toOpId) {
         RegisterBinding binding;
         Interval any = unhandledLists.any;
         Interval fixed = unhandledLists.fixed;
@@ -191,42 +191,61 @@
         } else if (fixed != Interval.EndMarker) {
             binding = RegisterBinding.Fixed;
         } else {
-            currentInterval = null;
-            return;
+            return null;
         }
+        Interval currentInterval = unhandledLists.get(binding);
+
+        if (toOpId < currentInterval.from()) {
+            return null;
+        }
+
         currentBinding = binding;
-        currentInterval = unhandledLists.get(binding);
         unhandledLists.set(binding, currentInterval.next);
         currentInterval.next = Interval.EndMarker;
         currentInterval.rewindRange();
+        return currentInterval;
     }
 
-    void walkTo(int toOpId) {
+    /**
+     * Walk up to {@code toOpId}.
+     *
+     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeLists} and
+     *                {@link #inactiveLists} are populated and {@link Interval#state}s are up to
+     *                date.
+     */
+    protected void walkTo(int toOpId) {
         assert currentPosition <= toOpId : "can not walk backwards";
-        while (currentInterval != null) {
-            boolean isActive = currentInterval.from() <= toOpId;
-            int opId = isActive ? currentInterval.from() : toOpId;
+        for (Interval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
+            int opId = currentInterval.from();
 
             // set currentPosition prior to call of walkTo
             currentPosition = opId;
 
+            // update unhandled stack intervals
+            updateUnhandledStackIntervals(opId);
+
             // call walkTo even if currentPosition == id
             walkTo(State.Active, opId);
             walkTo(State.Inactive, opId);
 
-            if (isActive) {
-                try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
-                    currentInterval.state = State.Active;
-                    if (activateCurrent()) {
-                        activeLists.addToListSortedByCurrentFromPositions(currentBinding, currentInterval);
-                        intervalMoved(currentInterval, State.Unhandled, State.Active);
-                    }
+            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
+                currentInterval.state = State.Active;
+                if (activateCurrent(currentInterval)) {
+                    activeLists.addToListSortedByCurrentFromPositions(currentBinding, currentInterval);
+                    intervalMoved(currentInterval, State.Unhandled, State.Active);
+                }
+            }
+        }
+        // set currentPosition prior to call of walkTo
+        currentPosition = toOpId;
 
-                    nextInterval();
-                }
-            } else {
-                return;
-            }
+        if (currentPosition <= allocator.maxOpId()) {
+            // update unhandled stack intervals
+            updateUnhandledStackIntervals(toOpId);
+
+            // call walkTo if still in range
+            walkTo(State.Active, toOpId);
+            walkTo(State.Inactive, toOpId);
         }
     }
 
@@ -237,4 +256,29 @@
             Debug.log("interval moved from %s to %s: %s", from, to, interval.logString(allocator));
         }
     }
+
+    /**
+     * Move {@linkplain #unhandledLists unhandled} stack intervals to
+     * {@linkplain IntervalWalker #activeLists active}.
+     *
+     * Note that for {@linkplain RegisterBinding#Fixed fixed} and {@linkplain RegisterBinding#Any
+     * any} intervals this is done in {@link #nextInterval(int)}.
+     */
+    private void updateUnhandledStackIntervals(int opId) {
+        Interval currentInterval = unhandledLists.get(RegisterBinding.Stack);
+        while (currentInterval != Interval.EndMarker && currentInterval.from() <= opId) {
+            Interval next = currentInterval.next;
+            if (currentInterval.to() > opId) {
+                currentInterval.state = State.Active;
+                activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, currentInterval);
+                intervalMoved(currentInterval, State.Unhandled, State.Active);
+            } else {
+                currentInterval.state = State.Handled;
+                intervalMoved(currentInterval, State.Unhandled, State.Handled);
+            }
+            currentInterval = next;
+        }
+        unhandledLists.set(RegisterBinding.Stack, currentInterval);
+    }
+
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri May 30 15:09:09 2014 +0200
@@ -65,7 +65,7 @@
 
     boolean callKillsRegisters;
 
-    private static final int INITIAL_SPLIT_INTERVALS_CAPACITY = 32;
+    private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
 
     public static class BlockData {
 
@@ -147,13 +147,6 @@
     BitMap2D intervalInLoop;
 
     /**
-     * The variable operands allocated from this pool. The {@linkplain #operandNumber(Value) number}
-     * of the first variable operand in this pool is one greater than the number of the last
-     * register operand in the pool.
-     */
-    private final ArrayList<Variable> variables;
-
-    /**
      * The {@linkplain #operandNumber(Value) number} of the first variable operand allocated.
      */
     private final int firstVariableNumber;
@@ -167,7 +160,6 @@
 
         this.registers = target.arch.getRegisters();
         this.firstVariableNumber = registers.length;
-        this.variables = new ArrayList<>(ir.numVariables() * 3 / 2);
         this.blockData = new BlockMap<>(ir.getControlFlowGraph());
     }
 
@@ -204,20 +196,6 @@
     }
 
     /**
-     * Gets the operand denoted by a given operand number.
-     */
-    private AllocatableValue operandFor(int operandNumber) {
-        if (operandNumber < firstVariableNumber) {
-            assert operandNumber >= 0;
-            return registers[operandNumber].asValue();
-        }
-        int index = operandNumber - firstVariableNumber;
-        Variable variable = variables.get(index);
-        assert variable.index == index;
-        return variable;
-    }
-
-    /**
      * Gets the number of operands. This value will increase by 1 for new variable.
      */
     private int operandSize() {
@@ -304,12 +282,10 @@
             firstDerivedIntervalIndex = intervalsSize;
         }
         if (intervalsSize == intervals.length) {
-            intervals = Arrays.copyOf(intervals, intervals.length * 2);
+            intervals = Arrays.copyOf(intervals, intervals.length + (intervals.length >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT));
         }
         intervalsSize++;
         Variable variable = new Variable(source.kind(), ir.nextVariable());
-        assert variables.size() == variable.index;
-        variables.add(variable);
 
         Interval interval = createInterval(variable);
         assert intervals[intervalsSize - 1] == interval;
@@ -342,6 +318,10 @@
         return intervalInLoop.at(interval, loop);
     }
 
+    Interval intervalFor(int operandNumber) {
+        return intervals[operandNumber];
+    }
+
     Interval intervalFor(Value operand) {
         int operandNumber = operandNumber(operand);
         assert operandNumber < intervalsSize;
@@ -609,16 +589,16 @@
      * {@linkplain ComputeBlockOrder linear scan order}.
      */
     void numberInstructions() {
+
+        intervalsSize = operandSize();
+        intervals = new Interval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
+
         ValueProcedure setVariableProc = new ValueProcedure() {
 
             @Override
             public Value doValue(Value value) {
                 if (isVariable(value)) {
-                    int variableIdx = asVariable(value).index;
-                    while (variables.size() <= variableIdx) {
-                        variables.add(null);
-                    }
-                    variables.set(variableIdx, asVariable(value));
+                    getOrCreateInterval(asVariable(value));
                 }
                 return value;
             }
@@ -659,13 +639,6 @@
         }
         assert index == numInstructions : "must match";
         assert (index << 1) == opId : "must match: " + (index << 1);
-
-        if (DetailedAsserts.getValue()) {
-            for (int i = 0; i < variables.size(); i++) {
-                assert variables.get(i) != null && variables.get(i).index == i;
-            }
-            assert variables.size() == ir.numVariables();
-        }
     }
 
     /**
@@ -687,66 +660,66 @@
                 List<LIRInstruction> instructions = ir.getLIRforBlock(block);
                 int numInst = instructions.size();
 
+                ValueProcedure useProc = new ValueProcedure() {
+
+                    @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().getIndex());
+                            }
+                        }
+
+                        if (DetailedAsserts.getValue()) {
+                            verifyInput(block, liveKill, operand);
+                        }
+                        return operand;
+                    }
+                };
+                ValueProcedure stateProc = 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().getIndex());
+                            }
+                        }
+
+                        if (DetailedAsserts.getValue()) {
+                            // fixed intervals are never live at block boundaries, so
+                            // they need not be processed in live sets
+                            // process them only in debug mode so that this can be checked
+                            verifyTemp(liveKill, operand);
+                        }
+                        return operand;
+                    }
+                };
+
                 // iterate all instructions of the block
                 for (int j = 0; j < numInst; j++) {
                     final LIRInstruction op = instructions.get(j);
 
-                    ValueProcedure useProc = new ValueProcedure() {
-
-                        @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);
-                                }
-                            }
-
-                            if (DetailedAsserts.getValue()) {
-                                verifyInput(block, liveKill, operand);
-                            }
-                            return operand;
-                        }
-                    };
-                    ValueProcedure stateProc = 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);
-                                }
-                            }
-
-                            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);
@@ -824,14 +797,12 @@
                         // liveOut(block) is the union of liveIn(sux), for successors sux of block
                         int n = block.getSuccessorCount();
                         if (n > 0) {
+                            liveOut.clear();
                             // block has successors
                             if (n > 0) {
-                                liveOut.clear();
                                 for (AbstractBlock<?> successor : block.getSuccessors()) {
                                     liveOut.or(blockData.get(successor).liveIn);
                                 }
-                            } else {
-                                liveOut.clear();
                             }
 
                             if (!blockSets.liveOut.equals(liveOut)) {
@@ -908,14 +879,14 @@
                 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);
+                        Value operand = intervalFor(operandNum).operand;
                         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);
+                    Value operand = intervalFor(operandNum).operand;
                     try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand))) {
 
                         Deque<AbstractBlock<?>> definedIn = new ArrayDeque<>();
@@ -1153,9 +1124,6 @@
 
         try (Indent indent = Debug.logAndIndent("build intervals")) {
 
-            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();
 
@@ -1176,7 +1144,7 @@
                     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);
+                        AllocatableValue operand = intervalFor(operandNum).operand;
                         Debug.log("live in %d: %s", operandNum, operand);
 
                         addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal);
@@ -1185,8 +1153,8 @@
                         // 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);
+                        if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
+                            intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
                         }
                     }
 
@@ -1398,7 +1366,7 @@
         int newLen = newList.length;
 
         // conventional sort-algorithm for new intervals
-        Arrays.sort(newList, INTERVAL_COMPARATOR);
+        Arrays.sort(newList, (Interval a, Interval b) -> a.from() - b.from());
 
         // merge old and new list (both already sorted) into one combined list
         Interval[] combinedList = new Interval[oldLen + newLen];
@@ -1418,25 +1386,6 @@
         sortedIntervals = combinedList;
     }
 
-    private static final Comparator<Interval> INTERVAL_COMPARATOR = new Comparator<Interval>() {
-
-        public int compare(Interval a, Interval b) {
-            if (a != null) {
-                if (b != null) {
-                    return a.from() - b.from();
-                } else {
-                    return -1;
-                }
-            } else {
-                if (b != null) {
-                    return 1;
-                } else {
-                    return 0;
-                }
-            }
-        }
-    };
-
     public void allocateRegisters() {
         try (Indent indent = Debug.logAndIndent("allocate registers")) {
             Interval precoloredIntervals;
@@ -1447,7 +1396,12 @@
             notPrecoloredIntervals = result.second;
 
             // allocate cpu registers
-            LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
+            LinearScanWalker lsw;
+            if (OptimizingLinearScanWalker.Options.LSRAOptimization.getValue()) {
+                lsw = new OptimizingLinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
+            } else {
+                lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
+            }
             lsw.walk();
             lsw.finishAllocation();
         }
@@ -1469,25 +1423,12 @@
         throw new BailoutException("LinearScan: interval is null");
     }
 
-    Interval intervalAtBlockBegin(AbstractBlock<?> block, Value operand) {
-        assert isVariable(operand) : "register number out of bounds";
-        assert intervalFor(operand) != null : "no interval found";
-
-        return splitChildAtOpId(intervalFor(operand), getFirstLirInstructionId(block), LIRInstruction.OperandMode.DEF);
+    Interval intervalAtBlockBegin(AbstractBlock<?> block, int operandNumber) {
+        return splitChildAtOpId(intervalFor(operandNumber), getFirstLirInstructionId(block), LIRInstruction.OperandMode.DEF);
     }
 
-    Interval intervalAtBlockEnd(AbstractBlock<?> block, Value operand) {
-        assert isVariable(operand) : "register number out of bounds";
-        assert intervalFor(operand) != null : "no interval found";
-
-        return splitChildAtOpId(intervalFor(operand), getLastLirInstructionId(block) + 1, LIRInstruction.OperandMode.DEF);
-    }
-
-    Interval intervalAtOpId(Value operand, int opId) {
-        assert isVariable(operand) : "register number out of bounds";
-        assert intervalFor(operand) != null : "no interval found";
-
-        return splitChildAtOpId(intervalFor(operand), opId, LIRInstruction.OperandMode.USE);
+    Interval intervalAtBlockEnd(AbstractBlock<?> block, int operandNumber) {
+        return splitChildAtOpId(intervalFor(operandNumber), getLastLirInstructionId(block) + 1, LIRInstruction.OperandMode.DEF);
     }
 
     void resolveCollectMappings(AbstractBlock<?> fromBlock, AbstractBlock<?> toBlock, MoveResolver moveResolver) {
@@ -1501,9 +1442,8 @@
             assert operandNum < numOperands : "live information set for not exisiting interval";
             assert blockData.get(fromBlock).liveOut.get(operandNum) && blockData.get(toBlock).liveIn.get(operandNum) : "interval not live at this edge";
 
-            Value liveOperand = operandFor(operandNum);
-            Interval fromInterval = intervalAtBlockEnd(fromBlock, liveOperand);
-            Interval toInterval = intervalAtBlockBegin(toBlock, liveOperand);
+            Interval fromInterval = intervalAtBlockEnd(fromBlock, operandNum);
+            Interval toInterval = intervalAtBlockBegin(toBlock, operandNum);
 
             if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
                 // need to insert move instruction
@@ -1914,7 +1854,6 @@
             }
 
             printLir("After register number assignment", true);
-
         }
     }
 
@@ -1946,10 +1885,6 @@
         // (check that all intervals have a correct register and that no registers are overwritten)
         verifyIntervals();
 
-        // verifyNoOopsInFixedIntervals();
-
-        verifyConstants();
-
         verifyRegisters();
 
         Debug.log("no errors found");
@@ -2103,23 +2038,6 @@
         }
     }
 
-    void verifyConstants() {
-        try (Indent indent = Debug.logAndIndent("verifying that unpinned constants are not alive across block boundaries")) {
-            for (AbstractBlock<?> block : sortedBlocks) {
-                BitSet liveAtEdge = blockData.get(block).liveIn;
-
-                // visit all operands where the liveAtEdge bit is set
-                for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) {
-                    Debug.log("checking interval %d of block B%d", operandNum, block.getId());
-                    Value operand = operandFor(operandNum);
-                    assert isVariable(operand) : "value must have variable operand";
-                    // TKR assert value.asConstant() == null || value.isPinned() :
-                    // "only pinned constants can be alive accross block boundaries";
-                }
-            }
-        }
-    }
-
     /**
      * Returns a value for a interval definition, which can be used for re-materialization.
      *
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Fri May 30 15:09:09 2014 +0200
@@ -42,14 +42,14 @@
 
 /**
  */
-final class LinearScanWalker extends IntervalWalker {
+class LinearScanWalker extends IntervalWalker {
 
-    private Register[] availableRegs;
+    protected Register[] availableRegs;
 
-    private final int[] usePos;
-    private final int[] blockPos;
+    protected final int[] usePos;
+    protected final int[] blockPos;
 
-    private List<Interval>[] spillIntervals;
+    protected List<Interval>[] spillIntervals;
 
     private MoveResolver moveResolver; // for ordering spill moves
 
@@ -430,7 +430,7 @@
 
             splitPart.setInsertMoveWhenActivated(moveNecessary);
 
-            assert splitPart.from() >= currentInterval.currentFrom() : "cannot append new interval before current walk position";
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
             unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
 
             if (Debug.isLogEnabled()) {
@@ -466,6 +466,7 @@
                     assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition";
 
                     allocator.assignSpillSlot(interval);
+                    handleSpillSlot(interval);
                     allocator.changeSpillState(interval, minSplitPos);
 
                     // Also kick parent intervals out of register to memory when they have no use
@@ -480,6 +481,7 @@
                                 // parent is never used, so kick it out of its assigned register
                                 Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
                                 allocator.assignSpillSlot(parent);
+                                handleSpillSlot(parent);
                             } else {
                                 // do not go further back because the register is actually used by
                                 // the interval
@@ -508,6 +510,7 @@
 
                     Interval spilledPart = interval.split(optimalSplitPos, allocator);
                     allocator.assignSpillSlot(spilledPart);
+                    handleSpillSlot(spilledPart);
                     allocator.changeSpillState(spilledPart, optimalSplitPos);
 
                     if (!allocator.isBlockBegin(optimalSplitPos)) {
@@ -528,6 +531,14 @@
         }
     }
 
+    /**
+     * This is called for every interval that is assigned to a stack slot.
+     */
+    protected void handleSpillSlot(Interval interval) {
+        assert interval.location() != null && (interval.canMaterialize() || isStackSlot(interval.location())) : "interval not assigned to a stack slot " + interval;
+        // Do nothing. Stack slots are not processed in this implementation.
+    }
+
     void splitStackInterval(Interval interval) {
         int minSplitPos = currentPosition + 1;
         int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to());
@@ -836,8 +847,7 @@
 
     // allocate a physical register or memory location to an interval
     @Override
-    boolean activateCurrent() {
-        Interval interval = currentInterval;
+    protected boolean activateCurrent(Interval interval) {
         boolean result = true;
 
         try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/OptimizingLinearScanWalker.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.alloc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.alloc.Interval.RegisterBinding;
+import com.oracle.graal.compiler.alloc.Interval.RegisterBindingLists;
+import com.oracle.graal.compiler.alloc.Interval.State;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.options.*;
+
+public class OptimizingLinearScanWalker extends LinearScanWalker {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable LSRA optimization")
+        public static final OptionValue<Boolean> LSRAOptimization = new OptionValue<>(true);
+        @Option(help = "LSRA optimization: Only split but do not reassign")
+        public static final OptionValue<Boolean> LSRAOptSplitOnly = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    OptimizingLinearScanWalker(LinearScan allocator, Interval unhandledFixedFirst, Interval unhandledAnyFirst) {
+        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
+    }
+
+    @Override
+    protected void handleSpillSlot(Interval interval) {
+        assert interval.location() != null : "interval  not assigned " + interval;
+        if (interval.canMaterialize()) {
+            assert !isStackSlot(interval.location()) : "interval can materialize but assigned to a stack slot " + interval;
+            return;
+        }
+        assert isStackSlot(interval.location()) : "interval not assigned to a stack slot " + interval;
+        try (Scope s1 = Debug.scope("LSRAOptimization")) {
+            Debug.log("adding stack to unhandled list %s", interval);
+            unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Stack, interval);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static void printRegisterBindingList(RegisterBindingLists list, RegisterBinding binding) {
+        for (Interval interval = list.get(binding); interval != Interval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval);
+        }
+    }
+
+    @Override
+    void walk() {
+        try (Scope s = Debug.scope("OptimizingLinearScanWalker")) {
+            for (AbstractBlock<?> block : allocator.sortedBlocks) {
+                int nextBlock = allocator.getFirstLirInstructionId(block);
+                try (Scope s1 = Debug.scope("LSRAOptimization")) {
+                    Debug.log("next block: %s (%d)", block, nextBlock);
+                }
+                try (Indent indent0 = Debug.indent()) {
+                    walkTo(nextBlock);
+
+                    try (Scope s1 = Debug.scope("LSRAOptimization")) {
+                        boolean changed = true;
+                        // we need to do this because the active lists might change
+                        loop: while (changed) {
+                            changed = false;
+                            try (Indent indent1 = Debug.logAndIndent("Active intervals: (block %s [%d])", block, nextBlock)) {
+                                for (Interval active = activeLists.get(RegisterBinding.Any); active != Interval.EndMarker; active = active.next) {
+                                    Debug.log("active   (any): %s", active);
+                                    if (optimize(nextBlock, block, active, RegisterBinding.Any)) {
+                                        changed = true;
+                                        break loop;
+                                    }
+                                }
+                                for (Interval active = activeLists.get(RegisterBinding.Stack); active != Interval.EndMarker; active = active.next) {
+                                    Debug.log("active (stack): %s", active);
+                                    if (optimize(nextBlock, block, active, RegisterBinding.Stack)) {
+                                        changed = true;
+                                        break loop;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        super.walk();
+    }
+
+    private boolean optimize(int currentPos, AbstractBlock<?> currentBlock, Interval currentInterval, RegisterBinding binding) {
+        // BEGIN initialize and sanity checks
+        assert currentBlock != null : "block must not be null";
+        assert currentInterval != null : "interval must not be null";
+
+        if (currentBlock.getPredecessorCount() != 1) {
+            // more than one predecessors -> optimization not possible
+            return false;
+        }
+        if (!currentInterval.isSplitChild()) {
+            // interval is not a split child -> no need for optimization
+            return false;
+        }
+
+        if (currentInterval.from() == currentPos) {
+            // the interval starts at the current position so no need for splitting
+            return false;
+        }
+
+        // get current location
+        AllocatableValue currentLocation = currentInterval.location();
+        assert currentLocation != null : "active intervals must have a location assigned!";
+
+        // get predecessor stuff
+        AbstractBlock<?> predecessorBlock = currentBlock.getPredecessors().get(0);
+        int predEndId = allocator.getLastLirInstructionId(predecessorBlock);
+        Interval predecessorInterval = currentInterval.getIntervalCoveringOpId(predEndId);
+        assert predecessorInterval != null : "variable not live at the end of the only predecessor! " + predecessorBlock + " -> " + currentBlock + " interval: " + currentInterval;
+        AllocatableValue predecessorLocation = predecessorInterval.location();
+        assert predecessorLocation != null : "handled intervals must have a location assigned!";
+
+        // END initialize and sanity checks
+
+        if (currentLocation.equals(predecessorLocation)) {
+            // locations are already equal -> nothing to optimize
+            return false;
+        }
+
+        if (!isStackSlot(predecessorLocation) && !isRegister(predecessorLocation)) {
+            assert predecessorInterval.canMaterialize();
+            // value is materialized -> no need for optimization
+            return false;
+        }
+
+        assert isStackSlot(currentLocation) || isRegister(currentLocation) : "current location not a register or stack slot " + currentLocation;
+
+        try (Indent indent = Debug.logAndIndent("location differs: %s vs. %s", predecessorLocation, currentLocation)) {
+            // split current interval at current position
+            Debug.log("splitting at position %d", currentPos);
+
+            assert allocator.isBlockBegin(currentPos) && ((currentPos & 1) == 0) : "split pos must be even when on block boundary";
+
+            Interval splitPart = currentInterval.split(currentPos, allocator);
+            activeLists.remove(binding, currentInterval);
+
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
+
+            // the currentSplitChild is needed later when moves are inserted for reloading
+            assert splitPart.currentSplitChild() == currentInterval : "overwriting wrong currentSplitChild";
+            splitPart.makeCurrentSplitChild();
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("left interval  : %s", currentInterval.logString(allocator));
+                Debug.log("right interval : %s", splitPart.logString(allocator));
+            }
+
+            if (Options.LSRAOptSplitOnly.getValue()) {
+                // just add the split interval to the unhandled list
+                unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
+            } else {
+                if (isRegister(predecessorLocation)) {
+                    splitRegisterInterval(splitPart, asRegister(predecessorLocation));
+                } else {
+                    assert isStackSlot(predecessorLocation);
+                    Debug.log("assigning interval %s to %s", splitPart, predecessorLocation);
+                    splitPart.assignLocation(predecessorLocation);
+                    // activate interval
+                    activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, splitPart);
+                    splitPart.state = State.Active;
+
+                    splitStackInterval(splitPart);
+                }
+            }
+        }
+        return true;
+    }
+
+    private void splitRegisterInterval(Interval interval, Register reg) {
+        // collect current usage of registers
+        initVarsForAlloc(interval);
+        initUseLists(false);
+        spillExcludeActiveFixed();
+        // spillBlockUnhandledFixed(cur);
+        assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0";
+        spillBlockInactiveFixed(interval);
+        spillCollectActiveAny();
+        spillCollectInactiveAny(interval);
+
+        if (Debug.isLogEnabled()) {
+            try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+                for (Register register : availableRegs) {
+                    int i = register.number;
+                    try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
+                        for (int j = 0; j < spillIntervals[i].size(); j++) {
+                            Debug.log("%d ", spillIntervals[i].get(j).operandNumber);
+                        }
+                    }
+                }
+            }
+        }
+
+        // the register must be free at least until this position
+        boolean needSplit = blockPos[reg.number] <= interval.to();
+
+        int splitPos = blockPos[reg.number];
+
+        assert splitPos > 0 : "invalid splitPos";
+        assert needSplit || splitPos > interval.from() : "splitting interval at from";
+
+        Debug.log("assigning interval %s to %s", interval, reg);
+        interval.assignLocation(reg.asValue(interval.kind()));
+        if (needSplit) {
+            // register not available for full interval : so split it
+            splitWhenPartialRegisterAvailable(interval, splitPos);
+        }
+
+        // perform splitting and spilling for all affected intervals
+        splitAndSpillIntersectingIntervals(reg);
+
+        // activate interval
+        activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Any, interval);
+        interval.state = State.Active;
+
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -22,16 +22,15 @@
  */
 package com.oracle.graal.compiler.gen;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.gen.*;
 
-public class BytecodeLIRBuilder {
-    protected final LIRGenerator gen;
+public abstract class BytecodeLIRBuilder {
+    protected final LIRGeneratorTool gen;
     protected final BytecodeParserTool parser;
 
-    public BytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         this.gen = gen;
         this.parser = parser;
     }
@@ -53,7 +52,7 @@
         gen.emitIncomingValues(params);
 
         Signature sig = method.getSignature();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         for (int i = 0; i < sig.getParameterCount(!isStatic); i++) {
             Value paramValue = params[i];
             assert paramValue.getKind() == sig.getParameterKind(i).getStackKind();
@@ -62,4 +61,10 @@
 
     }
 
+    public abstract int getArrayLengthOffset();
+
+    public abstract Constant getClassConstant(ResolvedJavaType declaringClass);
+
+    public abstract int getFieldOffset(ResolvedJavaField field);
+
 }
\ No newline at end of file
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.compiler.gen;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -46,8 +48,8 @@
         this.nodeOperands = nodeOperands;
     }
 
-    protected final HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
-    protected final IdentityHashMap<VirtualObjectNode, EscapeObjectState> objectStates = new IdentityHashMap<>();
+    protected final Map<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
+    protected final Map<VirtualObjectNode, EscapeObjectState> objectStates = newNodeIdentityMap();
 
     public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) {
         assert virtualObjects.size() == 0;
@@ -76,7 +78,7 @@
             boolean changed;
             do {
                 changed = false;
-                IdentityHashMap<VirtualObjectNode, VirtualObject> virtualObjectsCopy = new IdentityHashMap<>(virtualObjects);
+                Map<VirtualObjectNode, VirtualObject> virtualObjectsCopy = newIdentityMap(virtualObjects);
                 for (Entry<VirtualObjectNode, VirtualObject> entry : virtualObjectsCopy.entrySet()) {
                     if (entry.getValue().getValues() == null) {
                         VirtualObjectNode vobj = entry.getKey();
@@ -116,21 +118,33 @@
     }
 
     protected BytecodeFrame computeFrameForState(FrameState state) {
-        int numLocals = state.localsSize();
-        int numStack = state.stackSize();
-        int numLocks = state.locksSize();
+        try {
+            assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI;
+            assert state.bci != BytecodeFrame.UNKNOWN_BCI;
+            assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0;
+            assert !(state.method().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) ||
+                            state.locksSize() > 0;
+            assert state.verify();
+
+            int numLocals = state.localsSize();
+            int numStack = state.stackSize();
+            int numLocks = state.locksSize();
 
-        Value[] values = new Value[numLocals + numStack + numLocks];
-        computeLocals(state, numLocals, values);
-        computeStack(state, numLocals, numStack, values);
-        computeLocks(state, values);
+            Value[] values = new Value[numLocals + numStack + numLocks];
+            computeLocals(state, numLocals, values);
+            computeStack(state, numLocals, numStack, values);
+            computeLocks(state, values);
 
-        BytecodeFrame caller = null;
-        if (state.outerFrameState() != null) {
-            caller = computeFrameForState(state.outerFrameState());
+            BytecodeFrame caller = null;
+            if (state.outerFrameState() != null) {
+                caller = computeFrameForState(state.outerFrameState());
+            }
+            return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
+        } catch (GraalInternalError e) {
+            throw e.addContext("FrameState: ", state);
         }
-        assert state.bci >= FrameState.BEFORE_BCI : "bci == " + state.bci;
-        return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
     }
 
     protected void computeLocals(FrameState state, int numLocals, Value[] values) {
@@ -169,39 +183,43 @@
     private static final DebugMetric STATE_CONSTANTS = Debug.metric("StateConstants");
 
     protected Value toValue(ValueNode value) {
-        if (value instanceof VirtualObjectNode) {
-            VirtualObjectNode obj = (VirtualObjectNode) value;
-            EscapeObjectState state = objectStates.get(obj);
-            if (state == null && obj.entryCount() > 0) {
-                // null states occur for objects with 0 fields
-                throw new GraalInternalError("no mapping found for virtual object %s", obj);
-            }
-            if (state instanceof MaterializedObjectState) {
-                return toValue(((MaterializedObjectState) state).materializedValue());
-            } else {
-                assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
-                VirtualObject vobject = virtualObjects.get(value);
-                if (vobject == null) {
-                    vobject = VirtualObject.get(obj.type(), null, virtualObjects.size());
-                    virtualObjects.put(obj, vobject);
+        try {
+            if (value instanceof VirtualObjectNode) {
+                VirtualObjectNode obj = (VirtualObjectNode) value;
+                EscapeObjectState state = objectStates.get(obj);
+                if (state == null && obj.entryCount() > 0) {
+                    // null states occur for objects with 0 fields
+                    throw new GraalInternalError("no mapping found for virtual object %s", obj);
                 }
-                STATE_VIRTUAL_OBJECTS.increment();
-                return vobject;
-            }
-        } else if (value instanceof ConstantNode) {
-            STATE_CONSTANTS.increment();
-            return ((ConstantNode) value).getValue();
+                if (state instanceof MaterializedObjectState) {
+                    return toValue(((MaterializedObjectState) state).materializedValue());
+                } else {
+                    assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
+                    VirtualObject vobject = virtualObjects.get(value);
+                    if (vobject == null) {
+                        vobject = VirtualObject.get(obj.type(), null, virtualObjects.size());
+                        virtualObjects.put(obj, vobject);
+                    }
+                    STATE_VIRTUAL_OBJECTS.increment();
+                    return vobject;
+                }
+            } else if (value instanceof ConstantNode) {
+                STATE_CONSTANTS.increment();
+                return ((ConstantNode) value).getValue();
 
-        } else if (value != null) {
-            STATE_VARIABLES.increment();
-            Value operand = nodeOperands.get(value);
-            assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value;
-            return operand;
+            } else if (value != null) {
+                STATE_VARIABLES.increment();
+                Value operand = nodeOperands.get(value);
+                assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value;
+                return operand;
 
-        } else {
-            // return a dummy value because real value not needed
-            STATE_ILLEGALS.increment();
-            return Value.ILLEGAL;
+            } else {
+                // return a dummy value because real value not needed
+                STATE_ILLEGALS.increment();
+                return Value.ILLEGAL;
+            }
+        } catch (GraalInternalError e) {
+            throw e.addContext("toValue: ", value);
         }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResult.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.gen;
-
-import com.oracle.graal.lir.*;
-
-public interface LIRGenerationResult {
-    FrameMap getFrameMap();
-
-    LIR getLIR();
-
-    boolean hasForeignCall();
-
-    void setForeignCall(boolean b);
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResultBase.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.gen;
-
-import com.oracle.graal.lir.*;
-
-public class LIRGenerationResultBase implements LIRGenerationResult {
-    private final LIR lir;
-    private final FrameMap frameMap;
-    /**
-     * Records whether the code being generated makes at least one foreign call.
-     */
-    private boolean hasForeignCall;
-
-    public LIRGenerationResultBase(LIR lir, FrameMap frameMap) {
-        this.lir = lir;
-        this.frameMap = frameMap;
-    }
-
-    public LIR getLIR() {
-        return lir;
-    }
-
-    /**
-     * Determines whether the code being generated makes at least one foreign call.
-     */
-    public boolean hasForeignCall() {
-        return hasForeignCall;
-    }
-
-    public final void setForeignCall(boolean hasForeignCall) {
-        this.hasForeignCall = hasForeignCall;
-    }
-
-    public final FrameMap getFrameMap() {
-        return frameMap;
-    }
-
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,628 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.gen;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.lir.LIR.*;
-import static com.oracle.graal.lir.LIRValueUtil.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.NoOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.options.*;
-import com.oracle.graal.phases.util.*;
-
-/**
- * This class traverses the HIR instructions and generates LIR instructions from them.
- */
-public abstract class LIRGenerator implements ArithmeticLIRGenerator, LIRGeneratorTool, LIRTypeTool {
-
-    public static class Options {
-        // @formatter:off
-        @Option(help = "Print HIR along side LIR as the latter is generated")
-        public static final OptionValue<Boolean> PrintIRWithLIR = new OptionValue<>(false);
-        @Option(help = "The trace level for the LIR generator")
-        public static final OptionValue<Integer> TraceLIRGeneratorLevel = new OptionValue<>(0);
-        // @formatter:on
-    }
-
-    private final Providers providers;
-    private final CallingConvention cc;
-
-    private DebugInfoBuilder debugInfoBuilder;
-
-    protected AbstractBlock<?> currentBlock;
-    public final int traceLevel;
-    public final boolean printIRWithLIR;
-
-    /**
-     * Handle for an operation that loads a constant into a variable. The operation starts in the
-     * first block where the constant is used but will eventually be
-     * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the
-     * constant.
-     */
-    public static class LoadConstant implements Comparable<LoadConstant> {
-        /**
-         * The index of {@link #op} within {@link #block}'s instruction list or -1 if {@code op} is
-         * to be moved to a dominator block.
-         */
-        int index;
-
-        /**
-         * The operation that loads the constant.
-         */
-        private final LIRInstruction op;
-
-        /**
-         * The block that does or will contain {@link #op}. This is initially the block where the
-         * first usage of the constant is seen during LIR generation.
-         */
-        AbstractBlock<?> block;
-
-        /**
-         * The variable into which the constant is loaded.
-         */
-        final Variable variable;
-
-        public LoadConstant(Variable variable, AbstractBlock<?> block, int index, LIRInstruction op) {
-            this.variable = variable;
-            this.block = block;
-            this.index = index;
-            this.op = op;
-        }
-
-        /**
-         * Sorts {@link LoadConstant} objects according to their enclosing blocks. This is used to
-         * group loads per block in {@link LIRGenerator#insertConstantLoads()}.
-         */
-        public int compareTo(LoadConstant o) {
-            if (block.getId() < o.block.getId()) {
-                return -1;
-            }
-            if (block.getId() > o.block.getId()) {
-                return 1;
-            }
-            return 0;
-        }
-
-        @Override
-        public String toString() {
-            return block + "#" + op;
-        }
-
-        /**
-         * Removes the {@link #op} from its original location if it is still at that location.
-         */
-        public void unpin(LIR lir) {
-            if (index >= 0) {
-                // Replace the move with a filler op so that the operation
-                // list does not need to be adjusted.
-                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-                instructions.set(index, new NoOp(null, -1));
-                index = -1;
-            }
-        }
-    }
-
-    Map<Constant, LoadConstant> constantLoads;
-
-    private LIRGenerationResult res;
-
-    /**
-     * Set this before using the LIRGenerator.
-     *
-     * TODO this should be removed
-     */
-    void setDebugInfoBuilder(DebugInfoBuilder builder) {
-        debugInfoBuilder = builder;
-    }
-
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for store
-     * operations, i.e., on the right hand side of a memory access.
-     *
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    public abstract boolean canStoreConstant(Constant c, boolean isCompressed);
-
-    public LIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult res) {
-        this.res = res;
-        this.providers = providers;
-        this.cc = cc;
-        this.traceLevel = Options.TraceLIRGeneratorLevel.getValue();
-        this.printIRWithLIR = Options.PrintIRWithLIR.getValue();
-    }
-
-    /**
-     * Returns true if the redundant move elimination optimization should be done after register
-     * allocation.
-     */
-    public boolean canEliminateRedundantMoves() {
-        return true;
-    }
-
-    @Override
-    public TargetDescription target() {
-        return getCodeCache().getTarget();
-    }
-
-    public Providers getProviders() {
-        return providers;
-    }
-
-    @Override
-    public MetaAccessProvider getMetaAccess() {
-        return providers.getMetaAccess();
-    }
-
-    @Override
-    public CodeCacheProvider getCodeCache() {
-        return providers.getCodeCache();
-    }
-
-    @Override
-    public ForeignCallsProvider getForeignCalls() {
-        return providers.getForeignCalls();
-    }
-
-    /**
-     * Creates a new {@linkplain Variable variable}.
-     *
-     * @param platformKind The kind of the new variable.
-     * @return a new variable
-     */
-    @Override
-    public Variable newVariable(PlatformKind platformKind) {
-        return new Variable(platformKind, res.getLIR().nextVariable());
-    }
-
-    @Override
-    public RegisterAttributes attributes(Register register) {
-        return res.getFrameMap().registerConfig.getAttributesMap()[register.number];
-    }
-
-    @Override
-    public abstract Variable emitMove(Value input);
-
-    public AllocatableValue asAllocatable(Value value) {
-        if (isAllocatableValue(value)) {
-            return asAllocatableValue(value);
-        } else {
-            return emitMove(value);
-        }
-    }
-
-    public Variable load(Value value) {
-        if (!isVariable(value)) {
-            return emitMove(value);
-        }
-        return (Variable) value;
-    }
-
-    public Value loadNonConst(Value value) {
-        if (isConstant(value) && !canInlineConstant((Constant) value)) {
-            return emitMove(value);
-        }
-        return value;
-    }
-
-    /**
-     * Determines if only oop maps are required for the code generated from the LIR.
-     */
-    protected boolean needOnlyOopMaps() {
-        return false;
-    }
-
-    private static FrameState getFrameState(DeoptimizingNode deopt) {
-        if (deopt instanceof DeoptimizingNode.DeoptBefore) {
-            assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter);
-            return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore();
-        } else if (deopt instanceof DeoptimizingNode.DeoptDuring) {
-            assert !(deopt instanceof DeoptimizingNode.DeoptAfter);
-            return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring();
-        } else {
-            assert deopt instanceof DeoptimizingNode.DeoptAfter;
-            return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter();
-        }
-    }
-
-    public LIRFrameState state(DeoptimizingNode deopt) {
-        if (!deopt.canDeoptimize()) {
-            return null;
-        }
-        return stateFor(getFrameState(deopt));
-    }
-
-    public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
-        if (!deopt.canDeoptimize()) {
-            return null;
-        }
-        return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge);
-    }
-
-    public LIRFrameState stateFor(FrameState state) {
-        return stateForWithExceptionEdge(state, null);
-    }
-
-    public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) {
-        if (needOnlyOopMaps()) {
-            return new LIRFrameState(null, null, null);
-        }
-        assert state != null;
-        return getDebugInfoBuilder().build(state, exceptionEdge);
-    }
-
-    /**
-     * Gets the ABI specific operand used to return a value of a given kind from a method.
-     *
-     * @param kind the kind of value being returned
-     * @return the operand representing the ABI defined location used return a value of kind
-     *         {@code kind}
-     */
-    public AllocatableValue resultOperandFor(Kind kind) {
-        if (kind == Kind.Void) {
-            return ILLEGAL;
-        }
-        return res.getFrameMap().registerConfig.getReturnRegister(kind).asValue(kind);
-    }
-
-    public void append(LIRInstruction op) {
-        if (printIRWithLIR && !TTY.isSuppressed()) {
-            TTY.println(op.toStringWithIdPrefix());
-            TTY.println();
-        }
-        assert LIRVerifier.verify(op);
-        res.getLIR().getLIRforBlock(currentBlock).add(op);
-    }
-
-    public boolean hasBlockEnd(AbstractBlock<?> block) {
-        List<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
-        if (ops.size() == 0) {
-            return false;
-        }
-        return ops.get(ops.size() - 1) instanceof BlockEndOp;
-    }
-
-    public final void doBlockStart(AbstractBlock<?> block) {
-        if (printIRWithLIR) {
-            TTY.print(block.toString());
-        }
-
-        currentBlock = block;
-
-        // set up the list of LIR instructions
-        assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block";
-        res.getLIR().setLIRforBlock(block, new ArrayList<LIRInstruction>());
-
-        append(new LabelOp(new Label(block.getId()), block.isAligned()));
-
-        if (traceLevel >= 1) {
-            TTY.println("BEGIN Generating LIR for block B" + block.getId());
-        }
-    }
-
-    public final void doBlockEnd(AbstractBlock<?> block) {
-
-        if (traceLevel >= 1) {
-            TTY.println("END Generating LIR for block B" + block.getId());
-        }
-
-        currentBlock = null;
-
-        if (printIRWithLIR) {
-            TTY.println();
-        }
-    }
-
-    public void emitIncomingValues(Value[] params) {
-        ((LabelOp) res.getLIR().getLIRforBlock(currentBlock).get(0)).setIncomingValues(params);
-    }
-
-    public abstract void emitJump(LabelRef label);
-
-    public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
-                    double trueDestinationProbability);
-
-    public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
-
-    public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
-
-    public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
-
-    public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
-
-    protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
-
-    public static AllocatableValue toStackKind(AllocatableValue value) {
-        if (value.getKind().getStackKind() != value.getKind()) {
-            // We only have stack-kinds in the LIR, so convert the operand kind for values from the
-            // calling convention.
-            if (isRegister(value)) {
-                return asRegister(value).asValue(value.getKind().getStackKind());
-            } else if (isStackSlot(value)) {
-                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
-            } else {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-        return value;
-    }
-
-    @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
-        LIRFrameState state = null;
-        if (linkage.canDeoptimize()) {
-            if (info != null) {
-                state = stateFor(getFrameState(info));
-            } else {
-                assert needOnlyOopMaps();
-                state = new LIRFrameState(null, null, null);
-            }
-        }
-
-        // move the arguments into the correct location
-        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
-        res.getFrameMap().callsMethod(linkageCc);
-        assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
-        Value[] argLocations = new Value[args.length];
-        for (int i = 0; i < args.length; i++) {
-            Value arg = args[i];
-            AllocatableValue loc = linkageCc.getArgument(i);
-            emitMove(loc, arg);
-            argLocations[i] = loc;
-        }
-        res.setForeignCall(true);
-        emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
-
-        if (isLegal(linkageCc.getReturn())) {
-            return emitMove(linkageCc.getReturn());
-        } else {
-            return null;
-        }
-    }
-
-    protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
-        int keyCount = keyConstants.length;
-        SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
-        long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
-        double tableSwitchDensity = keyCount / (double) valueRange;
-        /*
-         * This heuristic tries to find a compromise between the effort for the best switch strategy
-         * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
-         * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
-         * gradually with additional effort.
-         */
-        if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) {
-            emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
-        } else {
-            int minValue = keyConstants[0].asInt();
-            assert valueRange < Integer.MAX_VALUE;
-            LabelRef[] targets = new LabelRef[(int) valueRange];
-            for (int i = 0; i < valueRange; i++) {
-                targets[i] = defaultTarget;
-            }
-            for (int i = 0; i < keyCount; i++) {
-                targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
-            }
-            emitTableSwitch(minValue, defaultTarget, targets, value);
-        }
-    }
-
-    protected abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
-
-    protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
-
-    public CallingConvention getCallingConvention() {
-        return cc;
-    }
-
-    public DebugInfoBuilder getDebugInfoBuilder() {
-        assert debugInfoBuilder != null;
-        return debugInfoBuilder;
-    }
-
-    @Override
-    public void beforeRegisterAllocation() {
-        insertConstantLoads();
-    }
-
-    /**
-     * Moves deferred {@linkplain LoadConstant loads} of constants into blocks dominating all usages
-     * of the constant. Any operations inserted into a block are guaranteed to be immediately prior
-     * to the first control flow instruction near the end of the block.
-     */
-    private void insertConstantLoads() {
-        if (constantLoads != null) {
-            // Remove loads where all usages are in the same block.
-            for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) {
-                LoadConstant lc = iter.next().getValue();
-
-                // Move loads of constant outside of loops
-                if (OptScheduleOutOfLoops.getValue()) {
-                    AbstractBlock<?> outOfLoopDominator = lc.block;
-                    while (outOfLoopDominator.getLoop() != null) {
-                        outOfLoopDominator = outOfLoopDominator.getDominator();
-                    }
-                    if (outOfLoopDominator != lc.block) {
-                        lc.unpin(res.getLIR());
-                        lc.block = outOfLoopDominator;
-                    }
-                }
-
-                if (lc.index != -1) {
-                    assert res.getLIR().getLIRforBlock(lc.block).get(lc.index) == lc.op;
-                    iter.remove();
-                }
-            }
-            if (constantLoads.isEmpty()) {
-                return;
-            }
-
-            // Sorting groups the loads per block.
-            LoadConstant[] groupedByBlock = constantLoads.values().toArray(new LoadConstant[constantLoads.size()]);
-            Arrays.sort(groupedByBlock);
-
-            int groupBegin = 0;
-            while (true) {
-                int groupEnd = groupBegin + 1;
-                AbstractBlock<?> block = groupedByBlock[groupBegin].block;
-                while (groupEnd < groupedByBlock.length && groupedByBlock[groupEnd].block == block) {
-                    groupEnd++;
-                }
-                int groupSize = groupEnd - groupBegin;
-
-                List<LIRInstruction> ops = res.getLIR().getLIRforBlock(block);
-                int lastIndex = ops.size() - 1;
-                assert ops.get(lastIndex) instanceof BlockEndOp;
-                int insertionIndex = lastIndex;
-                for (int i = Math.max(0, lastIndex - MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END); i < lastIndex; i++) {
-                    if (getExceptionEdge(ops.get(i)) != null) {
-                        insertionIndex = i;
-                        break;
-                    }
-                }
-
-                if (groupSize == 1) {
-                    ops.add(insertionIndex, groupedByBlock[groupBegin].op);
-                } else {
-                    assert groupSize > 1;
-                    List<LIRInstruction> moves = new ArrayList<>(groupSize);
-                    for (int i = groupBegin; i < groupEnd; i++) {
-                        moves.add(groupedByBlock[i].op);
-                    }
-                    ops.addAll(insertionIndex, moves);
-                }
-
-                if (groupEnd == groupedByBlock.length) {
-                    break;
-                }
-                groupBegin = groupEnd;
-            }
-            constantLoads = null;
-        }
-    }
-
-    /**
-     * Gets a garbage value for a given kind.
-     */
-    protected Constant zapValueForKind(PlatformKind kind) {
-        long dead = 0xDEADDEADDEADDEADL;
-        switch ((Kind) kind) {
-            case Boolean:
-                return Constant.FALSE;
-            case Byte:
-                return Constant.forByte((byte) dead);
-            case Char:
-                return Constant.forChar((char) dead);
-            case Short:
-                return Constant.forShort((short) dead);
-            case Int:
-                return Constant.forInt((int) dead);
-            case Double:
-                return Constant.forDouble(Double.longBitsToDouble(dead));
-            case Float:
-                return Constant.forFloat(Float.intBitsToFloat((int) dead));
-            case Long:
-                return Constant.forLong(dead);
-            case Object:
-                return Constant.NULL_OBJECT;
-            default:
-                throw new IllegalArgumentException(kind.toString());
-        }
-    }
-
-    /**
-     * Default implementation: Return the Java stack kind for each stamp.
-     */
-    public PlatformKind getPlatformKind(Stamp stamp) {
-        return stamp.getPlatformKind(this);
-    }
-
-    public PlatformKind getIntegerKind(int bits) {
-        if (bits <= 8) {
-            return Kind.Byte;
-        } else if (bits <= 16) {
-            return Kind.Short;
-        } else if (bits <= 32) {
-            return Kind.Int;
-        } else {
-            assert bits <= 64;
-            return Kind.Long;
-        }
-    }
-
-    public PlatformKind getFloatingKind(int bits) {
-        switch (bits) {
-            case 32:
-                return Kind.Float;
-            case 64:
-                return Kind.Double;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public PlatformKind getObjectKind() {
-        return Kind.Object;
-    }
-
-    public abstract void emitBitCount(Variable result, Value operand);
-
-    public abstract void emitBitScanForward(Variable result, Value operand);
-
-    public abstract void emitBitScanReverse(Variable result, Value operand);
-
-    public abstract void emitByteSwap(Variable result, Value operand);
-
-    public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
-
-    public AbstractBlock<?> getCurrentBlock() {
-        return currentBlock;
-    }
-
-    void setCurrentBlock(AbstractBlock<?> block) {
-        currentBlock = block;
-    }
-
-    public LIRGenerationResult getResult() {
-        return res;
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,8 @@
 package com.oracle.graal.compiler.gen;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
 
@@ -34,44 +36,79 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.LIRGenerator.LoadConstant;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGenerator.LoadConstant;
+import com.oracle.graal.lir.gen.LIRGenerator.Options;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 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.
  */
+@MatchableNode(nodeClass = ConstantNode.class, shareable = true)
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = FloatSubNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"object", "location"})
+@MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
+@MatchableNode(nodeClass = IntegerSubNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = NarrowNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = ReadNode.class, inputs = {"object", "location"})
+@MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = WriteNode.class, inputs = {"object", "location", "value"})
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatAddNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatMulNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerAddNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerBelowThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerMulNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = XorNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = PiNode.class, inputs = {"object"})
+@MatchableNode(nodeClass = ConstantLocationNode.class, shareable = true)
 public abstract class NodeLIRBuilder implements NodeLIRBuilderTool {
 
     private final NodeMap<Value> nodeOperands;
     private final DebugInfoBuilder debugInfoBuilder;
 
-    protected final LIRGenerator gen;
+    protected final LIRGeneratorTool gen;
 
     private ValueNode currentInstruction;
     private ValueNode lastInstructionPrinted; // Debugging only
 
-    public NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    private Map<Class<? extends ValueNode>, List<MatchStatement>> matchRules;
+
+    public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         this.gen = gen;
         this.nodeOperands = graph.createNodeMap();
-        this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
-        gen.setDebugInfoBuilder(debugInfoBuilder);
+        this.debugInfoBuilder = createDebugInfoBuilder(graph, nodeOperands);
+        if (MatchExpressions.getValue()) {
+            matchRules = MatchRuleRegistry.lookup(getClass());
+        }
     }
 
-    @SuppressWarnings("hiding")
-    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+    @SuppressWarnings({"unused", "hiding"})
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
         return new DebugInfoBuilder(nodeOperands);
     }
 
@@ -113,25 +150,25 @@
                     return setResult(node, value);
                 } else {
                     Variable loadedValue;
-                    if (gen.constantLoads == null) {
-                        gen.constantLoads = new HashMap<>();
+                    if (gen.getConstantLoads() == null) {
+                        gen.setConstantLoads(new HashMap<>());
                     }
-                    LoadConstant load = gen.constantLoads.get(value);
+                    LoadConstant load = gen.getConstantLoads().get(value);
                     assert gen.getCurrentBlock() instanceof Block;
                     if (load == null) {
                         int index = gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
                         loadedValue = gen.emitMove(value);
                         LIRInstruction op = gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).get(index);
-                        gen.constantLoads.put(value, new LoadConstant(loadedValue, gen.getCurrentBlock(), index, op));
+                        gen.getConstantLoads().put(value, new LoadConstant(loadedValue, gen.getCurrentBlock(), index, op));
                     } else {
-                        AbstractBlock<?> dominator = ControlFlowGraph.commonDominator((Block) load.block, (Block) gen.getCurrentBlock());
-                        loadedValue = load.variable;
-                        if (dominator != load.block) {
+                        AbstractBlock<?> dominator = ControlFlowGraph.commonDominator((Block) load.getBlock(), (Block) gen.getCurrentBlock());
+                        loadedValue = load.getVariable();
+                        if (dominator != load.getBlock()) {
                             load.unpin(gen.getResult().getLIR());
                         } else {
-                            assert load.block != gen.getCurrentBlock() || load.index < gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
+                            assert load.getBlock() != gen.getCurrentBlock() || load.getIndex() < gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size();
                         }
-                        load.block = dominator;
+                        load.setBlock(dominator);
                     }
                     return loadedValue;
                 }
@@ -154,13 +191,25 @@
     @Override
     public Value setResult(ValueNode x, Value operand) {
         assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable());
-        assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice";
         assert operand != null && isLegal(operand) : "operand must be legal";
         assert !(x instanceof VirtualObjectNode);
         nodeOperands.set(x, operand);
         return operand;
     }
 
+    /**
+     * Used by the {@link MatchStatement} machinery to override the generation LIR for some
+     * ValueNodes.
+     */
+    public void setMatchResult(ValueNode x, Value operand) {
+        assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue;
+        assert operand instanceof ComplexMatchValue || x.usages().count() == 1 : "interior matches must be single user";
+        assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert !(x instanceof VirtualObjectNode);
+        nodeOperands.set(x, operand);
+    }
+
     public LabelRef getLIRBlock(FixedNode b) {
         assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph;
         Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b);
@@ -172,7 +221,7 @@
     }
 
     public final void append(LIRInstruction op) {
-        if (gen.printIRWithLIR && !TTY.isSuppressed()) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
             if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
                 lastInstructionPrinted = currentInstruction;
                 InstructionPrinter ip = new InstructionPrinter(TTY.out());
@@ -193,34 +242,42 @@
         }
 
         List<ScheduledNode> nodes = blockMap.get(block);
-        int instructionsFolded = 0;
+
+        // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
+        // of instructions
+        matchComplexExpressions(nodes);
+
         for (int i = 0; i < nodes.size(); i++) {
             Node instr = nodes.get(i);
-            if (gen.traceLevel >= 3) {
+            if (Options.TraceLIRGeneratorLevel.getValue() >= 3) {
                 TTY.println("LIRGen for " + instr);
             }
-            if (instructionsFolded > 0) {
-                instructionsFolded--;
-                continue;
-            }
             if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
                 // Loading of constants is done lazily by operand()
 
             } else if (instr instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) instr;
-                if (!hasOperand(valueNode)) {
+                Value operand = getOperand(valueNode);
+                if (operand == null) {
                     if (!peephole(valueNode)) {
-                        instructionsFolded = maybeFoldMemory(nodes, i, valueNode);
-                        if (instructionsFolded == 0) {
-                            try {
-                                doRoot((ValueNode) instr);
-                            } catch (GraalInternalError e) {
-                                throw GraalGraphInternalError.transformAndAddContext(e, instr);
-                            } catch (Throwable e) {
-                                throw new GraalGraphInternalError(e).addContext(instr);
-                            }
+                        try {
+                            doRoot((ValueNode) instr);
+                        } catch (GraalInternalError e) {
+                            throw GraalGraphInternalError.transformAndAddContext(e, instr);
+                        } catch (Throwable e) {
+                            throw new GraalGraphInternalError(e).addContext(instr);
                         }
                     }
+                } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) {
+                    // Doesn't need to be evaluated
+                    Debug.log("interior match for %s", valueNode);
+                } else if (operand instanceof ComplexMatchValue) {
+                    Debug.log("complex match for %s", valueNode);
+                    ComplexMatchValue match = (ComplexMatchValue) operand;
+                    operand = match.evaluate(this);
+                    if (operand != null) {
+                        setResult(valueNode, operand);
+                    }
                 } else {
                     // There can be cases in which the result of an instruction is already set
                     // before by other instructions.
@@ -245,156 +302,45 @@
         gen.doBlockEnd(block);
     }
 
-    private static final DebugMetric MemoryFoldSuccess = Debug.metric("MemoryFoldSuccess");
-    private static final DebugMetric MemoryFoldFailed = Debug.metric("MemoryFoldFailed");
-    private static final DebugMetric MemoryFoldFailedNonAdjacent = Debug.metric("MemoryFoldedFailedNonAdjacent");
-    private static final DebugMetric MemoryFoldFailedDifferentBlock = Debug.metric("MemoryFoldedFailedDifferentBlock");
-
-    /**
-     * Subclass can provide helper to fold memory operations into other operations.
-     */
-    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
-        return null;
-    }
-
-    private static final Object LOG_OUTPUT_LOCK = new Object();
-
-    /**
-     * Try to find a sequence of Nodes which can be passed to the backend to look for optimized
-     * instruction sequences using memory. Currently this basically is a read with a single
-     * arithmetic user followed by an possible if use. This should generalized to more generic
-     * pattern matching so that it can be more flexibly used.
-     */
-    private int maybeFoldMemory(List<ScheduledNode> nodes, int i, ValueNode access) {
-        MemoryArithmeticLIRLowerer lowerer = getMemoryLowerer();
-        if (lowerer != null && GraalOptions.OptFoldMemory.getValue() && (access instanceof ReadNode || access instanceof FloatingReadNode) && access.usages().count() == 1 && i + 1 < nodes.size()) {
-            try (Scope s = Debug.scope("MaybeFoldMemory", access)) {
-                // This is all bit hacky since it's happening on the linearized schedule. This needs
-                // to be revisited at some point.
-
-                // Uncast the memory operation.
-                Node use = access.usages().first();
-                if (use instanceof UnsafeCastNode && use.usages().count() == 1) {
-                    use = use.usages().first();
+    protected void matchComplexExpressions(List<ScheduledNode> nodes) {
+        if (matchRules != null) {
+            try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                if (LogVerbose.getValue()) {
+                    int i = 0;
+                    for (ScheduledNode node : nodes) {
+                        Debug.log("%d: (%s) %1S", i++, node.usages().count(), node);
+                    }
                 }
 
-                // Find a memory lowerable usage of this operation
-                if (use instanceof MemoryArithmeticLIRLowerable) {
-                    ValueNode operation = (ValueNode) use;
-                    if (!nodes.contains(operation)) {
-                        Debug.log("node %1s in different block from %1s", access, operation);
-                        MemoryFoldFailedDifferentBlock.increment();
-                        return 0;
+                // Match the nodes in backwards order to encourage longer matches.
+                for (int index = nodes.size() - 1; index >= 0; index--) {
+                    ScheduledNode snode = nodes.get(index);
+                    if (!(snode instanceof ValueNode)) {
+                        continue;
                     }
-                    ValueNode firstOperation = operation;
-                    if (operation instanceof LogicNode) {
-                        if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) {
-                            ValueNode ifNode = (ValueNode) operation.usages().first();
-                            if (!nodes.contains(ifNode)) {
-                                MemoryFoldFailedDifferentBlock.increment();
-                                Debug.log("if node %1s in different block from %1s", ifNode, operation);
-                                try (Indent indent = Debug.logAndIndent("checking operations")) {
-                                    int start = nodes.indexOf(access);
-                                    int end = nodes.indexOf(operation);
-                                    for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
-                                        Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
-                                    }
-                                }
-                                return 0;
-                            } else {
-                                operation = ifNode;
-                            }
-                        }
+                    ValueNode node = (ValueNode) snode;
+                    if (getOperand(node) != null) {
+                        continue;
                     }
-                    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));
-                                }
+                    // See if this node is the root of any MatchStatements
+                    List<MatchStatement> statements = matchRules.get(node.getClass());
+                    if (statements != null) {
+                        for (MatchStatement statement : statements) {
+                            if (statement.generate(this, index, node, nodes)) {
+                                // Found a match so skip to the next
+                                break;
                             }
                         }
                     }
-                    // Possible lowerable operation in the same block. Check out the dependencies.
-                    int opIndex = nodes.indexOf(operation);
-                    int current = i + 1;
-                    ArrayList<ValueNode> deferred = null;
-                    for (; current < opIndex; current++) {
-                        ScheduledNode node = nodes.get(current);
-                        if (node != firstOperation) {
-                            if (node instanceof LocationNode || node instanceof VirtualObjectNode) {
-                                // nothing to do
-                                continue;
-                            } else if (node instanceof ConstantNode) {
-                                if (deferred == null) {
-                                    deferred = new ArrayList<>(2);
-                                }
-                                // These nodes are collected and the backend is expended to
-                                // evaluate them before generating the lowered form. This
-                                // basically works around unfriendly scheduling of values which
-                                // are defined in a block but not used there.
-                                deferred.add((ValueNode) node);
-                                continue;
-                            } else if (node instanceof UnsafeCastNode) {
-                                UnsafeCastNode cast = (UnsafeCastNode) node;
-                                if (cast.getOriginalNode() == access) {
-                                    continue;
-                                }
-                            }
-
-                            // Unexpected inline node
-                            // Debug.log("unexpected node %1s", node);
-                            break;
-                        }
-                    }
-
-                    if (current == opIndex) {
-                        if (lowerer.memoryPeephole((Access) access, (MemoryArithmeticLIRLowerable) operation, deferred)) {
-                            MemoryFoldSuccess.increment();
-                            // if this operation had multiple access inputs, then previous attempts
-                            // would be marked as failures which is wrong. Try to adjust the
-                            // counters to account for this.
-                            for (Node input : operation.inputs()) {
-                                if (input == access) {
-                                    continue;
-                                }
-                                if (input instanceof Access && nodes.contains(input)) {
-                                    MemoryFoldFailedNonAdjacent.add(-1);
-                                }
-                            }
-                            if (deferred != null) {
-                                // Ensure deferred nodes were evaluated
-                                for (ValueNode node : deferred) {
-                                    assert hasOperand(node);
-                                }
-                            }
-                            return opIndex - i;
-                        } else {
-                            // This isn't true failure, it just means there wasn't match for the
-                            // pattern. Usually that means it's just not supported by the backend.
-                            MemoryFoldFailed.increment();
-                            return 0;
-                        }
-                    } else {
-                        MemoryFoldFailedNonAdjacent.increment();
-                    }
-                } else if (!(use instanceof Access) && !(use instanceof PhiNode) && use.usages().count() == 1) {
-                    // memory usage which isn't considered lowerable. Mostly these are
-                    // uninteresting but it might be worth looking at to ensure that interesting
-                    // nodes are being properly handled.
-                    // Debug.log("usage isn't lowerable %1s", access.usages().first());
                 }
             }
         }
-        return 0;
     }
 
     protected abstract boolean peephole(ValueNode valueNode);
 
     private void doRoot(ValueNode instr) {
-        if (gen.traceLevel >= 2) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 2) {
             TTY.println("Emitting LIR for instruction " + instr);
         }
         currentInstruction = instr;
@@ -408,11 +354,7 @@
         if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) {
             Debug.log("This node has invalid type, we are emitting dead code(?): %s", node);
         }
-        if (node instanceof LIRGenLowerable) {
-            ((LIRGenLowerable) node).generate(this);
-        } else if (node instanceof LIRGenResLowerable) {
-            ((LIRGenResLowerable) node).generate(this, gen.getResult());
-        } else if (node instanceof LIRLowerable) {
+        if (node instanceof LIRLowerable) {
             ((LIRLowerable) node).generate(this);
         } else if (node instanceof ArithmeticLIRLowerable) {
             ((ArithmeticLIRLowerable) node).generate(this, gen);
@@ -461,7 +403,7 @@
     }
 
     private void moveToPhi(MergeNode merge, AbstractEndNode pred) {
-        if (gen.traceLevel >= 1) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
             TTY.println("MOVE TO PHI from " + pred + " to " + merge);
         }
         PhiResolver resolver = new PhiResolver(gen);
@@ -569,7 +511,7 @@
         if (x instanceof InvokeWithExceptionNode) {
             exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge());
         }
-        LIRFrameState callState = gen.stateWithExceptionEdge(x, exceptionEdge);
+        LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge);
 
         Value result = invokeCc.getReturn();
         if (callTarget instanceof DirectCallTargetNode) {
@@ -662,6 +604,45 @@
         return debugInfoBuilder;
     }
 
+    private static FrameState getFrameState(DeoptimizingNode deopt) {
+        if (deopt instanceof DeoptimizingNode.DeoptBefore) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore();
+        } else if (deopt instanceof DeoptimizingNode.DeoptDuring) {
+            assert !(deopt instanceof DeoptimizingNode.DeoptAfter);
+            return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring();
+        } else {
+            assert deopt instanceof DeoptimizingNode.DeoptAfter;
+            return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter();
+        }
+    }
+
+    public LIRFrameState state(DeoptimizingNode deopt) {
+        if (!deopt.canDeoptimize()) {
+            return null;
+        }
+        return stateFor(getFrameState(deopt));
+    }
+
+    public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) {
+        if (!deopt.canDeoptimize()) {
+            return null;
+        }
+        return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge);
+    }
+
+    public LIRFrameState stateFor(FrameState state) {
+        return stateForWithExceptionEdge(state, null);
+    }
+
+    public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) {
+        if (gen.needOnlyOopMaps()) {
+            return new LIRFrameState(null, null, null);
+        }
+        assert state != null;
+        return getDebugInfoBuilder().build(state, exceptionEdge);
+    }
+
     public void emitOverflowCheckBranch(BeginNode overflowSuccessor, BeginNode next, double probability) {
         gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), probability);
     }
@@ -687,11 +668,7 @@
     }
 
     @Override
-    public LIRGenerator getLIRGeneratorTool() {
-        return gen;
-    }
-
-    public LIRGenerator getLIRGenerator() {
+    public LIRGeneratorTool getLIRGeneratorTool() {
         return gen;
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri May 30 15:09:09 2014 +0200
@@ -29,22 +29,23 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * Converts {@link ValuePhiNode} instructions into moves.
- * 
+ *
  * Resolves cycles:
- * 
+ *
  * <pre>
- * 
+ *
  *  r1 := r2  becomes  temp := r1
  *  r2 := r1           r1 := r2
  *                     r2 := temp
  * </pre>
- * 
+ *
  * and orders moves:
- * 
+ *
  * <pre>
  *  r2 := r3  becomes  r1 := r2
  *  r1 := r2           r2 := r3
@@ -103,7 +104,7 @@
         }
     }
 
-    private final LIRGenerator gen;
+    private final LIRGeneratorTool gen;
 
     /**
      * The operand loop header phi for the operand currently being process in {@link #dispose()}.
@@ -120,7 +121,7 @@
      */
     private final HashMap<Value, PhiResolverNode> operandToNodeMap = new HashMap<>();
 
-    public PhiResolver(LIRGenerator gen) {
+    public PhiResolver(LIRGeneratorTool gen) {
         this.gen = gen;
         temp = ILLEGAL;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * A closure that can be evaluated to produce the LIR for some complex match. Using a closure allows
+ * normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes evaluated at
+ * the proper time.
+ */
+public interface ComplexMatchResult {
+    Value evaluate(NodeLIRBuilder gen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * A wrapper value for the lazy evaluation of a complex match. There's an intermediate class for the
+ * closure because Value is serializable which is a hassle for the little inner classes which
+ * usually occur here.
+ */
+public class ComplexMatchValue extends Value {
+    private static final long serialVersionUID = -4734670273590368770L;
+
+    /**
+     * This is the Value of a node which was matched as part of a complex match. The value isn't
+     * actually useable but this marks it as having been evaluated.
+     */
+    @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) {
+
+        @Override
+        public String toString() {
+            return "INTERIOR_MATCH";
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            // This class is a singleton
+            return other != null && getClass() == other.getClass();
+        }
+    };
+
+    final ComplexMatchResult result;
+
+    public ComplexMatchValue(ComplexMatchResult result) {
+        super(Kind.Illegal);
+        this.result = result;
+    }
+
+    public Value evaluate(NodeLIRBuilder builder) {
+        return result.evaluate(builder);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.virtual.*;
+
+/**
+ * Container for state captured during a match.
+ */
+public class MatchContext {
+
+    private final ValueNode root;
+
+    private final List<ScheduledNode> nodes;
+
+    private final MatchStatement rule;
+
+    private Map<String, NamedNode> namedNodes;
+
+    private ArrayList<ValueNode> consumed;
+
+    private int startIndex;
+
+    private int endIndex;
+
+    private final NodeLIRBuilder builder;
+
+    private static class NamedNode {
+        final Class<? extends ValueNode> type;
+        final ValueNode value;
+
+        NamedNode(Class<? extends ValueNode> type, ValueNode value) {
+            this.type = type;
+            this.value = value;
+        }
+    }
+
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List<ScheduledNode> nodes) {
+        this.builder = builder;
+        this.rule = rule;
+        this.root = node;
+        this.nodes = nodes;
+        assert index == nodes.indexOf(node);
+        // The root should be the last index since all the inputs must be scheduled before it.
+        startIndex = endIndex = index;
+    }
+
+    public ValueNode getRoot() {
+        return root;
+    }
+
+    public Result captureNamedValue(String name, Class<? extends ValueNode> type, ValueNode value) {
+        if (namedNodes == null) {
+            namedNodes = new HashMap<>(2);
+        }
+        NamedNode current = namedNodes.get(name);
+        if (current == null) {
+            current = new NamedNode(type, value);
+            namedNodes.put(name, current);
+            return Result.OK;
+        } else {
+            if (current.value != value || current.type != type) {
+                return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern());
+            }
+            return Result.OK;
+        }
+    }
+
+    public Result validate() {
+        // Ensure that there's no unsafe work in between these operations.
+        for (int i = startIndex; i <= endIndex; i++) {
+            ScheduledNode node = nodes.get(i);
+            if (node instanceof VirtualObjectNode || node instanceof FloatingNode) {
+                // The order of evaluation of these nodes controlled by data dependence so they
+                // don't interfere with this match.
+                continue;
+            } else if ((consumed == null || !consumed.contains(node)) && node != root) {
+                if (LogVerbose.getValue()) {
+                    Debug.log("unexpected node %s", node);
+                    for (int j = startIndex; j <= endIndex; j++) {
+                        ScheduledNode theNode = nodes.get(j);
+                        Debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode);
+                    }
+                }
+                return Result.NOT_SAFE(node, rule.getPattern());
+            }
+        }
+        return Result.OK;
+    }
+
+    /**
+     * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result.
+     * During final LIR generation it will be evaluated to produce the actual LIR value.
+     *
+     * @param result
+     */
+    public void setResult(ComplexMatchResult result) {
+        ComplexMatchValue value = new ComplexMatchValue(result);
+        Debug.log("matched %s %s", rule.getName(), rule.getPattern());
+        Debug.log("with nodes %s", rule.formatMatch(root));
+        if (consumed != null) {
+            for (ValueNode node : consumed) {
+                // All the interior nodes should be skipped during the normal doRoot calls in
+                // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
+                // closure which will be evaluated to produce the final LIR.
+                builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH);
+            }
+        }
+        builder.setMatchResult(root, value);
+    }
+
+    /**
+     * Mark a node as consumed by the match. Consumed nodes will never be evaluated.
+     *
+     * @return Result.OK if the node can be safely consumed.
+     */
+    public Result consume(ValueNode node) {
+        assert node.usages().count() <= 1 : "should have already been checked";
+
+        // Check NOT_IN_BLOCK first since that usually implies ALREADY_USED
+        int index = nodes.indexOf(node);
+        if (index == -1) {
+            return Result.NOT_IN_BLOCK(node, rule.getPattern());
+        }
+
+        if (builder.hasOperand(node)) {
+            return Result.ALREADY_USED(node, rule.getPattern());
+        }
+
+        startIndex = Math.min(startIndex, index);
+        if (consumed == null) {
+            consumed = new ArrayList<>(2);
+        }
+        consumed.add(node);
+        return Result.OK;
+    }
+
+    /**
+     * Return the named node. It's an error if the
+     *
+     * @param name the name of a node in the match rule
+     * @return the matched node
+     * @throws GraalInternalError is the named node doesn't exist.
+     */
+    public ValueNode namedNode(String name) {
+        if (namedNodes != null) {
+            NamedNode value = namedNodes.get(name);
+            if (value != null) {
+                return value.value;
+            }
+        }
+        throw new GraalInternalError("missing node %s", name);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : "");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * Code generator for complex match patterns.
+ */
+public interface MatchGenerator {
+    /**
+     * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be
+     *          evaluated during LIR generation to produce the final LIR value.
+     */
+    ComplexMatchResult match(NodeLIRBuilder gen, Object... args);
+
+    /**
+     * @return a descriptive name meaningful to the user.
+     */
+    String getName();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A simple recursive pattern matcher for a DAG of nodes.
+ */
+
+public class MatchPattern {
+
+    enum MatchResultCode {
+        OK,
+        WRONG_CLASS,
+        NAMED_VALUE_MISMATCH,
+        TOO_MANY_USERS,
+        NOT_IN_BLOCK,
+        NOT_SAFE,
+        ALREADY_USED,
+    }
+
+    /**
+     * A descriptive result for match failures. This can be helpful for debugging why a match
+     * doesn't work as expected.
+     */
+    static class Result {
+        final MatchResultCode code;
+
+        final ScheduledNode node;
+
+        final MatchPattern matcher;
+
+        Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) {
+            this.code = result;
+            this.node = node;
+            this.matcher = matcher;
+        }
+
+        private static final DebugMetric MatchResult_WRONG_CLASS = Debug.metric("MatchResult_WRONG_CLASS");
+        private static final DebugMetric MatchResult_NAMED_VALUE_MISMATCH = Debug.metric("MatchResult_NAMED_VALUE_MISMATCH");
+        private static final DebugMetric MatchResult_TOO_MANY_USERS = Debug.metric("MatchResult_TOO_MANY_USERS");
+        private static final DebugMetric MatchResult_NOT_IN_BLOCK = Debug.metric("MatchResult_NOT_IN_BLOCK");
+        private static final DebugMetric MatchResult_NOT_SAFE = Debug.metric("MatchResult_NOT_SAFE");
+        private static final DebugMetric MatchResult_ALREADY_USED = Debug.metric("MatchResult_ALREADY_USED");
+
+        static final Result OK = new Result(MatchResultCode.OK, null, null);
+
+        static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) {
+            MatchResult_WRONG_CLASS.increment();
+            return new Result(MatchResultCode.WRONG_CLASS, node, matcher);
+        }
+
+        static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) {
+            MatchResult_NAMED_VALUE_MISMATCH.increment();
+            return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher);
+        }
+
+        static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) {
+            MatchResult_TOO_MANY_USERS.increment();
+            return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher);
+        }
+
+        static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) {
+            MatchResult_NOT_IN_BLOCK.increment();
+            return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher);
+        }
+
+        static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) {
+            MatchResult_NOT_SAFE.increment();
+            return new Result(MatchResultCode.NOT_SAFE, node, matcher);
+        }
+
+        static Result ALREADY_USED(ValueNode node, MatchPattern matcher) {
+            MatchResult_ALREADY_USED.increment();
+            return new Result(MatchResultCode.ALREADY_USED, node, matcher);
+        }
+
+        @Override
+        public String toString() {
+            if (code == MatchResultCode.OK) {
+                return "OK";
+            }
+            return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
+        }
+    }
+
+    /**
+     * The expected type of the node. It must match exactly.
+     */
+    private final Class<? extends ValueNode> nodeClass;
+
+    /**
+     * An optional name for this node. A name can occur multiple times in a match and that name must
+     * always refer to the same node of the match will fail.
+     */
+    private final String name;
+
+    /**
+     * Patterns to match the inputs.
+     */
+    private final MatchPattern[] patterns;
+
+    /**
+     * The inputs to match the patterns against.
+     */
+    private final NodeClass.Position[] inputs;
+
+    /**
+     * Can there only be one user of the node. Constant nodes can be matched even if there are other
+     * users.
+     */
+    private final boolean singleUser;
+
+    private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
+
+    public MatchPattern(String name, boolean singleUser) {
+        this(null, name, singleUser);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) {
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.patterns = EMPTY_PATTERNS;
+        this.inputs = null;
+    }
+
+    private MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, NodeClass.Position[] inputs) {
+        assert inputs == null || inputs.length == patterns.length;
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.patterns = patterns;
+        this.inputs = inputs;
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, NodeClass.Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, NodeClass.Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, NodeClass.Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs);
+    }
+
+    Class<? extends ValueNode> nodeClass() {
+        return nodeClass;
+    }
+
+    private Result matchType(ValueNode node) {
+        if (nodeClass != null && node.getClass() != nodeClass) {
+            return Result.WRONG_CLASS(node, this);
+        }
+        return Result.OK;
+    }
+
+    /**
+     * Match any named nodes and ensure that the consumed nodes can be safely merged.
+     *
+     * @param node
+     * @param context
+     * @return Result.OK is the pattern can be safely matched.
+     */
+    Result matchUsage(ValueNode node, MatchContext context) {
+        Result result = matchUsage(node, context, true);
+        if (result == Result.OK) {
+            result = context.validate();
+        }
+        return result;
+    }
+
+    private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
+        }
+        if (singleUser && !atRoot) {
+            result = context.consume(node);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        if (name != null) {
+            result = context.captureNamedValue(name, nodeClass, node);
+        }
+
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchUsage(getInput(input, node), context, false);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Recursively match the shape of the tree without worry about named values. Most matches fail
+     * at this point so it's performed first.
+     *
+     * @param node
+     * @param statement
+     * @return Result.OK if the shape of the pattern matches.
+     */
+    public Result matchShape(ValueNode node, MatchStatement statement) {
+        return matchShape(node, statement, true);
+    }
+
+    private Result matchShape(ValueNode node, MatchStatement statement, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
+        }
+
+        if (singleUser && !atRoot) {
+            if (node.usages().count() > 1) {
+                return Result.TOO_MANY_USERS(node, statement.getPattern());
+            }
+        }
+
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchShape(getInput(input, node), statement, false);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * For a node starting at root, produce a String showing the inputs that matched against this
+     * rule. It's assumed that a match has already succeeded against this rule, otherwise the
+     * printing may produce exceptions.
+     */
+    public String formatMatch(ValueNode root) {
+        String result = String.format("%s", root);
+        if (patterns.length == 0) {
+            return result;
+        } else {
+            StringBuilder sb = new StringBuilder();
+            sb.append("(");
+            sb.append(result);
+            for (int input = 0; input < patterns.length; input++) {
+                sb.append(" ");
+                sb.append(patterns[input].formatMatch(getInput(input, root)));
+            }
+            sb.append(")");
+            return sb.toString();
+        }
+    }
+
+    private ValueNode getInput(int index, ValueNode node) {
+        return (ValueNode) inputs[index].get(node);
+    }
+
+    @Override
+    public String toString() {
+        if (nodeClass == null) {
+            return name;
+        } else {
+            String nodeName = nodeClass.getSimpleName();
+            nodeName = nodeName.substring(0, nodeName.length() - 4);
+            if (patterns.length == 0) {
+                return nodeName + (name != null ? "=" + name : "");
+            } else {
+                StringBuilder sb = new StringBuilder();
+                sb.append("(");
+                sb.append(nodeName);
+                for (int index = 0; index < patterns.length; index++) {
+                    sb.append(" ");
+                    sb.append(patterns[index].toString());
+                }
+                sb.append(")");
+                return sb.toString();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,1073 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.lang.model.util.*;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
+ * generated for each top level class containing at least one such field. These service objects can
+ * be retrieved as follows:
+ *
+ * <pre>
+ *     Iterable<MatchStatementSet> sl = Services.load(MatchStatementSet.class);
+ *     for (MatchStatementSet rules : sl) {
+ *         ...
+ *     }
+ * </pre>
+ */
+@SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode",
+                "com.oracle.graal.compiler.match.MatchableNodes"})
+public class MatchProcessor extends AbstractProcessor {
+
+    public MatchProcessor() {
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private final Set<Element> processedMatchRule = new HashSet<>();
+    private final Set<Element> processedMatchableNode = new HashSet<>();
+
+    private static class RuleParseError extends RuntimeException {
+        private static final long serialVersionUID = 6456128283609257490L;
+
+        RuleParseError(String format, Object... args) {
+            super(String.format(format, args));
+        }
+    }
+
+    private static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+
+    private class RuleParser {
+        private ArrayList<TypeDescriptor> capturedTypes = new ArrayList<>();
+
+        private ArrayList<String> capturedNames = new ArrayList<>();
+
+        private final String[] tokens;
+
+        private int current;
+
+        private MatchDescriptor matchDescriptor;
+
+        private final Set<Element> originatingElements = new HashSet<>();
+
+        RuleParser(String rule) {
+            Matcher m = tokenizer.matcher(rule);
+            List<String> list = new ArrayList<>();
+            int end = 0;
+            while (m.lookingAt()) {
+                list.add(m.group(1));
+                end = m.end();
+                m.region(m.end(), m.regionEnd());
+            }
+            if (end != m.regionEnd()) {
+                throw new RuleParseError("Unexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
+            }
+            tokens = list.toArray(new String[0]);
+
+            matchDescriptor = parseExpression();
+            if (!done()) {
+                throw new RuleParseError("didn't consume all tokens");
+            }
+            capturedNames.add(0, "root");
+            capturedTypes.add(0, matchDescriptor.nodeType);
+        }
+
+        String next() {
+            return tokens[current++];
+        }
+
+        String peek(String name) {
+            if (current >= tokens.length) {
+                if (name == null) {
+                    throw new RuleParseError("Out of tokens");
+                }
+                throw new RuleParseError("Out of tokens looking for %s", name);
+            }
+            return tokens[current];
+        }
+
+        boolean done() {
+            return current == tokens.length;
+        }
+
+        private MatchDescriptor parseExpression() {
+            if (peek("(").equals("(")) {
+                next();
+                MatchDescriptor descriptor = parseType(true);
+                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+                    if (peek("(").equals("(")) {
+                        descriptor.inputs[n] = parseExpression();
+                    } else {
+                        descriptor.inputs[n] = parseType(false);
+                    }
+                }
+                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+                    if (descriptor.inputs[n] == null) {
+                        throw new RuleParseError("not enough inputs for " + descriptor.name);
+                    }
+                }
+                if (peek(")").equals(")")) {
+                    next();
+                    return descriptor;
+                }
+                throw new RuleParseError("Too many arguments to " + descriptor.nodeType.nodeClass);
+            }
+            throw new RuleParseError("Extra tokens following match pattern: " + peek(null));
+        }
+
+        private MatchDescriptor parseType(boolean forExpression) {
+            TypeDescriptor type = null;
+            String name = null;
+            if (Character.isUpperCase(peek("node type or name").charAt(0))) {
+                String token = next();
+                type = knownTypes.get(token);
+                if (type == null) {
+                    throw new RuleParseError("Unknown node type: " + token);
+                }
+                if (peek("=").equals("=")) {
+                    next();
+                    name = next();
+                }
+                originatingElements.addAll(type.originatingElements);
+            } else if (Character.isLowerCase(peek("name").charAt(0))) {
+                name = next();
+                type = valueType;
+            } else {
+                throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null));
+            }
+            if (name != null) {
+                if (!capturedNames.contains(name)) {
+                    capturedNames.add(name);
+                    capturedTypes.add(type);
+                } else {
+                    int index = capturedNames.indexOf(name);
+                    if (capturedTypes.get(index) != type) {
+                        throw new RuleParseError("Captured node \"%s\" has differing types", name);
+                    }
+                }
+            }
+            return new MatchDescriptor(type, name, forExpression);
+        }
+
+        List<String> generateVariants() {
+            return matchDescriptor.generateVariants();
+        }
+
+        /**
+         * Recursively accumulate any required NodeClass.Position declarations.
+         */
+        void generatePositionDeclarations(Set<String> declarations) {
+            matchDescriptor.generatePositionDeclarations(declarations);
+        }
+
+        /**
+         *
+         * @return the list of node types which are captured by name
+         */
+        public ArrayList<TypeDescriptor> capturedTypes() {
+            return capturedTypes;
+        }
+
+        public ArrayList<String> capturedNames() {
+            return capturedNames;
+        }
+    }
+
+    /**
+     * Set to true to enable logging to a local file during annotation processing. There's no normal
+     * channel for any debug messages and debugging annotation processors requires some special
+     * setup.
+     */
+    private static final boolean DEBUG = false;
+
+    private static final String LOGFILE = new File(System.getProperty("java.io.tmpdir"), "matchprocessor.log").getPath();
+
+    private static PrintWriter log;
+
+    /**
+     * Logging facility for the debugging the annotation processor.
+     */
+
+    private static synchronized PrintWriter getLog() {
+        if (log == null) {
+            try {
+                log = new PrintWriter(new FileWriter(LOGFILE, true));
+            } catch (IOException e) {
+                // Do nothing
+            }
+        }
+        return log;
+    }
+
+    private static synchronized void logMessage(String format, Object... args) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            bw.printf(format, args);
+            bw.flush();
+        }
+    }
+
+    private static synchronized void logException(Throwable t) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            t.printStackTrace(bw);
+            bw.flush();
+        }
+    }
+
+    /**
+     * Bugs in an annotation processor can cause silent failure so try to report any exception
+     * throws as errors.
+     */
+    private void reportExceptionThrow(Element element, Throwable t) {
+        logMessage("throw for %s:\n", element);
+        logException(t);
+        processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)), element);
+    }
+
+    static class TypeDescriptor {
+        final TypeMirror mirror;
+
+        /**
+         * The name uses in match expressions to refer to this type.
+         */
+        final String shortName;
+
+        /**
+         * The simple name of the {@link ValueNode} class represented by this type.
+         */
+        final String nodeClass;
+
+        /**
+         * The package of {@link ValueNode} class represented by this type.
+         */
+        final String nodePackage;
+
+        /**
+         * The matchable inputs of the node.
+         */
+        final String[] inputs;
+
+        /**
+         * Should swapped variants of this match be generated. The user of the match is expected to
+         * compensate for any ordering differences in compare which are commutative but require
+         * reinterpreting the condition in that case.
+         */
+        final boolean commutative;
+
+        /**
+         * Can multiple users of this node subsume it. Constants can be swallowed into a match even
+         * if there are multiple users.
+         */
+        final boolean shareable;
+
+        final Set<Element> originatingElements = new HashSet<>();
+
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable) {
+            this.mirror = mirror;
+            this.shortName = shortName;
+            this.nodeClass = nodeClass;
+            this.nodePackage = nodePackage;
+            this.inputs = inputs;
+            this.commutative = commutative;
+            this.shareable = shareable;
+            assert !commutative || inputs.length == 2;
+        }
+    }
+
+    /**
+     * The types which are know for purpose of parsing MatchRule expressions.
+     */
+    Map<String, TypeDescriptor> knownTypes = new HashMap<>();
+
+    /**
+     * The set of packages which must be imported to refer to the known classes.
+     */
+    List<String> requiredPackages = new ArrayList<>();
+
+    /**
+     * The mapping between elements with MatchRules and the wrapper class used invoke the code
+     * generation after the match.
+     */
+    private Map<ExecutableElement, MethodInvokerItem> invokers = new LinkedHashMap<>();
+
+    private TypeDescriptor valueType;
+
+    private TypeMirror matchRulesTypeMirror;
+
+    private TypeMirror matchRuleTypeMirror;
+
+    private TypeMirror matchableNodeTypeMirror;
+
+    private TypeMirror matchableNodesTypeMirror;
+
+    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable, Element element) {
+        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable);
+        descriptor.originatingElements.add(element);
+        knownTypes.put(shortName, descriptor);
+        if (!requiredPackages.contains(descriptor.nodePackage)) {
+            requiredPackages.add(descriptor.nodePackage);
+        }
+    }
+
+    private String findPackage(Element type) {
+        PackageElement p = processingEnv.getElementUtils().getPackageOf(type);
+        if (p != null) {
+            return p.getQualifiedName().toString();
+        }
+        throw new GraalInternalError("can't find package for %s", type);
+    }
+
+    class MatchDescriptor {
+        TypeDescriptor nodeType;
+        String name;
+        MatchDescriptor[] inputs;
+
+        MatchDescriptor(TypeDescriptor nodeType, String name, boolean forExpression) {
+            this.nodeType = nodeType;
+            this.name = name;
+            if (forExpression) {
+                this.inputs = new MatchDescriptor[nodeType.inputs.length];
+            } else {
+                this.inputs = new MatchDescriptor[0];
+            }
+        }
+
+        public void generatePositionDeclarations(Set<String> declarations) {
+            if (inputs.length == 0) {
+                return;
+            }
+            declarations.add(generatePositionDeclaration());
+            for (MatchDescriptor desc : inputs) {
+                desc.generatePositionDeclarations(declarations);
+            }
+        }
+
+        List<String> recurseVariants(int index) {
+            if (inputs.length == 0) {
+                return new ArrayList<>();
+            }
+            List<String> currentVariants = inputs[index].generateVariants();
+            if (index == inputs.length - 1) {
+                return currentVariants;
+            }
+            List<String> subVariants = recurseVariants(index + 1);
+            List<String> result = new ArrayList<>();
+            for (String current : currentVariants) {
+                for (String sub : subVariants) {
+                    result.add(current + ", " + sub);
+                    if (nodeType.commutative) {
+                        result.add(sub + ", " + current);
+                    }
+                }
+            }
+            return result;
+        }
+
+        /**
+         * Recursively generate all the variants of this rule pattern. Currently that just means to
+         * swap the inputs for commutative rules, producing all possible permutations.
+         *
+         * @return a list of Strings which will construct pattern matchers for this rule.
+         */
+        List<String> generateVariants() {
+            String prefix = formatPrefix();
+            String suffix = formatSuffix();
+            ArrayList<String> variants = new ArrayList<>();
+            if (inputs.length > 0) {
+                for (String var : recurseVariants(0)) {
+                    variants.add(prefix + ", " + var + suffix);
+                }
+            } else {
+                assert inputs.length == 0;
+                variants.add(prefix + suffix);
+            }
+
+            return variants;
+        }
+
+        private String formatPrefix() {
+            if (nodeType == valueType) {
+                return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null");
+            } else {
+                return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null");
+            }
+        }
+
+        private String formatSuffix() {
+            if (nodeType != null) {
+                if (inputs.length != nodeType.inputs.length) {
+                    return ", true)";
+                } else {
+                    if (nodeType.inputs.length > 0) {
+                        return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ")";
+                    }
+                    if (nodeType.shareable) {
+                        return ", false)";
+                    }
+                }
+            }
+            return ")";
+        }
+
+        String generatePositionDeclaration() {
+            return String.format("NodeClass.Position[] %s_positions = MatchRuleRegistry.findPositions(lookup, %s.class, new String[]{\"%s\"});", nodeType.nodeClass, nodeType.nodeClass,
+                            String.join("\", \"", nodeType.inputs));
+        }
+    }
+
+    /**
+     * Strip the package off a class name leaving the full class name including any outer classes.
+     */
+    private String fullClassName(Element element) {
+        assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE : element;
+        String pkg = findPackage(element);
+        return ((TypeElement) element).getQualifiedName().toString().substring(pkg.length() + 1);
+    }
+
+    private void createFiles(MatchRuleDescriptor info) {
+        String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
+        Name topDeclaringClass = info.topDeclaringType.getSimpleName();
+
+        String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
+        Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
+
+        Types typeUtils = typeUtils();
+        Filer filer = processingEnv.getFiler();
+        try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) {
+
+            out.println("// CheckStyle: stop header check");
+            out.println("// GENERATED CONTENT - DO NOT EDIT");
+            out.println("// Source: " + topDeclaringClass + ".java");
+            out.println("package " + pkg + ";");
+            out.println("");
+            out.println("import java.util.*;");
+            out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
+            out.println("import " + NodeLIRBuilder.class.getName() + ";");
+            out.println("import " + NodeClass.class.getName() + ";");
+            for (String p : requiredPackages) {
+                out.println("import " + p + ".*;");
+            }
+            out.println("");
+            out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+
+            out.println();
+
+            // Generate declarations for the wrapper class to invoke the code generation methods.
+            for (MethodInvokerItem invoker : invokers.values()) {
+                StringBuilder args = new StringBuilder();
+                StringBuilder types = new StringBuilder();
+                int count = invoker.fields.size();
+                int index = 0;
+                for (VariableElement arg : invoker.fields) {
+                    args.append('"');
+                    args.append(arg.getSimpleName());
+                    args.append('"');
+                    types.append(String.format("(%s) args[%s]", fullClassName(typeUtils.asElement(arg.asType())), index++));
+                    if (count-- > 1) {
+                        args.append(", ");
+                        types.append(", ");
+                    }
+                }
+                out.printf("    private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
+                out.printf("    private static final class %s implements MatchGenerator {\n", invoker.wrapperClass());
+                out.printf("        static MatchGenerator instance = new %s();\n", invoker.wrapperClass());
+                out.printf("        public ComplexMatchResult match(NodeLIRBuilder builder, Object...args) {\n");
+                out.printf("            return ((%s) builder).%s(%s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);
+                out.printf("        }\n");
+                out.printf("        public String getName() {\n");
+                out.printf("             return \"%s\";\n", invoker.methodName);
+                out.printf("        }\n");
+                out.printf("    }\n");
+                out.println();
+
+            }
+
+            String desc = MatchStatement.class.getSimpleName();
+
+            out.println("    public Class<? extends NodeLIRBuilder> forClass() {");
+            out.println("        return " + topDeclaringClass + ".class;");
+            out.println("    }");
+            out.println();
+            out.println("    @Override");
+            out.println("    public List<" + desc + "> statements(MatchRuleRegistry.NodeClassLookup lookup) {");
+
+            for (String positionDeclaration : info.positionDeclarations) {
+                out.println("        " + positionDeclaration);
+            }
+            out.println();
+
+            out.println("        // CheckStyle: stop line length check");
+            out.println("        List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList(");
+
+            int i = 0;
+            for (MatchRuleItem matchRule : info.matchRules) {
+                String comma = i == info.matchRules.size() - 1 ? "" : ",";
+                out.printf("            %s%s\n", matchRule.ruleBuilder(), comma);
+                i++;
+            }
+            out.println("        ));");
+            out.println("        // CheckStyle: resume line length check");
+            out.println("        return statements;");
+            out.println("    }");
+
+            out.println();
+
+            out.println("}");
+        }
+
+        try {
+            createProviderFile(pkg, matchStatementClassName, originatingElements);
+        } catch (IOException e) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType);
+        }
+    }
+
+    private void createProviderFile(String pkg, String providerClassName, Element... originatingElements) throws IOException {
+        String filename = "META-INF/providers/" + pkg + "." + providerClassName;
+        FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements);
+        PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
+        writer.println(MatchStatementSet.class.getName());
+        writer.close();
+    }
+
+    protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+        try {
+            // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle
+            JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements);
+            return new PrintWriter(sourceFile.openWriter()) {
+
+                @Override
+                public void println() {
+                    print("\n");
+                }
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Used to generate the MatchStatement constructor invocation.
+     */
+    static class MatchRuleItem {
+        private final String matchPattern;
+        private final MethodInvokerItem invoker;
+
+        public MatchRuleItem(String matchPattern, MethodInvokerItem invoker) {
+            this.matchPattern = matchPattern;
+            this.invoker = invoker;
+        }
+
+        /**
+         * @return a string which will construct the MatchStatement instance to match this pattern.
+         */
+        public String ruleBuilder() {
+            return String.format("new MatchStatement(\"%s\", %s, %s.instance, %s)", invoker.name, matchPattern, invoker.wrapperClass(), invoker.argumentsListName());
+        }
+    }
+
+    /**
+     * Used to generate the wrapper class to invoke the code generation method.
+     */
+    static class MethodInvokerItem {
+        final String name;
+        final String nodeLIRBuilderClass;
+        final String methodName;
+        final List<? extends VariableElement> fields;
+
+        MethodInvokerItem(String name, String nodeLIRBuilderClass, String methodName, List<? extends VariableElement> fields) {
+            this.name = name;
+            this.nodeLIRBuilderClass = nodeLIRBuilderClass;
+            this.methodName = methodName;
+            this.fields = fields;
+        }
+
+        String wrapperClass() {
+            return "MatchGenerator_" + methodName;
+        }
+
+        String argumentsListName() {
+            return methodName + "_arguments";
+        }
+    }
+
+    static class MatchRuleDescriptor {
+
+        final TypeElement topDeclaringType;
+        final List<MatchRuleItem> matchRules = new ArrayList<>();
+        private final Set<Element> originatingElements = new HashSet<>();
+        public Set<String> positionDeclarations = new LinkedHashSet<>();
+
+        public MatchRuleDescriptor(TypeElement topDeclaringType) {
+            this.topDeclaringType = topDeclaringType;
+        }
+    }
+
+    private static TypeElement topDeclaringType(Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) {
+            assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE;
+            return (TypeElement) element;
+        }
+        return topDeclaringType(enclosing);
+    }
+
+    private AnnotationMirror findAnnotationMirror(Element element, TypeMirror typeMirror) {
+        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
+            if (typeUtils().isSameType(mirror.getAnnotationType(), typeMirror)) {
+                return mirror;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+        logMessage("Starting round %s\n", roundEnv);
+        matchRulesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRules.class.getCanonicalName()).asType();
+        matchRuleTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRule.class.getCanonicalName()).asType();
+
+        matchableNodeTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNode.class.getCanonicalName()).asType();
+        matchableNodesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNodes.class.getCanonicalName()).asType();
+
+        try {
+            // Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes
+            // table since it shouldn't be mentioned in match rules.
+            TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
+            valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false);
+
+            Map<TypeElement, MatchRuleDescriptor> map = new LinkedHashMap<>();
+
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
+                processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
+            }
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
+                processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror));
+            }
+
+            for (MatchRuleDescriptor info : map.values()) {
+                createFiles(info);
+            }
+
+        } catch (Throwable t) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)));
+        }
+
+        return true;
+    }
+
+    /**
+     * Build up the type table to be used during parsing of the MatchRule.
+     */
+    private void processMatchableNode(Element element) {
+        if (!processedMatchableNode.contains(element)) {
+            try {
+                processedMatchableNode.add(element);
+
+                AnnotationMirror mirror = findAnnotationMirror(element, matchableNodesTypeMirror);
+                if (mirror == null) {
+                    mirror = findAnnotationMirror(element, matchableNodeTypeMirror);
+                }
+                if (mirror == null) {
+                    return;
+                }
+                TypeElement topDeclaringType = topDeclaringType(element);
+                List<AnnotationMirror> mirrors = null;
+                if (typeUtils().isSameType(mirror.getAnnotationType(), matchableNodesTypeMirror)) {
+                    // Unpack the mirrors for a repeatable annotation
+                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
+                }
+                int i = 0;
+                for (MatchableNode matchableNode : element.getAnnotationsByType(MatchableNode.class)) {
+                    processMatchableNode(element, topDeclaringType, matchableNode, mirrors != null ? mirrors.get(i++) : mirror);
+                }
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
+            }
+        }
+    }
+
+    private void processMatchableNode(Element element, TypeElement topDeclaringType, MatchableNode matchable, AnnotationMirror mirror) throws GraalInternalError {
+        logMessage("processMatchableNode %s %s %s\n", topDeclaringType, element, matchable);
+        String nodeClass;
+        String nodePackage;
+        TypeMirror nodeClassMirror = null;
+        try {
+            matchable.nodeClass();
+        } catch (MirroredTypeException e) {
+            nodeClassMirror = e.getTypeMirror();
+        }
+        if (nodeClassMirror == null) {
+            throw new GraalInternalError("Can't get mirror for node class %s", element);
+        }
+        if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) {
+            nodeClass = topDeclaringType.getQualifiedName().toString();
+        } else {
+            nodeClass = nodeClassMirror.toString();
+        }
+        nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass));
+        assert nodeClass.startsWith(nodePackage);
+        nodeClass = nodeClass.substring(nodePackage.length() + 1);
+        assert nodeClass.endsWith("Node");
+        String shortName = nodeClass.substring(0, nodeClass.length() - 4);
+
+        Types typeUtils = processingEnv.getTypeUtils();
+        TypeElement nodeClassElement = (TypeElement) typeUtils.asElement(nodeClassMirror);
+        for (String input : matchable.inputs()) {
+            boolean ok = false;
+            TypeElement current = nodeClassElement;
+            while (!ok && current != null) {
+                for (Element fieldElement : ElementFilter.fieldsIn(current.getEnclosedElements())) {
+                    if (fieldElement.getSimpleName().toString().equals(input)) {
+                        ok = true;
+                        break;
+                    }
+                }
+                TypeMirror theSuper = current.getSuperclass();
+                current = (TypeElement) typeUtils.asElement(theSuper);
+            }
+            if (!ok) {
+                String msg = String.format("Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, element, mirror);
+            }
+        }
+
+        declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element);
+    }
+
+    private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
+        if (!processedMatchRule.contains(element)) {
+            try {
+                processedMatchRule.add(element);
+
+                // The annotation element type should ensure this is true.
+                assert element instanceof ExecutableElement;
+
+                findMatchableNodes(element);
+
+                TypeElement topDeclaringType = topDeclaringType(element);
+                MatchRuleDescriptor info = map.get(topDeclaringType);
+                if (info == null) {
+                    info = new MatchRuleDescriptor(topDeclaringType);
+                    map.put(topDeclaringType, info);
+                }
+                List<AnnotationMirror> mirrors = null;
+                if (typeUtils().isSameType(mirror.getAnnotationType(), matchRulesTypeMirror)) {
+                    // Unpack the mirrors for a repeatable annotation
+                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
+                }
+                int i = 0;
+                for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
+                    processMethodMatchRule((ExecutableElement) element, info, matchRule, mirrors != null ? mirrors.get(i++) : mirror);
+                }
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
+            }
+        }
+    }
+
+    /**
+     * Search the super types of element for MatchableNode definitions. Any superclass or super
+     * interface can contain definitions of matchable nodes.
+     *
+     * @param element
+     */
+    private void findMatchableNodes(Element element) {
+        processMatchableNode(element);
+        Element enclosing = element.getEnclosingElement();
+        while (enclosing != null) {
+            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                TypeElement current = (TypeElement) enclosing;
+                while (current != null) {
+                    processMatchableNode(current);
+                    for (TypeMirror intf : current.getInterfaces()) {
+                        Element interfaceElement = typeUtils().asElement(intf);
+                        processMatchableNode(interfaceElement);
+                        // Recurse
+                        findMatchableNodes(interfaceElement);
+                    }
+                    TypeMirror theSuper = current.getSuperclass();
+                    current = (TypeElement) typeUtils().asElement(theSuper);
+                }
+            }
+            enclosing = enclosing.getEnclosingElement();
+        }
+    }
+
+    private Types typeUtils() {
+        return processingEnv.getTypeUtils();
+    }
+
+    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule, AnnotationMirror mirror) {
+        logMessage("processMethodMatchRule %s %s\n", method, mirror);
+
+        Types typeUtils = typeUtils();
+
+        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
+            String msg = String.format("MatchRule method %s must be public", method.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+            return;
+        }
+        if (method.getModifiers().contains(Modifier.STATIC)) {
+            String msg = String.format("MatchRule method %s must be non-static", method.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+            return;
+        }
+
+        try {
+            TypeMirror returnType = method.getReturnType();
+            if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) {
+                String msg = String.format("MatchRule method return type must be %s", ComplexMatchResult.class.getName());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                return;
+            }
+
+            String rule = matchRule.value();
+            RuleParser parser = new RuleParser(rule);
+            ArrayList<TypeDescriptor> expectedTypes = parser.capturedTypes();
+            ArrayList<String> expectedNames = parser.capturedNames();
+            List<? extends VariableElement> actualParameters = method.getParameters();
+            if (expectedTypes.size() + 1 < actualParameters.size()) {
+                String msg = String.format("Too many arguments for match method %s %s", expectedTypes.size() + 1, actualParameters.size());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                return;
+            }
+
+            // Walk through the parameters to the method and see if they exist in the match rule.
+            // The order doesn't matter but only names mentioned in the rule can be used and they
+            // must be assignment compatible.
+            for (VariableElement parameter : actualParameters) {
+                String name = parameter.getSimpleName().toString();
+                int nameIndex = expectedNames.indexOf(name);
+                if (nameIndex == -1) {
+                    String msg = String.format("Argument \"%s\" isn't captured in the match rule", name);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                    return;
+                }
+                TypeMirror type = parameter.asType();
+                if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) {
+                    String msg = String.format("Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                    return;
+                }
+            }
+
+            MethodInvokerItem invoker = invokers.get(method);
+            if (invoker == null) {
+                invoker = new MethodInvokerItem(method.getSimpleName().toString(), topDeclaringType(method).getSimpleName().toString(), method.getSimpleName().toString(), actualParameters);
+                invokers.put(method, invoker);
+            }
+
+            Element enclosing = method.getEnclosingElement();
+            String declaringClass = "";
+            String separator = "";
+            Set<Element> originatingElementsList = info.originatingElements;
+            originatingElementsList.add(method);
+            while (enclosing != null) {
+                if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                    if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
+                        String msg = String.format("MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                        processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                        return;
+                    }
+                    originatingElementsList.add(enclosing);
+                    declaringClass = enclosing.getSimpleName() + separator + declaringClass;
+                    separator = ".";
+                } else {
+                    assert enclosing.getKind() == ElementKind.PACKAGE;
+                }
+                enclosing = enclosing.getEnclosingElement();
+            }
+
+            originatingElementsList.addAll(parser.originatingElements);
+
+            // Accumulate any position declarations.
+            parser.generatePositionDeclarations(info.positionDeclarations);
+
+            List<String> matches = parser.generateVariants();
+            for (String match : matches) {
+                info.matchRules.add(new MatchRuleItem(match, invoker));
+            }
+        } catch (RuleParseError e) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), method, mirror);
+        }
+    }
+
+    // TODO borrowed from com.oracle.truffle.dsl.processor.Utils
+    @SuppressWarnings("unchecked")
+    private static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) {
+        List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name);
+        List<T> result = new ArrayList<>();
+
+        if (values != null) {
+            for (AnnotationValue value : values) {
+                T annotationValue = resolveAnnotationValue(expectedListType, value);
+                if (annotationValue != null) {
+                    result.add(annotationValue);
+                }
+            }
+        }
+        return result;
+    }
+
+    private static <T> T getAnnotationValue(Class<T> expectedType, AnnotationMirror mirror, String name) {
+        return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name));
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
+        if (value == null) {
+            return null;
+        }
+
+        Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null);
+        if (unboxedValue != null) {
+            if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
+                return null;
+            }
+            if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
+                throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
+            }
+        }
+        return (T) unboxedValue;
+    }
+
+    private static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) {
+        ExecutableElement valueMethod = null;
+        for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
+            if (method.getSimpleName().toString().equals(name)) {
+                valueMethod = method;
+                break;
+            }
+        }
+
+        if (valueMethod == null) {
+            return null;
+        }
+
+        AnnotationValue value = mirror.getElementValues().get(valueMethod);
+        if (value == null) {
+            value = valueMethod.getDefaultValue();
+        }
+
+        return value;
+    }
+
+    private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7<Object, Void> {
+
+        @Override
+        public Object visitBoolean(boolean b, Void p) {
+            return Boolean.valueOf(b);
+        }
+
+        @Override
+        public Object visitByte(byte b, Void p) {
+            return Byte.valueOf(b);
+        }
+
+        @Override
+        public Object visitChar(char c, Void p) {
+            return c;
+        }
+
+        @Override
+        public Object visitDouble(double d, Void p) {
+            return d;
+        }
+
+        @Override
+        public Object visitFloat(float f, Void p) {
+            return f;
+        }
+
+        @Override
+        public Object visitInt(int i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitLong(long i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitShort(short s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitString(String s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitType(TypeMirror t, Void p) {
+            return t;
+        }
+
+        @Override
+        public Object visitEnumConstant(VariableElement c, Void p) {
+            return c;
+        }
+
+        @Override
+        public Object visitAnnotation(AnnotationMirror a, Void p) {
+            return a;
+        }
+
+        @Override
+        public Object visitArray(List<? extends AnnotationValue> vals, Void p) {
+            return vals;
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * This annotation declares a textual pattern for matching an HIR tree. The format is a LISP style
+ * s-expression with node types and/or names that are matched against the HIR. Node types are always
+ * uppercase and the names of nodes are always lowercase. Named nodes can be used to match trees
+ * where a node is used multiple times but only as an input to the full match.
+ *
+ * <pre>
+ *   &lt;node-name&gt;    := [a-z][a-zA-Z0-9]*
+ *   &lt;node-type&gt;    := [A-Z][a-zA-Z0-9]*
+ *   &lt;node-spec&gt;    := &lt;node-type&gt; { '=' &lt;node-name&gt; }
+ *   &lt;node-or-name&gt; := &lt;node-spec&gt; | &lt;node-name&gt;
+ *   &lt;argument&gt;     := &lt;node-or-name&gt; | &lt;match-rule&gt;
+ *   &lt;match-rule&gt;   := '(' &lt;node-spec&gt; &lt;argument&gt;+ ')'
+ * </pre>
+ *
+ * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user.
+ * All matched nodes must be in the same block.
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Repeatable(value = MatchRules.class)
+public @interface MatchRule {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+public class MatchRuleRegistry {
+
+    /**
+     * Helper interface for mapping between Class and NodeClass. In static compilation environments,
+     * the current NodeClass might not be the same NodeClass used in the target so this provides a
+     * level of indirection.
+     */
+    public static interface NodeClassLookup {
+        NodeClass get(Class<?> theClass);
+
+    }
+
+    static class DefaultNodeClassLookup implements NodeClassLookup {
+        public NodeClass get(Class<?> theClass) {
+            return NodeClass.get(theClass);
+        }
+    }
+
+    /**
+     * Convert a list of field names into {@link com.oracle.graal.graph.NodeClass.Position} objects
+     * that can be used to read them during a match. The names should already have been confirmed to
+     * exist in the type.
+     *
+     * @param theClass
+     * @param names
+     * @return an array of Position objects corresponding to the named fields.
+     */
+    public static NodeClass.Position[] findPositions(NodeClassLookup lookup, Class<? extends ValueNode> theClass, String[] names) {
+        NodeClass.Position[] result = new NodeClass.Position[names.length];
+        NodeClass nodeClass = lookup.get(theClass);
+        for (int i = 0; i < names.length; i++) {
+            for (NodeClass.Position position : nodeClass.getFirstLevelInputPositions()) {
+                String name = nodeClass.getName(position);
+                if (name.endsWith("#NDF")) {
+                    name = name.substring(0, name.length() - 4);
+                }
+                if (name.equals(names[i])) {
+                    result[i] = position;
+                    break;
+                }
+            }
+            if (result[i] == null) {
+                throw new GraalInternalError("unknown field \"%s\" in class %s", names[i], theClass);
+            }
+        }
+        return result;
+    }
+
+    private static final HashMap<Class<? extends NodeLIRBuilder>, Map<Class<? extends ValueNode>, List<MatchStatement>>> registry = new HashMap<>();
+
+    /**
+     * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass.
+     *
+     * @param theClass
+     * @return the set of {@link MatchStatement}s applicable to theClass.
+     */
+    public synchronized static Map<Class<? extends ValueNode>, List<MatchStatement>> lookup(Class<? extends NodeLIRBuilder> theClass) {
+        Map<Class<? extends ValueNode>, List<MatchStatement>> result = registry.get(theClass);
+
+        if (result == null) {
+            NodeClassLookup lookup = new DefaultNodeClassLookup();
+            Map<Class<? extends ValueNode>, List<MatchStatement>> rules = createRules(theClass, lookup);
+            registry.put(theClass, rules);
+            assert registry.get(theClass) == rules;
+            result = rules;
+
+            if (LogVerbose.getValue()) {
+                try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                    Debug.log("Match rules for %s", theClass.getSimpleName());
+                    for (Entry<Class<? extends ValueNode>, List<MatchStatement>> entry : result.entrySet()) {
+                        Debug.log("  For node class: %s", entry.getKey());
+                        for (MatchStatement statement : entry.getValue()) {
+                            Debug.log("    %s", statement.getPattern());
+                        }
+                    }
+                }
+            }
+        }
+
+        if (result.size() == 0) {
+            return null;
+        }
+        return result;
+    }
+
+    /*
+     * This is a separate, public method so that external clients can create rules with a custom
+     * lookup and without the default caching behavior.
+     */
+    public static Map<Class<? extends ValueNode>, List<MatchStatement>> createRules(Class<? extends NodeLIRBuilder> theClass, NodeClassLookup lookup) {
+        HashMap<Class<? extends NodeLIRBuilder>, MatchStatementSet> matchSets = new HashMap<>();
+        Iterable<MatchStatementSet> sl = Services.load(MatchStatementSet.class);
+        for (MatchStatementSet rules : sl) {
+            matchSets.put(rules.forClass(), rules);
+        }
+
+        // Walk the class hierarchy collecting lists and merge them together. The subclass
+        // rules are first which gives them preference over earlier rules.
+        Map<Class<? extends ValueNode>, List<MatchStatement>> rules = new HashMap<>();
+        Class<?> currentClass = theClass;
+        do {
+            MatchStatementSet matchSet = matchSets.get(currentClass);
+            if (matchSet != null) {
+                List<MatchStatement> statements = matchSet.statements(lookup);
+                for (MatchStatement statement : statements) {
+                    Class<? extends ValueNode> nodeClass = statement.getPattern().nodeClass();
+                    List<MatchStatement> current = rules.get(nodeClass);
+                    if (current == null) {
+                        current = new ArrayList<>();
+                        rules.put(nodeClass, current);
+                    }
+                    current.add(statement);
+                }
+            }
+            currentClass = currentClass.getSuperclass();
+        } while (currentClass != NodeLIRBuilder.class);
+        return rules;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchRule}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface MatchRules {
+    MatchRule[] value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.MatchResultCode;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace
+ * one or more {@link ValueNode}s with a single {@link Value}.
+ */
+
+public class MatchStatement {
+    private static final DebugMetric MatchStatementSuccess = Debug.metric("MatchStatementSuccess");
+
+    /**
+     * A printable name for this statement. Usually it's just the name of the method doing the
+     * emission.
+     */
+    private final String name;
+
+    /**
+     * The actual match pattern.
+     */
+    private final MatchPattern pattern;
+
+    /**
+     * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission.
+     */
+    private MatchGenerator generatorMethod;
+
+    /**
+     * The name of arguments in the order they are expected to be passed to the generator method.
+     */
+    private String[] arguments;
+
+    public MatchStatement(String name, MatchPattern pattern, MatchGenerator generator, String[] arguments) {
+        this.name = name;
+        this.pattern = pattern;
+        this.generatorMethod = generator;
+        this.arguments = arguments;
+    }
+
+    /**
+     * Attempt to match the current statement against a Node.
+     *
+     * @param builder the current builder instance.
+     * @param node the node to be matched
+     * @param nodes the nodes in the current block
+     * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
+     *         evaluated by the NodeLIRBuilder.
+     */
+    public boolean generate(NodeLIRBuilder builder, int index, ValueNode node, List<ScheduledNode> nodes) {
+        assert index == nodes.indexOf(node);
+        // Check that the basic shape matches
+        Result result = pattern.matchShape(node, this);
+        if (result != Result.OK) {
+            return false;
+        }
+        // Now ensure that the other safety constraints are matched.
+        MatchContext context = new MatchContext(builder, this, index, node, nodes);
+        result = pattern.matchUsage(node, context);
+        if (result == Result.OK) {
+            // Invoke the generator method and set the result if it's non null.
+            ComplexMatchResult value = generatorMethod.match(builder, buildArgList(context));
+            if (value != null) {
+                context.setResult(value);
+                MatchStatementSuccess.increment();
+                Debug.metric("MatchStatement[%s]", getName()).increment();
+                return true;
+            }
+            // The pattern matched but some other code generation constraint disallowed code
+            // generation for the pattern.
+            if (LogVerbose.getValue()) {
+                Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName());
+                Debug.log("with nodes %s", formatMatch(node));
+            }
+        } else {
+            if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) {
+                Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param context
+     * @return the ValueNodes captured by the match rule in the order expected by the
+     *         generatorMethod
+     */
+    private Object[] buildArgList(MatchContext context) {
+        Object[] result = new Object[arguments.length];
+        for (int i = 0; i < arguments.length; i++) {
+            if ("root".equals(arguments[i])) {
+                result[i] = context.getRoot();
+            } else {
+                result[i] = context.namedNode(arguments[i]);
+                if (result[i] == null) {
+                    throw new GraalGraphInternalError("Can't find named node %s", arguments[i]);
+                }
+            }
+        }
+        return result;
+    }
+
+    public String formatMatch(ValueNode root) {
+        return pattern.formatMatch(root);
+    }
+
+    public MatchPattern getPattern() {
+        return pattern;
+    }
+
+    public String getName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.gen.*;
+
+public interface MatchStatementSet extends Service {
+    /**
+     * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement}
+     *         instances.
+     */
+    public Class<? extends NodeLIRBuilder> forClass();
+
+    /**
+     * @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass.
+     */
+    public List<MatchStatement> statements(MatchRuleRegistry.NodeClassLookup lookup);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * Describes the properties of a node for use when building a {@link MatchPattern}. These
+ * declarations are required when parsing a {@link MatchRule}. They are expected to be found on a
+ * super type of the holder of the method declaring the {@link MatchRule}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Repeatable(value = MatchableNodes.class)
+public @interface MatchableNode {
+
+    /**
+     * The {@link ValueNode} subclass this annotation describes. These annotations might work better
+     * if they were directly on the node being described but that may complicate the annotation
+     * processing.
+     */
+    Class<? extends ValueNode> nodeClass();
+
+    /**
+     * The names of the inputs in the order they should appear in the match.
+     */
+    String[] inputs() default {};
+
+    /**
+     * Can a pattern be matched with the operands swapped. This will cause swapped versions of
+     * patterns to be automatically generated.
+     */
+    boolean commutative() default false;
+
+    /**
+     * Can a node with multiple users be safely match by a rule.
+     */
+    boolean shareable() default false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchableNode}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchableNodes {
+    MatchableNode[] value() default {};
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri May 30 15:09:09 2014 +0200
@@ -22,14 +22,15 @@
  */
 package com.oracle.graal.compiler.phases;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.phases.HighTier.Options.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-
 import com.oracle.graal.loop.phases.*;
 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.common.cfs.IterativeFlowSensitiveReductionPhase;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
@@ -57,9 +58,14 @@
                 appendPhase(new InliningPhase(canonicalizer));
                 appendPhase(new DeadCodeEliminationPhase());
 
-                if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+                boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+                if (reduceOrEliminate && OptCanonicalizer.getValue()) {
                     appendPhase(canonicalizer);
-                    appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+                    if (FlowSensitiveReduction.getValue()) {
+                        appendPhase(new IterativeFlowSensitiveReductionPhase(canonicalizer));
+                    } else {
+                        appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+                    }
                 }
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.compiler.phases;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.options.*;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.compiler.phases;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.spi.*;
@@ -51,12 +51,7 @@
         }
 
         if (OptFloatingReads.getValue()) {
-            IncrementalCanonicalizerPhase<MidTierContext> incCanonicalizer = new IncrementalCanonicalizerPhase<>(canonicalizer);
-            incCanonicalizer.appendPhase(new FloatingReadPhase());
-            appendPhase(incCanonicalizer);
-            if (OptReadElimination.getValue()) {
-                appendPhase(new ReadEliminationPhase());
-            }
+            appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new FloatingReadPhase()));
         }
         appendPhase(new RemoveValueProxyPhase());
 
@@ -80,11 +75,11 @@
             appendPhase(canonicalizer);
         }
 
-        appendPhase(new LoopSafepointEliminationPhase());
+        appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopSafepointEliminationPhase()));
 
         appendPhase(new LoopSafepointInsertionPhase());
 
-        appendPhase(new GuardLoweringPhase());
+        appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new GuardLoweringPhase()));
 
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri May 30 15:09:09 2014 +0200
@@ -30,7 +30,9 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 
@@ -71,17 +73,17 @@
      */
     public abstract FrameMap newFrameMap(RegisterConfig registerConfig);
 
-    public abstract LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
+    public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
 
-    public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub);
+    public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, ResolvedJavaMethod method, Object stub);
 
-    public abstract NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen);
+    public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
 
     /**
      * @param gen the LIRGenerator the BytecodeLIRBuilder should use
      * @param parser the bytecode parser the BytecodeLIRBuilder should use
      */
-    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         throw GraalInternalError.unimplemented("Baseline compilation is not available for this Backend!");
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.target;
-
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerator} and {@link LIRInstruction}.
- */
-public interface LIRGenLowerable {
-
-    void generate(NodeLIRBuilder generator);
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.target;
-
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerationResult} and {@link LIRInstruction}.
- */
-public interface LIRGenResLowerable {
-
-    void generate(NodeLIRBuilderTool generator, LIRGenerationResult genRes);
-}
--- a/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java	Fri May 30 15:09:09 2014 +0200
@@ -111,7 +111,7 @@
         DebugHistogram histogram = Debug.createHistogram("TestHistogram");
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
         histogram.add("MyCustomValue");
-        new DebugHistogramAsciiPrinter(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10).print(histogram);
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10, 1).print(histogram);
         String[] lines = outputStream.toString().split("\n");
         Assert.assertEquals(4, lines.length);
         Assert.assertEquals("TestHistogram has 1 unique elements and 1 total elements:", lines[0]);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/AnsiColor.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,88 @@
+/*
+ * 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.debug;
+
+/**
+ * Ansi terminal color escape codes.
+ */
+public final class AnsiColor {
+    /** Foreground black */
+    public static final String BLACK = "\u001b[30m";
+    /** Foreground red */
+    public static final String RED = "\u001b[31m";
+    /** Foreground green */
+    public static final String GREEN = "\u001b[32m";
+    /** Foreground yellow */
+    public static final String YELLOW = "\u001b[33m";
+    /** Foreground blue */
+    public static final String BLUE = "\u001b[34m";
+    /** Foreground magenta */
+    public static final String MAGENTA = "\u001b[35m";
+    /** Foreground cyan */
+    public static final String CYAN = "\u001b[36m";
+    /** Foreground white */
+    public static final String WHITE = "\u001b[37m";
+
+    /** Foreground bold black */
+    public static final String BOLD_BLACK = "\u001b[30;1m";
+    /** Foreground bold red */
+    public static final String BOLD_RED = "\u001b[31;1m";
+    /** Foreground bold green */
+    public static final String BOLD_GREEN = "\u001b[32;1m";
+    /** Foreground bold yellow */
+    public static final String BOLD_YELLOW = "\u001b[33;1m";
+    /** Foreground bold blue */
+    public static final String BOLD_BLUE = "\u001b[34;1m";
+    /** Foreground bold magenta */
+    public static final String BOLD_MAGENTA = "\u001b[35;1m";
+    /** Foreground bold cyan */
+    public static final String BOLD_CYAN = "\u001b[36;1m";
+    /** Foreground bold white */
+    public static final String BOLD_WHITE = "\u001b[37;1m";
+
+    /** Background black */
+    public static final String BG_BLACK = "\u001b[40m";
+    /** Background red */
+    public static final String BG_RED = "\u001b[41m";
+    /** Background green */
+    public static final String BG_GREEN = "\u001b[42m";
+    /** Background yellow */
+    public static final String BG_YELLOW = "\u001b[43m";
+    /** Background blue */
+    public static final String BG_BLUE = "\u001b[44m";
+    /** Background magenta */
+    public static final String BG_MAGENTA = "\u001b[45m";
+    /** Background cyan */
+    public static final String BG_CYAN = "\u001b[46m";
+    /** Background white */
+    public static final String BG_WHITE = "\u001b[47m";
+
+    /** Reset */
+    public static final String RESET = "\u001b[0m";
+    /** Underline */
+    public static final String UNDERLINED = "\u001b[4m";
+
+    /** Prevent instantiation */
+    private AnsiColor() {
+    }
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri May 30 15:09:09 2014 +0200
@@ -94,6 +94,10 @@
         return ENABLED && DebugScope.getInstance().isTimeEnabled();
     }
 
+    public static boolean isMemUseTrackingEnabled() {
+        return ENABLED && DebugScope.getInstance().isMemUseTrackingEnabled();
+    }
+
     public static boolean isLogEnabledForMethod() {
         if (!ENABLED) {
             return false;
@@ -273,7 +277,11 @@
     }
 
     public static Scope forceLog() {
-        return Debug.sandbox("forceLog", new DelegatingDebugConfig().enable(LOG).enable(LOG_METHOD));
+        ArrayList<Object> context = new ArrayList<>();
+        for (Object obj : context()) {
+            context.add(obj);
+        }
+        return Debug.sandbox("forceLog", new DelegatingDebugConfig().enable(LOG).enable(LOG_METHOD), context.toArray());
     }
 
     /**
@@ -586,6 +594,69 @@
     }
 
     /**
+     * Creates a {@linkplain DebugMemUseTracker memory use tracker} that is enabled iff debugging is
+     * {@linkplain #isEnabled() enabled}.
+     * <p>
+     * A disabled tracker has virtually no overhead.
+     */
+    public static DebugMemUseTracker memUseTracker(CharSequence name) {
+        if (!ENABLED) {
+            return VOID_MEM_USE_TRACKER;
+        }
+        return createMemUseTracker("%s", name, null);
+    }
+
+    /**
+     * Creates a debug memory use tracker. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.memUseTracker(format, arg, null)
+     * </pre>
+     *
+     * except that the string formatting only happens if metering is enabled.
+     *
+     * @see #metric(String, Object, Object)
+     */
+    public static DebugMemUseTracker memUseTracker(String format, Object arg) {
+        if (!ENABLED) {
+            return VOID_MEM_USE_TRACKER;
+        }
+        return createMemUseTracker(format, arg, null);
+    }
+
+    /**
+     * Creates a debug memory use tracker. Invoking this method is equivalent to:
+     *
+     * <pre>
+     * Debug.memUseTracker(String.format(format, arg1, arg2))
+     * </pre>
+     *
+     * except that the string formatting only happens if memory use tracking 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 #memUseTracker(CharSequence)
+     */
+    public static DebugMemUseTracker memUseTracker(String format, Object arg1, Object arg2) {
+        if (!ENABLED) {
+            return VOID_MEM_USE_TRACKER;
+        }
+        return createMemUseTracker(format, arg1, arg2);
+    }
+
+    private static DebugMemUseTracker createMemUseTracker(String format, Object arg1, Object arg2) {
+        String name = formatDebugName(format, arg1, arg2);
+        return new MemUseTrackerImpl(name);
+    }
+
+    /**
      * Creates a {@linkplain DebugMetric metric} that is enabled iff debugging is
      * {@linkplain #isEnabled() enabled} or the system property whose name is formed by adding to
      * {@value #ENABLE_METRIC_PROPERTY_NAME_PREFIX} to {@code name} is
@@ -674,7 +745,7 @@
 
     private static DebugMetric createMetric(String format, Object arg1, Object arg2) {
         String name = formatDebugName(format, arg1, arg2);
-        boolean conditional = enabledMetrics != null && enabledMetrics.contains(name);
+        boolean conditional = enabledMetrics == null || !enabledMetrics.contains(name);
         return new MetricImpl(name, conditional);
     }
 
@@ -702,10 +773,10 @@
     }
 
     public static DebugConfig silentConfig() {
-        return fixedConfig(false, false, false, false, Collections.<DebugDumpHandler> emptyList(), System.out);
+        return fixedConfig(false, false, false, false, false, Collections.<DebugDumpHandler> emptyList(), System.out);
     }
 
-    public static DebugConfig fixedConfig(final boolean isLogEnabled, final boolean isDumpEnabled, final boolean isMeterEnabled, final boolean isTimerEnabled,
+    public static DebugConfig fixedConfig(final boolean isLogEnabled, final boolean isDumpEnabled, final boolean isMeterEnabled, final boolean isMemUseTrackingEnabled, final boolean isTimerEnabled,
                     final Collection<DebugDumpHandler> dumpHandlers, final PrintStream output) {
         return new DebugConfig() {
 
@@ -724,6 +795,11 @@
             }
 
             @Override
+            public boolean isMemUseTrackingEnabled() {
+                return isMemUseTrackingEnabled;
+            }
+
+            @Override
             public boolean isDumpEnabled() {
                 return isDumpEnabled;
             }
@@ -783,6 +859,17 @@
         }
     };
 
+    private static final DebugMemUseTracker VOID_MEM_USE_TRACKER = new DebugMemUseTracker() {
+
+        public Closeable start() {
+            return MemUseTrackerImpl.VOID_CLOSEABLE;
+        }
+
+        public long getCurrentValue() {
+            return 0;
+        }
+    };
+
     /**
      * @see #timer(CharSequence)
      */
@@ -875,7 +962,19 @@
 
     public static Object convertFormatArg(Object arg) {
         if (arg instanceof Class) {
-            return ((Class<?>) arg).getSimpleName();
+            Class<?> c = (Class<?>) arg;
+            final String simpleName = c.getSimpleName();
+            Class<?> enclosingClass = c.getEnclosingClass();
+            if (enclosingClass != null) {
+                String prefix = "";
+                while (enclosingClass != null) {
+                    prefix = enclosingClass.getSimpleName() + "_" + prefix;
+                    enclosingClass = enclosingClass.getEnclosingClass();
+                }
+                return prefix + simpleName;
+            } else {
+                return simpleName;
+            }
         }
         return arg;
     }
@@ -886,7 +985,7 @@
 
     private static DebugTimer createTimer(String format, Object arg1, Object arg2) {
         String name = formatDebugName(format, arg1, arg2);
-        boolean conditional = enabledTimers != null && enabledTimers.contains(name);
+        boolean conditional = enabledTimers == null || !enabledTimers.contains(name);
         return new TimerImpl(name, conditional);
     }
 
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Fri May 30 15:09:09 2014 +0200
@@ -47,6 +47,14 @@
     boolean isMeterEnabled();
 
     /**
+     * Determines if memory use tracking is enabled in the {@linkplain Debug#currentScope() current
+     * debug scope}.
+     *
+     * @see Debug#memUseTracker(CharSequence)
+     */
+    boolean isMemUseTrackingEnabled();
+
+    /**
      * Determines if dumping is enabled in the {@linkplain Debug#currentScope() current debug scope}
      * .
      *
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java	Fri May 30 15:09:09 2014 +0200
@@ -40,16 +40,18 @@
      */
     void add(Object value);
 
+    void add(Object value, long count);
+
     /**
      * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places
      * values with higher frequencies first.
      */
     public class CountedValue implements Comparable<CountedValue> {
 
-        private int count;
+        private long count;
         private final Object value;
 
-        public CountedValue(int count, Object value) {
+        public CountedValue(long count, Object value) {
             this.count = count;
             this.value = value;
         }
@@ -72,11 +74,11 @@
             count++;
         }
 
-        public void add(int n) {
+        public void add(long n) {
             count += n;
         }
 
-        public int getCount() {
+        public long getCount() {
             return count;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugMemUseTracker.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.debug;
+
+import com.sun.management.*;
+
+/**
+ * Tracks memory usage within a scope using {@link ThreadMXBean}. This facility should be employed
+ * using the try-with-resources pattern:
+ *
+ * <pre>
+ * try (DebugMemUseTracker.Closeable a = memUseTracker.start()) {
+ *     // the code to measure
+ * }
+ * </pre>
+ */
+public interface DebugMemUseTracker {
+
+    public interface Closeable extends AutoCloseable {
+        void close();
+    }
+
+    /**
+     * Creates a point from which memory usage will be recorded if memory use tracking is
+     * {@linkplain Debug#isMemUseTrackingEnabled() enabled}.
+     *
+     * @return an object that must be closed once the activity has completed to add the memory used
+     *         since this call to the total for this tracker
+     */
+    Closeable start();
+
+    /**
+     * Gets the current value of this tracker.
+     */
+    long getCurrentValue();
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugTimer.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugTimer.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,7 @@
 /**
  * A timer for some activity of interest. A timer should be deployed using the try-with-resources
  * pattern:
- * 
+ *
  * <pre>
  * try (TimerCloseable a = timer.start()) {
  *     // the code to time
@@ -41,21 +41,20 @@
     /**
      * Starts this timer if timing is {@linkplain Debug#isTimeEnabled() enabled} or this is an
      * {@linkplain #isConditional() unconditional} timer.
-     * 
+     *
      * @return an object that must be closed once the activity has completed to add the elapsed time
      *         since this call to the total for this timer
      */
     TimerCloseable start();
 
     /**
-     * Sets a flag determining if this timer is only enabled if metering is
-     * {@link Debug#isMeterEnabled() enabled}.
+     * Sets a flag determining if this timer is only enabled if timing is
+     * {@link Debug#isTimeEnabled() enabled}.
      */
     void setConditional(boolean flag);
 
     /**
-     * Determines if this timer is only enabled if metering is {@link Debug#isMeterEnabled()
-     * enabled}.
+     * Determines if this timer is only enabled if timing is {@link Debug#isTimeEnabled() enabled}.
      */
     boolean isConditional();
 
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Fri May 30 15:09:09 2014 +0200
@@ -59,6 +59,10 @@
          */
         METER,
         /**
+         * @see Debug#isMemUseTrackingEnabled()
+         */
+        TRACK_MEM_USE,
+        /**
          * @see Debug#isTimeEnabled()
          */
         TIME,
@@ -125,6 +129,14 @@
         return fs.booleanValue();
     }
 
+    public boolean isMemUseTrackingEnabled() {
+        Boolean fs = featureState.get(Feature.TRACK_MEM_USE);
+        if (fs == null) {
+            return delegate.isMemUseTrackingEnabled();
+        }
+        return fs.booleanValue();
+    }
+
     @Override
     public boolean isDumpEnabled() {
         Boolean fs = featureState.get(Feature.DUMP);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramAsciiPrinter.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramAsciiPrinter.java	Fri May 30 15:09:09 2014 +0200
@@ -37,14 +37,16 @@
     public static final int NumberSize = 10;
     public static final int DefaultNameSize = 50;
     public static final int DefaultBarSize = 100;
+    public static final int DefaultScale = 1;
 
-    private PrintStream os;
-    private int limit;
-    private int nameSize;
-    private int barSize;
+    private final PrintStream os;
+    private final int limit;
+    private final int nameSize;
+    private final int barSize;
+    private final int scale;
 
     public DebugHistogramAsciiPrinter(PrintStream os) {
-        this(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize);
+        this(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize, DefaultScale);
     }
 
     /**
@@ -52,12 +54,14 @@
      * @param limit limits printing to the {@code limit} most frequent values
      * @param nameSize the width of the value names column
      * @param barSize the width of the value frequency column
+     * @param scale a factor by which every result is divided
      */
-    public DebugHistogramAsciiPrinter(PrintStream os, int limit, int nameSize, int barSize) {
+    public DebugHistogramAsciiPrinter(PrintStream os, int limit, int nameSize, int barSize, int scale) {
         this.os = os;
         this.limit = limit;
         this.nameSize = nameSize;
         this.barSize = barSize;
+        this.scale = scale;
     }
 
     public void print(DebugHistogram histogram) {
@@ -68,21 +72,18 @@
         }
 
         // Sum up the total number of elements.
-        int total = 0;
-        for (CountedValue cv : list) {
-            total += cv.getCount();
-        }
+        long total = list.stream().mapToLong(CountedValue::getCount).sum();
 
         // Print header.
-        os.printf("%s has %d unique elements and %d total elements:%n", histogram.getName(), list.size(), total);
+        os.printf("%s has %d unique elements and %d total elements:%n", histogram.getName(), list.size(), total / scale);
 
-        int max = list.get(0).getCount();
+        long max = list.get(0).getCount() / scale;
         final int lineSize = nameSize + NumberSize + barSize + 10;
         printLine(os, '-', lineSize);
         String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n";
         for (int i = 0; i < list.size() && i < limit; ++i) {
             CountedValue cv = list.get(i);
-            int value = cv.getCount();
+            long value = cv.getCount() / scale;
             char[] bar = new char[(int) (((double) value / (double) max) * barSize)];
             Arrays.fill(bar, '=');
             String objectString = String.valueOf(cv.getValue());
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -44,6 +44,15 @@
         }
     }
 
+    public void add(Object value, long count) {
+        CountedValue cv = map.get(value);
+        if (cv == null) {
+            map.put(value, new CountedValue(count, value));
+        } else {
+            cv.add(count);
+        }
+    }
+
     @Override
     public String getName() {
         return name;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Fri May 30 15:09:09 2014 +0200
@@ -93,6 +93,7 @@
 
     private boolean meterEnabled;
     private boolean timeEnabled;
+    private boolean memUseTrackingEnabled;
     private boolean dumpEnabled;
     private boolean logEnabled;
 
@@ -169,6 +170,10 @@
         return timeEnabled;
     }
 
+    public boolean isMemUseTrackingEnabled() {
+        return memUseTrackingEnabled;
+    }
+
     public void log(String msg, Object... args) {
         lastUsedIndent.log(msg, args);
     }
@@ -261,6 +266,7 @@
         DebugConfig config = getConfig();
         if (config == null) {
             meterEnabled = false;
+            memUseTrackingEnabled = false;
             timeEnabled = false;
             dumpEnabled = false;
 
@@ -269,6 +275,7 @@
             output = System.out;
         } else {
             meterEnabled = config.isMeterEnabled();
+            memUseTrackingEnabled = config.isMemUseTrackingEnabled();
             timeEnabled = config.isTimeEnabled();
             dumpEnabled = config.isDumpEnabled();
             logEnabled = config.isLogEnabled();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,113 @@
+/*
+ * 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.debug.internal;
+
+import static java.lang.Thread.*;
+
+import java.lang.management.*;
+
+import com.oracle.graal.debug.*;
+import com.sun.management.ThreadMXBean;
+
+public final class MemUseTrackerImpl extends DebugValue implements DebugMemUseTracker {
+
+    private static final ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
+
+    /**
+     * The amount of memory allocated by {@link ThreadMXBean#getThreadAllocatedBytes(long)} itself.
+     */
+    private static final long threadMXBeanOverhead = -getCurrentThreadAllocatedBytes() + getCurrentThreadAllocatedBytes();
+
+    private static long getCurrentThreadAllocatedBytes() {
+        return threadMXBean.getThreadAllocatedBytes(currentThread().getId()) - threadMXBeanOverhead;
+    }
+
+    public static final Closeable VOID_CLOSEABLE = new Closeable() {
+
+        @Override
+        public void close() {
+        }
+    };
+
+    /**
+     * Records the most recent active tracker.
+     */
+    private static final ThreadLocal<CloseableImpl> currentTracker = new ThreadLocal<>();
+
+    private final DebugValue flat;
+
+    public MemUseTrackerImpl(String name) {
+        super(name + "_Accm", false);
+        this.flat = new DebugValue(name + "_Flat", false) {
+
+            @Override
+            public String toString(long value) {
+                return valueToString(value);
+            }
+        };
+    }
+
+    @Override
+    public Closeable start() {
+        if (!isConditional() || Debug.isTimeEnabled()) {
+            CloseableImpl result = new CloseableImpl();
+            currentTracker.set(result);
+            return result;
+        } else {
+            return VOID_CLOSEABLE;
+        }
+    }
+
+    public static String valueToString(long value) {
+        return String.format("%d bytes", value);
+    }
+
+    @Override
+    public String toString(long value) {
+        return valueToString(value);
+    }
+
+    private final class CloseableImpl implements Closeable {
+
+        private final CloseableImpl parent;
+        private final long start;
+        private long nestedAmountToSubtract;
+
+        private CloseableImpl() {
+            this.parent = currentTracker.get();
+            this.start = getCurrentThreadAllocatedBytes();
+        }
+
+        @Override
+        public void close() {
+            long end = getCurrentThreadAllocatedBytes();
+            long allocated = end - start;
+            if (parent != null) {
+                parent.nestedAmountToSubtract += allocated;
+            }
+            currentTracker.set(parent);
+            MemUseTrackerImpl.this.addToCurrentValue(allocated);
+            flat.addToCurrentValue(allocated - nestedAmountToSubtract);
+        }
+    }
+}
--- a/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java	Fri May 30 15:09:09 2014 +0200
@@ -43,6 +43,8 @@
     private long entryPoint;
     private StructuredGraph hostGraph;
 
+    private int[] oopMapArray;
+
     /**
      * Set the address for the point of entry to the external compilation result.
      * 
@@ -75,4 +77,13 @@
     public StructuredGraph getHostGraph() {
         return hostGraph;
     }
+
+    public void setOopMapArray(int[] arr) {
+        oopMapArray = arr;
+    }
+
+    public int[] getOopMapArray() {
+        return oopMapArray;
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graph.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.graal.graph.*;
+
+public class NodeMapTest {
+
+    private static class TestNode extends Node {
+    }
+
+    private Graph graph;
+    private TestNode[] nodes = new TestNode[100];
+    private NodeMap<Integer> map;
+
+    @Before
+    public void before() {
+        graph = new Graph();
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = graph.add(new TestNode());
+        }
+        map = new NodeMap<>(graph);
+        for (int i = 0; i < nodes.length; i += 2) {
+            map.set(nodes[i], i);
+        }
+    }
+
+    @Test
+    public void testEmpty() {
+        NodeMap<Integer> emptyMap = new NodeMap<>(graph);
+        for (TestNode node : nodes) {
+            assertEquals(null, emptyMap.get(node));
+        }
+    }
+
+    @Test
+    public void testSimple() {
+        for (int i = 0; i < nodes.length; i++) {
+            if ((i & 1) == 0) {
+                assertEquals((Integer) i, map.get(nodes[i]));
+            } else {
+                assertEquals(null, map.get(nodes[i]));
+            }
+        }
+    }
+
+    @Test
+    public void testSimpleChanged() {
+        for (TestNode node : nodes) {
+            map.set(node, 1);
+        }
+        for (TestNode node : nodes) {
+            map.set(node, null);
+        }
+        for (int i = 0; i < nodes.length; i += 2) {
+            map.set(nodes[i], i);
+        }
+
+        for (int i = 0; i < nodes.length; i++) {
+            if ((i & 1) == 0) {
+                assertEquals((Integer) i, map.get(nodes[i]));
+            } else {
+                assertEquals(null, map.get(nodes[i]));
+            }
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testNewGet() {
+        /*
+         * Failing here is not required, but if this behavior changes, usages of get need to be
+         * checked for compatibility.
+         */
+        TestNode newNode = graph.add(new TestNode());
+        map.get(newNode);
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testNewSet() {
+        /*
+         * Failing here is not required, but if this behavior changes, usages of set need to be
+         * checked for compatibility.
+         */
+        TestNode newNode = graph.add(new TestNode());
+        map.set(newNode, 1);
+    }
+
+    @Test
+    public void testNewGetAndGrow() {
+        TestNode newNode = graph.add(new TestNode());
+        assertEquals(null, map.getAndGrow(newNode));
+    }
+
+    @Test
+    public void testNewSetAndGrow() {
+        TestNode newNode = graph.add(new TestNode());
+        map.setAndGrow(newNode, 1);
+        assertEquals((Integer) 1, map.get(newNode));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/DefaultNodeCollectionsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graph;
+
+import java.util.*;
+
+import com.oracle.graal.api.collections.*;
+
+/**
+ * A default implementation of {@link NodeCollectionsProvider} that creates standard JDK collection
+ * class objects.
+ */
+public class DefaultNodeCollectionsProvider extends DefaultCollectionsProvider implements NodeCollectionsProvider {
+
+    public <E extends Node> Set<E> newNodeIdentitySet() {
+        return Collections.newSetFromMap(newNodeIdentityMap());
+    }
+
+    public <K extends Node, V> Map<K, V> newNodeIdentityMap() {
+        return new IdentityHashMap<>();
+    }
+
+    public <K extends Node, V> Map<K, V> newNodeIdentityMap(int expectedMaxSize) {
+        return new IdentityHashMap<>(expectedMaxSize);
+    }
+
+    public <K extends Node, V> Map<K, V> newNodeIdentityMap(Map<K, V> initFrom) {
+        return new IdentityHashMap<>(initFrom);
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FieldIntrospection.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.graph;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.concurrent.*;
-
-public abstract class FieldIntrospection extends UnsafeAccess {
-
-    /**
-     * Interface used by {@link #rescanAllFieldOffsets(CalcOffset)} to determine the offset (in
-     * bytes) of a field.
-     */
-    public interface CalcOffset {
-
-        long getOffset(Field field);
-    }
-
-    public static class DefaultCalcOffset implements CalcOffset {
-
-        @Override
-        public long getOffset(Field field) {
-            return unsafe.objectFieldOffset(field);
-        }
-    }
-
-    protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
-
-    protected final Class<?> clazz;
-    protected long[] dataOffsets;
-    protected Map<Long, String> fieldNames;
-    protected Map<Long, Class<?>> fieldTypes;
-
-    public FieldIntrospection(Class<?> clazz) {
-        this.clazz = clazz;
-    }
-
-    public static void rescanAllFieldOffsets(CalcOffset calc) {
-        for (FieldIntrospection nodeClass : allClasses.values()) {
-            nodeClass.rescanFieldOffsets(calc);
-        }
-    }
-
-    protected abstract void rescanFieldOffsets(CalcOffset calc);
-
-    public abstract static class BaseFieldScanner {
-
-        private final CalcOffset calc;
-
-        /** The offsets of fields that are not specially handled by subclasses. */
-        public final ArrayList<Long> dataOffsets = new ArrayList<>();
-
-        public final Map<Long, String> fieldNames = new HashMap<>();
-        public final Map<Long, Class<?>> fieldTypes = new HashMap<>();
-
-        protected BaseFieldScanner(CalcOffset calc) {
-            this.calc = calc;
-        }
-
-        protected void scan(Class<?> clazz) {
-            Class<?> currentClazz = clazz;
-            do {
-                for (Field field : currentClazz.getDeclaredFields()) {
-                    if (Modifier.isStatic(field.getModifiers())) {
-                        continue;
-                    }
-                    Class<?> type = field.getType();
-                    long offset = calc.getOffset(field);
-
-                    // scanField() may overwrite the name with a customized name.
-                    fieldNames.put(offset, field.getName());
-                    fieldTypes.put(offset, type);
-
-                    scanField(field, type, offset);
-                }
-                currentClazz = currentClazz.getSuperclass();
-            } while (currentClazz.getSuperclass() != Object.class);
-        }
-
-        protected abstract void scanField(Field field, Class<?> type, long offset);
-    }
-
-    protected static void copyInto(long[] dest, long[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, T[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, List<T> src) {
-        assert dest.length == src.size();
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src.get(i);
-        }
-    }
-
-    protected static <T> T[] arrayUsingSortedOffsets(Map<Long, T> map, long[] sortedOffsets, T[] result) {
-        for (int i = 0; i < sortedOffsets.length; i++) {
-            result[i] = map.get(sortedOffsets[i]);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1) {
-        Collections.sort(list1);
-        long[] result = new long[list1.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1, ArrayList<Long> list2) {
-        Collections.sort(list1);
-        Collections.sort(list2);
-        long[] result = new long[list1.size() + list2.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        for (int i = 0; i < list2.size(); i++) {
-            result[list1.size() + i] = list2.get(i);
-        }
-        return result;
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri May 30 15:09:09 2014 +0200
@@ -740,19 +740,11 @@
     }
 
     public NodeBitMap createNodeBitMap() {
-        return createNodeBitMap(false);
-    }
-
-    public NodeBitMap createNodeBitMap(boolean autoGrow) {
-        return new NodeBitMap(this, autoGrow);
+        return new NodeBitMap(this);
     }
 
     public <T> NodeMap<T> createNodeMap() {
-        return createNodeMap(false);
-    }
-
-    public <T> NodeMap<T> createNodeMap(boolean autoGrow) {
-        return new NodeMap<>(this, autoGrow);
+        return new NodeMap<>(this);
     }
 
     public NodeFlood createNodeFlood() {
@@ -760,11 +752,11 @@
     }
 
     public NodeWorkList createNodeWorkList() {
-        return new NodeWorkList(this);
+        return new NodeWorkList.SingletonNodeWorkList(this);
     }
 
-    public NodeWorkList createNodeWorkList(boolean fill, int iterationLimitPerNode) {
-        return new NodeWorkList(this, fill, iterationLimitPerNode);
+    public NodeWorkList createIterativeNodeWorkList(boolean fill, int iterationLimitPerNode) {
+        return new NodeWorkList.IterativeNodeWorkList(this, fill, iterationLimitPerNode);
     }
 
     void register(Node node) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri May 30 15:09:09 2014 +0200
@@ -142,13 +142,17 @@
      */
     private Node usage0;
     private Node usage1;
-    private Node[] extraUsages = NO_NODES;
+    private Node[] extraUsages;
 
     private Node predecessor;
 
     public Node() {
-        this.graph = null;
-        this.id = INITIAL_ID;
+        init();
+    }
+
+    final void init() {
+        id = INITIAL_ID;
+        extraUsages = NO_NODES;
     }
 
     int id() {
@@ -184,7 +188,6 @@
 
     class NodeUsageIterator implements Iterator<Node> {
 
-        private final int expectedModCount = usageModCount();
         int index = -1;
         Node current;
 
@@ -207,12 +210,10 @@
         }
 
         public boolean hasNext() {
-            assert expectedModCount == usageModCount();
             return current != null;
         }
 
         public Node next() {
-            assert expectedModCount == usageModCount();
             Node result = current;
             if (result == null) {
                 throw new NoSuchElementException();
@@ -227,10 +228,35 @@
         }
     }
 
+    class NodeUsageWithModCountIterator extends NodeUsageIterator {
+
+        private final int expectedModCount = usageModCount();
+
+        @Override
+        public boolean hasNext() {
+            if (expectedModCount != usageModCount()) {
+                throw new ConcurrentModificationException();
+            }
+            return super.hasNext();
+        }
+
+        @Override
+        public Node next() {
+            if (expectedModCount != usageModCount()) {
+                throw new ConcurrentModificationException();
+            }
+            return super.next();
+        }
+    }
+
     class NodeUsageIterable implements NodeIterable<Node> {
 
         public NodeUsageIterator iterator() {
-            return new NodeUsageIterator();
+            if (MODIFICATION_COUNTS_ENABLED) {
+                return new NodeUsageWithModCountIterator();
+            } else {
+                return new NodeUsageIterator();
+            }
         }
 
         @Override
@@ -651,7 +677,7 @@
             NodeClassIterator iter = usage.inputs().iterator();
             while (iter.hasNext()) {
                 Position pos = iter.nextPosition();
-                if (pos.getInputType(usage) == type) {
+                if (pos.getInputType(usage) == type && pos.get(usage) == this) {
                     pos.set(usage, other);
                 }
             }
@@ -931,7 +957,11 @@
      * @param map
      */
     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
-        getNodeClass().getDebugProperties(this, map);
+        NodeClass nodeClass = getNodeClass();
+        for (Integer pos : nodeClass.getPropertyPositions()) {
+            map.put(nodeClass.getPropertyName(pos), nodeClass.getProperty(this, pos));
+
+        }
         return map;
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Fri May 30 15:09:09 2014 +0200
@@ -27,92 +27,109 @@
 import com.oracle.graal.graph.iterators.*;
 
 public final class NodeBitMap implements NodeIterable<Node> {
+    private static final int SHIFT = 6;
 
-    private final boolean autoGrow;
-    private final BitSet bitMap;
+    private long[] bits;
     private int nodeCount;
     private final NodeIdAccessor nodeIdAccessor;
 
     public NodeBitMap(Graph graph) {
-        this(graph, false);
+        nodeCount = graph.nodeIdCount();
+        bits = new long[sizeForNodeCount(nodeCount)];
+        this.nodeIdAccessor = new NodeIdAccessor(graph);
     }
 
-    public NodeBitMap(Graph graph, boolean autoGrow) {
-        this(graph, autoGrow, graph.nodeIdCount(), new BitSet(graph.nodeIdCount()));
+    private static int sizeForNodeCount(int nodeCount) {
+        return (nodeCount + Long.SIZE - 1) >> SHIFT;
     }
 
-    private NodeBitMap(Graph graph, boolean autoGrow, int nodeCount, BitSet bits) {
-        this.nodeIdAccessor = new NodeIdAccessor(graph);
-        this.autoGrow = autoGrow;
-        this.nodeCount = nodeCount;
-        bitMap = bits;
+    private NodeBitMap(NodeBitMap other) {
+        this.bits = other.bits.clone();
+        this.nodeCount = other.nodeCount;
+        this.nodeIdAccessor = other.nodeIdAccessor;
     }
 
     public Graph graph() {
         return nodeIdAccessor.getGraph();
     }
 
-    public void setUnion(NodeBitMap other) {
-        bitMap.or(other.bitMap);
-    }
-
-    public void negate() {
-        grow();
-        bitMap.flip(0, nodeCount);
-    }
-
-    public boolean isNotNewMarked(Node node) {
-        return !isNew(node) && isMarked(node);
-    }
-
-    public boolean isNotNewNotMarked(Node node) {
-        return !isNew(node) && !isMarked(node);
-    }
-
-    public boolean isMarked(Node node) {
-        return bitMap.get(nodeIdAccessor.getNodeId(node));
-    }
-
     public boolean isNew(Node node) {
         return nodeIdAccessor.getNodeId(node) >= nodeCount;
     }
 
+    public boolean isMarked(Node node) {
+        assert check(node, false);
+        int id = nodeIdAccessor.getNodeId(node);
+        return (bits[id >> SHIFT] & (1L << id)) != 0;
+    }
+
+    public boolean isMarkedAndGrow(Node node) {
+        assert check(node, true);
+        int id = nodeIdAccessor.getNodeId(node);
+        checkGrow(id);
+        return (bits[id >> SHIFT] & (1L << id)) != 0;
+    }
+
     public void mark(Node node) {
-        if (autoGrow && isNew(node)) {
-            grow();
-        }
-        assert check(node);
-        bitMap.set(nodeIdAccessor.getNodeId(node));
+        assert check(node, false);
+        int id = nodeIdAccessor.getNodeId(node);
+        bits[id >> SHIFT] |= (1L << id);
+    }
+
+    public void markAndGrow(Node node) {
+        assert check(node, true);
+        int id = nodeIdAccessor.getNodeId(node);
+        checkGrow(id);
+        bits[id >> SHIFT] |= (1L << id);
     }
 
     public void clear(Node node) {
-        if (autoGrow && isNew(node)) {
-            return;
+        assert check(node, false);
+        int id = nodeIdAccessor.getNodeId(node);
+        bits[id >> SHIFT] &= ~(1L << id);
+    }
+
+    public void clearAndGrow(Node node) {
+        assert check(node, true);
+        int id = nodeIdAccessor.getNodeId(node);
+        checkGrow(id);
+        bits[id >> SHIFT] &= ~(1L << id);
+    }
+
+    private void checkGrow(int id) {
+        if (id >= nodeCount) {
+            if ((id >> SHIFT) >= bits.length) {
+                grow();
+            } else {
+                nodeCount = id + 1;
+            }
         }
-        assert check(node);
-        bitMap.clear(nodeIdAccessor.getNodeId(node));
     }
 
     public void clearAll() {
-        bitMap.clear();
+        Arrays.fill(bits, 0);
     }
 
     public void intersect(NodeBitMap other) {
         assert graph() == other.graph();
-        bitMap.and(other.bitMap);
-    }
-
-    public void grow(Node node) {
-        nodeCount = Math.max(nodeCount, nodeIdAccessor.getNodeId(node) + 1);
+        int commonLength = Math.min(bits.length, other.bits.length);
+        for (int i = commonLength; i < bits.length; i++) {
+            bits[i] = 0;
+        }
+        for (int i = 0; i < commonLength; i++) {
+            bits[i] &= other.bits[i];
+        }
     }
 
-    public void grow() {
+    private void grow() {
         nodeCount = Math.max(nodeCount, graph().nodeIdCount());
+        int newLength = Math.max((bits.length * 3 / 2) + 1, sizeForNodeCount(nodeCount));
+        bits = Arrays.copyOf(bits, newLength);
     }
 
-    private boolean check(Node node) {
+    private boolean check(Node node, boolean grow) {
         assert node.graph() == graph() : "this node is not part of the graph";
-        assert !isNew(node) : "node was added to the graph after creating the node bitmap: " + node;
+        assert grow || !isNew(node) : "node was added to the graph after creating the node bitmap: " + node;
         assert node.isAlive() : "node is deleted!";
         return true;
     }
@@ -175,12 +192,8 @@
         return new MarkedNodeIterator(NodeBitMap.this, graph().getNodes().iterator());
     }
 
-    public int cardinality() {
-        return bitMap.cardinality();
-    }
-
     public NodeBitMap copy() {
-        return new NodeBitMap(graph(), autoGrow, nodeCount, (BitSet) bitMap.clone());
+        return new NodeBitMap(this);
     }
 
     @Override
@@ -190,11 +203,20 @@
 
     @Override
     public int count() {
-        return bitMap.cardinality();
+        int count = 0;
+        for (long l : bits) {
+            count += Long.bitCount(l);
+        }
+        return count;
     }
 
     @Override
     public boolean contains(Node node) {
         return isMarked(node);
     }
+
+    @Override
+    public String toString() {
+        return snapshot().toString();
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.graph;
 
 import static com.oracle.graal.graph.Graph.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -179,10 +180,10 @@
             this.iterableId = nextIterableId++;
             List<NodeClass> existingClasses = new LinkedList<>();
             for (FieldIntrospection nodeClass : allClasses.values()) {
-                if (clazz.isAssignableFrom(nodeClass.clazz)) {
+                if (clazz.isAssignableFrom(nodeClass.getClazz())) {
                     existingClasses.add((NodeClass) nodeClass);
                 }
-                if (nodeClass.clazz.isAssignableFrom(clazz) && IterableNodeType.class.isAssignableFrom(nodeClass.clazz)) {
+                if (nodeClass.getClazz().isAssignableFrom(clazz) && IterableNodeType.class.isAssignableFrom(nodeClass.getClazz())) {
                     NodeClass superNodeClass = (NodeClass) nodeClass;
                     superNodeClass.iterableIds = Arrays.copyOf(superNodeClass.iterableIds, superNodeClass.iterableIds.length + 1);
                     superNodeClass.iterableIds[superNodeClass.iterableIds.length - 1] = this.iterableId;
@@ -207,7 +208,7 @@
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
         FieldScanner scanner = new FieldScanner(calc);
-        scanner.scan(clazz);
+        scanner.scan(getClazz());
         assert directInputCount == scanner.inputOffsets.size();
         copyInto(inputOffsets, sortedLongCopy(scanner.inputOffsets, scanner.inputListOffsets));
         assert directSuccessorCount == scanner.successorOffsets.size();
@@ -324,7 +325,7 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append("NodeClass ").append(clazz.getSimpleName()).append(" [");
+        str.append("NodeClass ").append(getClazz().getSimpleName()).append(" [");
         for (int i = 0; i < inputOffsets.length; i++) {
             str.append(i == 0 ? "" : ", ").append(inputOffsets[i]);
         }
@@ -754,43 +755,6 @@
         return number;
     }
 
-    /**
-     * Populates a given map with the names and values of all data fields.
-     *
-     * @param node the node from which to take the values.
-     * @param properties a map that will be populated.
-     */
-    public void getDebugProperties(Node node, Map<Object, Object> properties) {
-        for (int i = 0; i < dataOffsets.length; ++i) {
-            Class<?> type = fieldTypes.get(dataOffsets[i]);
-            Object value = null;
-            if (type.isPrimitive()) {
-                if (type == Integer.TYPE) {
-                    value = unsafe.getInt(node, dataOffsets[i]);
-                } else if (type == Long.TYPE) {
-                    value = unsafe.getLong(node, dataOffsets[i]);
-                } else if (type == Boolean.TYPE) {
-                    value = unsafe.getBoolean(node, dataOffsets[i]);
-                } else if (type == Float.TYPE) {
-                    value = unsafe.getFloat(node, dataOffsets[i]);
-                } else if (type == Double.TYPE) {
-                    value = unsafe.getDouble(node, dataOffsets[i]);
-                } else if (type == Short.TYPE) {
-                    value = unsafe.getShort(node, dataOffsets[i]);
-                } else if (type == Character.TYPE) {
-                    value = unsafe.getChar(node, dataOffsets[i]);
-                } else if (type == Byte.TYPE) {
-                    value = unsafe.getByte(node, dataOffsets[i]);
-                } else {
-                    assert false : "unhandled property type: " + type;
-                }
-            } else {
-                value = unsafe.getObject(node, dataOffsets[i]);
-            }
-            properties.put(fieldNames.get(dataOffsets[i]), value);
-        }
-    }
-
     private static boolean deepEquals0(Object e1, Object e2) {
         assert e1 != null;
         boolean eq;
@@ -932,6 +896,73 @@
         return fieldNames.get(pos.isInput() ? inputOffsets[pos.getIndex()] : successorOffsets[pos.getIndex()]);
     }
 
+    public String getPropertyName(int pos) {
+        return fieldNames.get(dataOffsets[pos]);
+    }
+
+    public Class<?> getPropertyType(int pos) {
+        return fieldTypes.get(dataOffsets[pos]);
+    }
+
+    public Object getProperty(Node node, int pos) {
+        long dataOffset = dataOffsets[pos];
+        Class<?> type = fieldTypes.get(dataOffset);
+        Object value = null;
+        if (type.isPrimitive()) {
+            if (type == Integer.TYPE) {
+                value = unsafe.getInt(node, dataOffset);
+            } else if (type == Long.TYPE) {
+                value = unsafe.getLong(node, dataOffset);
+            } else if (type == Boolean.TYPE) {
+                value = unsafe.getBoolean(node, dataOffset);
+            } else if (type == Float.TYPE) {
+                value = unsafe.getFloat(node, dataOffset);
+            } else if (type == Double.TYPE) {
+                value = unsafe.getDouble(node, dataOffset);
+            } else if (type == Short.TYPE) {
+                value = unsafe.getShort(node, dataOffset);
+            } else if (type == Character.TYPE) {
+                value = unsafe.getChar(node, dataOffset);
+            } else if (type == Byte.TYPE) {
+                value = unsafe.getByte(node, dataOffset);
+            } else {
+                assert false : "unhandled property type: " + type;
+            }
+        } else {
+            value = unsafe.getObject(node, dataOffset);
+        }
+        return value;
+    }
+
+    public void setProperty(Node node, int pos, Object value) {
+        long dataOffset = dataOffsets[pos];
+        Class<?> type = fieldTypes.get(dataOffset);
+        if (type.isPrimitive()) {
+            if (type == Integer.TYPE) {
+                unsafe.putInt(node, dataOffset, (Integer) value);
+            } else if (type == Long.TYPE) {
+                unsafe.putLong(node, dataOffset, (Long) value);
+            } else if (type == Boolean.TYPE) {
+                unsafe.putBoolean(node, dataOffset, (Boolean) value);
+            } else if (type == Float.TYPE) {
+                unsafe.putFloat(node, dataOffset, (Float) value);
+            } else if (type == Double.TYPE) {
+                unsafe.putDouble(node, dataOffset, (Double) value);
+            } else if (type == Short.TYPE) {
+                unsafe.putShort(node, dataOffset, (Short) value);
+            } else if (type == Character.TYPE) {
+                unsafe.putChar(node, dataOffset, (Character) value);
+            } else if (type == Byte.TYPE) {
+                unsafe.putByte(node, dataOffset, (Byte) value);
+            } else {
+                assert false : "unhandled property type: " + type;
+            }
+        } else {
+            assert value == null || !value.getClass().isPrimitive();
+            unsafe.putObject(node, dataOffset, value);
+        }
+    }
+
     void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) {
         int index = 0;
         while (index < directInputCount) {
@@ -972,7 +1003,7 @@
         int index = startIndex;
         while (index < inputOffsets.length) {
             NodeList<Node> list = getNodeList(node, inputOffsets[index]);
-            assert list != null : clazz;
+            assert list != null : getClazz();
             putNodeList(node, inputOffsets[index], updateInputListCopy(list, node, duplicationReplacement));
             index++;
         }
@@ -982,7 +1013,7 @@
         int index = startIndex;
         while (index < successorOffsets.length) {
             NodeList<Node> list = getNodeList(node, successorOffsets[index]);
-            assert list != null : clazz;
+            assert list != null : getClazz();
             putNodeList(node, successorOffsets[index], updateSuccListCopy(list, node, duplicationReplacement));
             index++;
         }
@@ -1030,7 +1061,7 @@
             if (pos.getSubIndex() < list.size()) {
                 list.set(pos.getSubIndex(), x);
             } else {
-                while (pos.getSubIndex() < list.size() - 1) {
+                while (list.size() < pos.getSubIndex()) {
                     list.add(null);
                 }
                 list.add(x);
@@ -1039,7 +1070,7 @@
     }
 
     public NodeClassIterable getInputIterable(final Node node) {
-        assert clazz.isInstance(node);
+        assert getClazz().isInstance(node);
         return new NodeClassIterable() {
 
             @Override
@@ -1059,7 +1090,7 @@
     }
 
     public NodeClassIterable getSuccessorIterable(final Node node) {
-        assert clazz.isInstance(node);
+        assert getClazz().isInstance(node);
         return new NodeClassIterable() {
 
             @Override
@@ -1092,7 +1123,7 @@
         }
         while (index < inputOffsets.length) {
             NodeList<Node> list = getNodeList(node, inputOffsets[index]);
-            assert list != null : clazz;
+            assert list != null : getClazz();
             if (list.replaceFirst(old, other)) {
                 return true;
             }
@@ -1115,7 +1146,7 @@
         }
         while (index < successorOffsets.length) {
             NodeList<Node> list = getNodeList(node, successorOffsets[index]);
-            assert list != null : clazz + " " + successorOffsets[index] + " " + node;
+            assert list != null : getClazz() + " " + successorOffsets[index] + " " + node;
             if (list.replaceFirst(old, other)) {
                 return true;
             }
@@ -1172,7 +1203,7 @@
      * @param newNode the node to which the inputs should be copied.
      */
     public void copyInputs(Node node, Node newNode) {
-        assert node.getClass() == clazz && newNode.getClass() == clazz;
+        assert node.getClass() == getClazz() && newNode.getClass() == getClazz();
 
         int index = 0;
         while (index < directInputCount) {
@@ -1194,7 +1225,7 @@
      * @param newNode the node to which the successors should be copied.
      */
     public void copySuccessors(Node node, Node newNode) {
-        assert node.getClass() == clazz && newNode.getClass() == clazz;
+        assert node.getClass() == getClazz() && newNode.getClass() == getClazz();
 
         int index = 0;
         while (index < directSuccessorCount) {
@@ -1213,7 +1244,7 @@
     }
 
     public boolean inputsEqual(Node node, Node other) {
-        assert node.getClass() == clazz && other.getClass() == clazz;
+        assert node.getClass() == getClazz() && other.getClass() == getClazz();
         int index = 0;
         while (index < directInputCount) {
             if (getNode(other, inputOffsets[index]) != getNode(node, inputOffsets[index])) {
@@ -1232,7 +1263,7 @@
     }
 
     public boolean successorsEqual(Node node, Node other) {
-        assert node.getClass() == clazz && other.getClass() == clazz;
+        assert node.getClass() == getClazz() && other.getClass() == getClazz();
         int index = 0;
         while (index < directSuccessorCount) {
             if (getNode(other, successorOffsets[index]) != getNode(node, successorOffsets[index])) {
@@ -1251,7 +1282,7 @@
     }
 
     public boolean inputContains(Node node, Node other) {
-        assert node.getClass() == clazz;
+        assert node.getClass() == getClazz();
 
         int index = 0;
         while (index < directInputCount) {
@@ -1271,7 +1302,7 @@
     }
 
     public boolean successorContains(Node node, Node other) {
-        assert node.getClass() == clazz;
+        assert node.getClass() == getClazz();
 
         int index = 0;
         while (index < directSuccessorCount) {
@@ -1352,8 +1383,56 @@
         };
     }
 
+    public Collection<Integer> getPropertyPositions() {
+        return new AbstractCollection<Integer>() {
+            @Override
+            public Iterator<Integer> iterator() {
+                return new Iterator<Integer>() {
+                    int i = 0;
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+
+                    public Integer next() {
+                        Integer pos = i++;
+                        return pos;
+                    }
+
+                    public boolean hasNext() {
+                        return i < dataOffsets.length;
+                    }
+                };
+            }
+
+            @Override
+            public int size() {
+                return dataOffsets.length;
+            }
+        };
+    }
+
+    /**
+     * Initializes a fresh allocated node for which no constructor is called yet. Needed to
+     * implement node factories in svm.
+     */
+    public void initRawNode(Node node) {
+        node.init();
+        for (int inputPos = directInputCount; inputPos < inputOffsets.length; inputPos++) {
+            if (getNodeList(node, inputOffsets[inputPos]) == null) {
+                putNodeList(node, inputOffsets[inputPos], new NodeInputList<>(node));
+            }
+        }
+        for (int successorPos = directSuccessorCount; successorPos < successorOffsets.length; successorPos++) {
+            if (getNodeList(node, successorOffsets[successorPos]) == null) {
+                putNodeList(node, successorOffsets[successorPos], new NodeSuccessorList<>(node));
+            }
+        }
+    }
+
     public Class<?> getJavaClass() {
-        return clazz;
+        return getClazz();
     }
 
     /**
@@ -1371,12 +1450,13 @@
 
     static Map<Node, Node> addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable<Node> nodes, final DuplicationReplacement replacements) {
         final Map<Node, Node> newNodes;
-        if (estimatedNodeCount > (oldGraph.getNodeCount() + oldGraph.getNodesDeletedSinceLastCompression() >> 4)) {
+        int denseThreshold = oldGraph.getNodeCount() + oldGraph.getNodesDeletedSinceLastCompression() >> 4;
+        if (estimatedNodeCount > denseThreshold) {
             // Use dense map
             newNodes = new NodeNodeMap(oldGraph);
         } else {
             // Use sparse map
-            newNodes = new IdentityHashMap<>();
+            newNodes = newIdentityMap();
         }
         createNodeDuplicates(graph, nodes, replacements, newNodes);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeCollectionsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graph;
+
+import java.util.*;
+
+import com.oracle.graal.api.collections.*;
+
+/**
+ * Extends {@link CollectionsProvider} with support for creating {@link Node} based collections.
+ */
+public interface NodeCollectionsProvider extends CollectionsProvider {
+
+    /**
+     * Creates a set of {@link Node}s that uses reference-equality in place of object-equality when
+     * comparing entries.
+     */
+    <E extends Node> Set<E> newNodeIdentitySet();
+
+    /**
+     * Creates a map whose keys are {@link Node}s that uses reference-equality in place of
+     * object-equality when comparing keys. All {@link Node} keys must be in the same graph.
+     */
+    <K extends Node, V> Map<K, V> newNodeIdentityMap();
+
+    /**
+     * Creates a map whose keys are {@link Node}s that uses reference-equality in place of
+     * object-equality when comparing keys. All {@link Node} keys must be in the same graph.
+     */
+    <K extends Node, V> Map<K, V> newNodeIdentityMap(int expectedMaxSize);
+
+    /**
+     * Creates a map whose keys are {@link Node}s that uses reference-equality in place of
+     * object-equality when comparing keys. All {@link Node} keys must be in the same graph.
+     *
+     * @param initFrom the returned map is populated with the entries in this map
+     */
+    <K extends Node, V> Map<K, V> newNodeIdentityMap(Map<K, V> initFrom);
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Fri May 30 15:09:09 2014 +0200
@@ -28,31 +28,39 @@
 
 public class NodeMap<T> extends NodeIdAccessor {
 
-    private final boolean autogrow;
+    private static final int MIN_REALLOC_SIZE = 16;
+
     protected Object[] values;
 
     public NodeMap(Graph graph) {
-        this(graph, false);
-    }
-
-    public NodeMap(Graph graph, boolean autogrow) {
         super(graph);
         this.values = new Object[graph.nodeIdCount()];
-        this.autogrow = autogrow;
     }
 
     public NodeMap(NodeMap<T> copyFrom) {
         super(copyFrom.graph);
         this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length);
-        this.autogrow = copyFrom.autogrow;
     }
 
     @SuppressWarnings("unchecked")
     public T get(Node node) {
-        check(node);
+        assert check(node);
+        return (T) values[getNodeId(node)];
+    }
+
+    @SuppressWarnings("unchecked")
+    public T getAndGrow(Node node) {
+        checkAndGrow(node);
         return (T) values[getNodeId(node)];
     }
 
+    private void checkAndGrow(Node node) {
+        if (isNew(node)) {
+            this.values = Arrays.copyOf(values, Math.max(MIN_REALLOC_SIZE, graph.nodeIdCount() * 3 / 2));
+        }
+        assert check(node);
+    }
+
     public boolean isEmpty() {
         return !entries().iterator().hasNext();
     }
@@ -81,7 +89,12 @@
     }
 
     public void set(Node node, T value) {
-        check(node);
+        assert check(node);
+        values[getNodeId(node)] = value;
+    }
+
+    public void setAndGrow(Node node, T value) {
+        checkAndGrow(node);
         values[getNodeId(node)] = value;
     }
 
@@ -93,16 +106,10 @@
         return getNodeId(node) >= size();
     }
 
-    public void grow() {
-        this.values = Arrays.copyOf(values, graph.nodeIdCount());
-    }
-
-    private void check(Node node) {
-        if (autogrow && isNew(node)) {
-            grow();
-        }
+    private boolean check(Node node) {
         assert node.graph() == graph : String.format("%s is not part of the graph", node);
         assert !isNew(node) : "this node was added to the graph after creating the node map : " + node;
+        return true;
     }
 
     public void clear() {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeNodeMap.java	Fri May 30 15:09:09 2014 +0200
@@ -27,7 +27,7 @@
 public final class NodeNodeMap extends NodeMap<Node> implements Map<Node, Node> {
 
     public NodeNodeMap(Graph graph) {
-        super(graph, true);
+        super(graph);
     }
 
     public NodeNodeMap(NodeNodeMap copyFrom) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Fri May 30 15:09:09 2014 +0200
@@ -24,23 +24,11 @@
 
 import java.util.*;
 
-public class NodeWorkList implements Iterable<Node> {
+public abstract class NodeWorkList implements Iterable<Node> {
 
-    private final NodeBitMap visited;
-    private final NodeBitMap inQueue;
-    private final Queue<Node> worklist;
-    private int iterationLimit = Integer.MAX_VALUE;
-    private Node firstNoChange;
-    private Node lastPull;
-    private Node lastChain;
+    protected final Queue<Node> worklist;
 
-    public NodeWorkList(Graph graph) {
-        this(graph, false, -1);
-    }
-
-    public NodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) {
-        visited = graph.createNodeBitMap();
-        inQueue = graph.createNodeBitMap();
+    private NodeWorkList(Graph graph, boolean fill) {
         if (fill) {
             ArrayDeque<Node> deque = new ArrayDeque<>(graph.getNodeCount());
             for (Node node : graph.getNodes()) {
@@ -50,9 +38,6 @@
         } else {
             worklist = new ArrayDeque<>();
         }
-        if (iterationLimitPerNode > 0) {
-            iterationLimit = iterationLimitPerNode * graph.getNodeCount();
-        }
     }
 
     public void addAll(Iterable<? extends Node> nodes) {
@@ -63,111 +48,13 @@
         }
     }
 
-    public void add(Node node) {
-        if (node != null) {
-            if (visited.isNew(node)) {
-                visited.grow(node);
-                inQueue.grow(node);
-            }
-            if (!visited.isMarked(node)) {
-                addAgain(node);
-            }
-        }
-    }
+    public abstract void add(Node node);
 
-    public void addAgain(Node node) {
-        if (visited.isNew(node)) {
-            visited.grow(node);
-            inQueue.grow(node);
-        }
-        if (node != null && !inQueue.isMarked(node)) {
-            if (lastPull == node) {
-                if (firstNoChange == null) {
-                    firstNoChange = node;
-                    lastChain = node;
-                } else if (node == firstNoChange) {
-                    throw new InfiniteWorkException("ReAdded " + node);
-                } else {
-                    lastChain = node;
-                }
-            } else {
-                firstNoChange = null;
-            }
-            visited.mark(node);
-            inQueue.mark(node);
-            worklist.add(node);
-        }
-    }
-
-    public void clearVisited() {
-        visited.clearAll();
-    }
-
-    public void replaced(Node newNode, Node oldNode) {
-        this.replaced(newNode, oldNode, false);
-    }
+    private abstract class QueueConsumingIterator implements Iterator<Node> {
 
-    public void replaced(Node newNode, Node oldNode, boolean add) {
-        worklist.remove(oldNode);
-        if (newNode == null) {
-            return;
-        }
-        if (add) {
-            this.add(newNode);
-        }
-        for (Node n : newNode.usages()) {
-            addAgain(n);
-        }
-    }
-
-    public boolean isMarked(Node node) {
-        return visited.isMarked(node);
-    }
-
-    public boolean isNew(Node node) {
-        return visited.isNew(node);
-    }
-
-    public boolean isEmpty() {
-        return worklist.isEmpty();
-    }
-
-    public boolean isInQueue(Node node) {
-        return !inQueue.isNew(node) && inQueue.isMarked(node);
-    }
-
-    private class QueueConsumingIterator implements Iterator<Node> {
-
-        private final Queue<Node> queue;
-
-        public QueueConsumingIterator(Queue<Node> queue) {
-            this.queue = queue;
-        }
-
-        @Override
-        public boolean hasNext() {
-            dropDeleted();
-            return iterationLimit > 0 && !queue.isEmpty();
-        }
-
-        @Override
-        public Node next() {
-            if (iterationLimit-- <= 0) {
-                throw new NoSuchElementException();
-            }
-            dropDeleted();
-            Node node = queue.remove();
-            if (lastPull != lastChain) {
-                firstNoChange = null;
-            }
-            lastPull = node;
-            inQueue.clear(node);
-            return node;
-        }
-
-        private void dropDeleted() {
-            while (!queue.isEmpty() && queue.peek().isDeleted()) {
-                queue.remove();
+        protected void dropDeleted() {
+            while (!worklist.isEmpty() && worklist.peek().isDeleted()) {
+                worklist.remove();
             }
         }
 
@@ -177,74 +64,142 @@
         }
     }
 
-    @Override
-    public Iterator<Node> iterator() {
-        return new QueueConsumingIterator(worklist);
-    }
-
-    private static class UnmarkedNodeIterator implements Iterator<Node> {
+    public static final class IterativeNodeWorkList extends NodeWorkList {
 
-        private final NodeBitMap visited;
-        private Iterator<Node> nodes;
-        private Node nextNode;
-
-        public UnmarkedNodeIterator(NodeBitMap visited, Iterator<Node> nodes) {
-            this.visited = visited;
-            this.nodes = nodes;
-            forward();
-        }
+        private static final int EXPLICIT_BITMAP_THRESHOLD = 10;
+        protected NodeBitMap inQueue;
 
-        private void forward() {
-            do {
-                if (!nodes.hasNext()) {
-                    nextNode = null;
-                    return;
-                }
-                nextNode = nodes.next();
-            } while (visited.isMarked(nextNode));
-        }
+        private int iterationLimit = Integer.MAX_VALUE;
+        private Node firstNoChange;
+        private Node lastPull;
+        private Node lastChain;
 
-        @Override
-        public boolean hasNext() {
-            return nextNode != null;
-        }
-
-        @Override
-        public Node next() {
-            try {
-                return nextNode;
-            } finally {
-                forward();
+        public IterativeNodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) {
+            super(graph, fill);
+            if (iterationLimitPerNode > 0) {
+                iterationLimit = iterationLimitPerNode * graph.getNodeCount();
             }
         }
 
         @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
+        public Iterator<Node> iterator() {
+            return new QueueConsumingIterator() {
+                @Override
+                public boolean hasNext() {
+                    dropDeleted();
+                    return iterationLimit > 0 && !worklist.isEmpty();
+                }
+
+                @Override
+                public Node next() {
+                    if (iterationLimit-- <= 0) {
+                        throw new NoSuchElementException();
+                    }
+                    dropDeleted();
+                    Node node = worklist.remove();
+                    assert updateInfiniteWork(node);
+                    if (inQueue != null) {
+                        inQueue.clearAndGrow(node);
+                    }
+                    return node;
+                }
+
+                private boolean updateInfiniteWork(Node node) {
+                    if (lastPull != lastChain) {
+                        firstNoChange = null;
+                    }
+                    lastPull = node;
+                    return true;
+                }
+            };
         }
 
+        @Override
+        public void add(Node node) {
+            if (node != null) {
+                if (inQueue != null) {
+                    if (inQueue.isMarkedAndGrow(node)) {
+                        return;
+                    }
+                } else {
+                    if (worklist.size() > EXPLICIT_BITMAP_THRESHOLD) {
+                        inflateToBitMap(node.graph());
+                    } else {
+                        for (Node queuedNode : worklist) {
+                            if (queuedNode == node) {
+                                return;
+                            }
+                        }
+                    }
+                }
+                assert checkInfiniteWork(node) : "Readded " + node;
+                if (inQueue != null) {
+                    inQueue.markAndGrow(node);
+                }
+                worklist.add(node);
+            }
+        }
+
+        private boolean checkInfiniteWork(Node node) {
+            if (lastPull == node) {
+                if (firstNoChange == null) {
+                    firstNoChange = node;
+                    lastChain = node;
+                } else if (node == firstNoChange) {
+                    return false;
+                } else {
+                    lastChain = node;
+                }
+            } else {
+                firstNoChange = null;
+            }
+            return true;
+        }
+
+        private void inflateToBitMap(Graph graph) {
+            assert inQueue == null;
+            inQueue = graph.createNodeBitMap();
+            for (Node queuedNode : worklist) {
+                if (queuedNode.isAlive()) {
+                    inQueue.mark(queuedNode);
+                }
+            }
+        }
     }
 
-    public Iterable<Node> unmarkedNodes() {
-        return new Iterable<Node>() {
+    public static final class SingletonNodeWorkList extends NodeWorkList {
+        protected final NodeBitMap visited;
 
-            @Override
-            public Iterator<Node> iterator() {
-                return new UnmarkedNodeIterator(visited, visited.graph().getNodes().iterator());
-            }
-        };
-    }
-
-    public static class InfiniteWorkException extends RuntimeException {
-
-        private static final long serialVersionUID = -5319329402219396658L;
-
-        public InfiniteWorkException() {
-            super();
+        public SingletonNodeWorkList(Graph graph) {
+            super(graph, false);
+            visited = graph.createNodeBitMap();
         }
 
-        public InfiniteWorkException(String message) {
-            super(message);
+        @Override
+        public void add(Node node) {
+            if (node != null) {
+                if (!visited.isMarkedAndGrow(node)) {
+                    visited.mark(node);
+                    worklist.add(node);
+                }
+            }
+        }
+
+        @Override
+        public Iterator<Node> iterator() {
+            return new QueueConsumingIterator() {
+                @Override
+                public boolean hasNext() {
+                    dropDeleted();
+                    return !worklist.isEmpty();
+                }
+
+                @Override
+                public Node next() {
+                    dropDeleted();
+                    return worklist.remove();
+                }
+            };
         }
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.graph;
-
-import java.lang.reflect.*;
-
-import sun.misc.*;
-
-public class UnsafeAccess {
-
-    /**
-     * An instance of {@link Unsafe} for use within Graal.
-     */
-    public static final Unsafe unsafe = getUnsafe();
-
-    private static Unsafe getUnsafe() {
-        try {
-            // this will fail if Graal is not part of the boot class path
-            return Unsafe.getUnsafe();
-        } catch (SecurityException e) {
-            // nothing to do
-        }
-        try {
-            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
-            theUnsafeInstance.setAccessible(true);
-            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
-        } catch (Exception e) {
-            // currently we rely on being able to use Unsafe...
-            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
-        }
-    }
-
-    /**
-     * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'}
-     * terminated C string. The native memory buffer is allocated via
-     * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when
-     * it is no longer needed via {@link Unsafe#freeMemory(long)}.
-     * 
-     * @return the native memory pointer of the C string created from {@code s}
-     */
-    public static long createCString(String s) {
-        return writeCString(s, unsafe.allocateMemory(s.length() + 1));
-    }
-
-    /**
-     * Reads a {@code '\0'} terminated C string from native memory and converts it to a
-     * {@link String}.
-     * 
-     * @return a Java string
-     */
-    public static String readCString(long address) {
-        if (address == 0) {
-            return null;
-        }
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0;; i++) {
-            char c = (char) unsafe.getByte(address + i);
-            if (c == 0) {
-                break;
-            }
-            sb.append(c);
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'}
-     * terminated C string. The caller is responsible for ensuring the buffer is at least
-     * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer
-     * when it is no longer.
-     * 
-     * @return the value of {@code buf}
-     */
-    public static long writeCString(String s, long buf) {
-        int size = s.length();
-        for (int i = 0; i < size; i++) {
-            unsafe.putByte(buf + i, (byte) s.charAt(i));
-        }
-        unsafe.putByte(buf + size, (byte) '\0');
-        return buf;
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java	Fri May 30 15:09:09 2014 +0200
@@ -50,7 +50,7 @@
             return true;
         }
         if (visited == null) {
-            visited = n.graph().createNodeBitMap(true);
+            visited = n.graph().createNodeBitMap();
         }
         boolean accept = !visited.isMarked(n);
         visited.mark(n);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/util/CollectionsAccess.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graph.util;
+
+import java.util.*;
+
+import com.oracle.graal.api.collections.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.graph.*;
+
+/**
+ * Static methods for accessing the methods in the installed {@link GraalRuntime}'s
+ * {@link CollectionsProvider} and {@link NodeCollectionsProvider}.
+ */
+public class CollectionsAccess {
+
+    private static final NodeCollectionsProvider provider = Graal.getRequiredCapability(NodeCollectionsProvider.class);
+
+    /**
+     * @see CollectionsProvider#newIdentityMap()
+     */
+    public static <K, V> Map<K, V> newIdentityMap() {
+        return provider.newIdentityMap();
+    }
+
+    /**
+     * @see CollectionsProvider#newIdentityMap()
+     */
+    public static <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
+        return provider.newIdentityMap(expectedMaxSize);
+    }
+
+    /**
+     * @see CollectionsProvider#newIdentityMap(Map)
+     */
+    public static <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom) {
+        return provider.newIdentityMap(initFrom);
+    }
+
+    /**
+     * @see NodeCollectionsProvider#newNodeIdentitySet()
+     */
+    public static <E extends Node> Set<E> newNodeIdentitySet() {
+        return provider.newNodeIdentitySet();
+    }
+
+    /**
+     * @see NodeCollectionsProvider#newNodeIdentityMap()
+     */
+    public static <K extends Node, V> Map<K, V> newNodeIdentityMap() {
+        return provider.newNodeIdentityMap();
+    }
+
+    /**
+     * @see NodeCollectionsProvider#newNodeIdentityMap(int)
+     */
+    public static <K extends Node, V> Map<K, V> newNodeIdentityMap(int expectedMaxSize) {
+        return provider.newNodeIdentityMap(expectedMaxSize);
+    }
+
+    /**
+     * @see NodeCollectionsProvider#newNodeIdentityMap(Map)
+     */
+    public static <K extends Node, V> Map<K, V> newNodeIdentityMap(Map<K, V> initFrom) {
+        return provider.newNodeIdentityMap(initFrom);
+    }
+
+    /**
+     * Creates an identity set.
+     */
+    public static <E> Set<E> newIdentitySet() {
+        return provider.newIdentitySet();
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java	Fri May 30 15:09:09 2014 +0200
@@ -35,7 +35,7 @@
 
     public AMD64DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, target, linkage);
-        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14});
+        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14});
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri May 30 15:09:09 2014 +0200
@@ -25,8 +25,7 @@
 import static com.oracle.graal.amd64.AMD64.*;
 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.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
@@ -48,7 +47,9 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
 /**
  * HotSpot AMD64 specific backend.
@@ -72,22 +73,22 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new AMD64HotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, ResolvedJavaMethod method, Object stub) {
         return new AMD64HotSpotLIRGenerationResult(lir, frameMap, stub);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new AMD64HotSpotNodeLIRBuilder(graph, lirGen);
     }
 
     @Override
-    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         return new AMD64HotSpotBytecodeLIRBuilder(gen, parser);
 
     }
@@ -190,7 +191,6 @@
                 CalleeSaveLayout csl = crb.frameMap.registerConfig.getCalleeSaveLayout();
 
                 if (csl != null && csl.size != 0) {
-                    crb.compilationResult.setRegisterRestoreEpilogueOffset(asm.position());
                     // saved all registers, restore all registers
                     int frameToCSA = crb.frameMap.offsetToCalleeSaveArea();
                     asm.restore(csl, frameToCSA);
@@ -264,7 +264,7 @@
      */
     public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, RegisterConfig regConfig, HotSpotVMConfig config, Label verifiedEntry) {
         HotSpotProviders providers = getProviders();
-        if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
+        if (installedCodeOwner != null && !installedCodeOwner.isStatic()) {
             MarkId.recordMark(crb, MarkId.UNVERIFIED_ENTRY);
             CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false);
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
@@ -312,7 +312,7 @@
             MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
             AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
-            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null);
+            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
+
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
@@ -30,6 +32,7 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
@@ -98,24 +101,65 @@
         assert host == null;
         TargetDescription target = createTarget(runtime.getConfig());
 
-        HotSpotRegistersProvider registers = createRegisters();
-        HotSpotMetaAccessProvider metaAccess = createMetaAccess(runtime);
-        HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target);
-        HotSpotConstantReflectionProvider constantReflection = createConstantReflection(runtime);
-        Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
-        HotSpotHostForeignCallsProvider foreignCalls = createForeignCalls(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
-        HotSpotLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers);
-        // Replacements cannot have speculative optimizations since they have
-        // to be valid for the entire run of the VM.
-        Assumptions assumptions = new Assumptions(false);
-        Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
-        HotSpotSnippetReflectionProvider snippetReflection = createSnippetReflection();
-        Replacements replacements = createReplacements(runtime, assumptions, p, snippetReflection);
-        HotSpotDisassemblerProvider disassembler = createDisassembler(runtime);
-        HotSpotSuitesProvider suites = createSuites(runtime);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
-
-        return createBackend(runtime, providers);
+        HotSpotProviders providers;
+        HotSpotRegistersProvider registers;
+        HotSpotCodeCacheProvider codeCache;
+        HotSpotConstantReflectionProvider constantReflection;
+        HotSpotHostForeignCallsProvider foreignCalls;
+        Value[] nativeABICallerSaveRegisters;
+        HotSpotMetaAccessProvider metaAccess;
+        HotSpotLoweringProvider lowerer;
+        HotSpotSnippetReflectionProvider snippetReflection;
+        Replacements replacements;
+        HotSpotDisassemblerProvider disassembler;
+        HotSpotSuitesProvider suites;
+        HotSpotMethodHandleAccessProvider methodHandleAccess;
+        try (InitTimer t = timer("create providers")) {
+            try (InitTimer rt = timer("create HotSpotRegisters provider")) {
+                registers = createRegisters();
+            }
+            try (InitTimer rt = timer("create MetaAccess provider")) {
+                metaAccess = createMetaAccess(runtime);
+            }
+            try (InitTimer rt = timer("create CodeCache provider")) {
+                codeCache = createCodeCache(runtime, target);
+            }
+            try (InitTimer rt = timer("create ConstantReflection provider")) {
+                constantReflection = createConstantReflection(runtime);
+            }
+            try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) {
+                nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
+            }
+            try (InitTimer rt = timer("create ForeignCalls provider")) {
+                foreignCalls = createForeignCalls(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
+            }
+            try (InitTimer rt = timer("create Lowerer provider")) {
+                lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
+            }
+            // Replacements cannot have speculative optimizations since they have
+            // to be valid for the entire run of the VM.
+            Assumptions assumptions = new Assumptions(false);
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
+            try (InitTimer rt = timer("create SnippetReflection provider")) {
+                snippetReflection = createSnippetReflection();
+            }
+            try (InitTimer rt = timer("create Replacements provider")) {
+                replacements = createReplacements(runtime, assumptions, p, snippetReflection);
+            }
+            try (InitTimer rt = timer("create Disassembler provider")) {
+                disassembler = createDisassembler(runtime);
+            }
+            try (InitTimer rt = timer("create Suites provider")) {
+                suites = createSuites(runtime);
+            }
+            try (InitTimer rt = timer("create MethodHandleAccess provider")) {
+                methodHandleAccess = new HotSpotMethodHandleAccessProvider();
+            }
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection, methodHandleAccess);
+        }
+        try (InitTimer rt = timer("instantiate backend")) {
+            return createBackend(runtime, providers);
+        }
     }
 
     protected AMD64HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) {
@@ -159,8 +203,9 @@
         return new HotSpotSnippetReflectionProvider();
     }
 
-    protected AMD64HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
-        return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
+                    TargetDescription target) {
+        return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, target);
     }
 
     protected Value[] createNativeABICallerSaveRegisters(HotSpotVMConfig config, RegisterConfig regConfig) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -24,17 +24,17 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotLIRGenerator.SaveRbp;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.lir.gen.*;
 
 public class AMD64HotSpotBytecodeLIRBuilder extends BytecodeLIRBuilder {
 
-    public AMD64HotSpotBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public AMD64HotSpotBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         super(gen, parser);
     }
 
@@ -72,7 +72,7 @@
         gen.append(getSaveRbp().placeholder);
 
         Signature sig = method.getSignature();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         for (int i = 0; i < sig.getParameterCount(!isStatic); i++) {
             Value paramValue = params[i];
             assert paramValue.getKind() == sig.getParameterKind(i).getStackKind();
@@ -80,4 +80,19 @@
         }
     }
 
+    @Override
+    public int getArrayLengthOffset() {
+        return getGen().config.arrayLengthOffset;
+    }
+
+    @Override
+    public Constant getClassConstant(ResolvedJavaType declaringClass) {
+        return HotSpotObjectConstant.forObject(((HotSpotResolvedJavaType) declaringClass).mirror());
+    }
+
+    @Override
+    public int getFieldOffset(ResolvedJavaField field) {
+        return ((HotSpotResolvedJavaField) field).offset();
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.data.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64HotSpotCompare {
+
+    @Opcode("NCMP")
+    public static class HotSpotCompareNarrowOp extends AMD64LIRInstruction {
+
+        @Use({REG}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public HotSpotCompareNarrowOp(AllocatableValue x, AllocatableValue y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(y)) {
+                masm.cmpl(asRegister(x), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                masm.cmpl(asRegister(x), (AMD64Address) crb.asAddress(y));
+            }
+        }
+
+        @Override
+        protected void verify() {
+            assert x.getPlatformKind() == NarrowOopStamp.NarrowOop && y.getPlatformKind() == NarrowOopStamp.NarrowOop;
+        }
+    }
+
+    @Opcode("CMP")
+    public static class HotSpotCompareConstantOp extends AMD64LIRInstruction {
+
+        @Use({REG}) protected AllocatableValue x;
+        protected Constant y;
+
+        public HotSpotCompareConstantOp(AllocatableValue x, Constant y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            assert isRegister(x);
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) {
+                // compressed null
+                masm.testl(asRegister(x), asRegister(x));
+            } else if (y instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed(y)) {
+                    // compressed oop
+                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(y), true));
+                    masm.cmpl(asRegister(x), 0xDEADDEAD);
+                } else {
+                    // uncompressed oop
+                    AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(new OopData(8, HotSpotObjectConstant.asObject(y), false));
+                    masm.cmpq(asRegister(x), patch);
+                }
+            } else if (y instanceof HotSpotMetaspaceConstant) {
+                if (y.getKind() == Kind.Int) {
+                    // compressed metaspace pointer
+                    crb.recordInlineDataInCode(new MetaspaceData(0, y.asInt(), HotSpotMetaspaceConstant.getMetaspaceObject(y), true));
+                    masm.cmpl(asRegister(x), y.asInt());
+                } else {
+                    // uncompressed metaspace pointer
+                    AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(new MetaspaceData(8, y.asLong(), HotSpotObjectConstant.asObject(y), false));
+                    masm.cmpq(asRegister(x), patch);
+                }
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Opcode("CMP")
+    public static class HotSpotCompareMemoryConstantOp extends MemOp {
+
+        protected Constant y;
+
+        public HotSpotCompareMemoryConstantOp(Kind kind, AMD64AddressValue x, Constant y, LIRFrameState state) {
+            super(kind, x, state);
+            this.y = y;
+        }
+
+        @Override
+        protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) {
+                // compressed null
+                masm.cmpl(address.toAddress(), 0);
+            } else if (y instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed(y) && crb.target.inlineObjects) {
+                    // compressed oop
+                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(y), true));
+                    masm.cmpl(address.toAddress(), 0xDEADDEAD);
+                } else {
+                    // uncompressed oop
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else if (y instanceof HotSpotMetaspaceConstant) {
+                if (y.getKind() == Kind.Int) {
+                    // compressed metaspace pointer
+                    crb.recordInlineDataInCode(new MetaspaceData(0, y.asInt(), HotSpotMetaspaceConstant.getMetaspaceObject(y), true));
+                    masm.cmpl(address.toAddress(), y.asInt());
+                } else {
+                    // uncompressed metaspace pointer
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -29,19 +29,20 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
  * Emits code that enters a stack frame which is tailored to call the C++ method
- * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
  */
 @Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction {
 
-    private final Register thread;
+    private final Register threadRegister;
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
     private final int threadLastJavaFpOffset;
@@ -49,32 +50,51 @@
     @Alive(REG) AllocatableValue senderSp;
     @Alive(REG) AllocatableValue senderFp;
 
-    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc, AllocatableValue senderSp,
-                    AllocatableValue senderFp) {
-        this.thread = thread;
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc,
+                    AllocatableValue senderSp, AllocatableValue senderFp, SaveRegistersOp saveRegisterOp) {
+        this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.threadLastJavaFpOffset = threadLastJavaFpOffset;
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.senderFp = senderFp;
+        this.saveRegisterOp = saveRegisterOp;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+        final int totalFrameSize = frameMap.totalFrameSize();
+
+        // Push return address.
         masm.push(asRegister(framePc));
+
+        // Push base pointer.
         masm.push(asRegister(senderFp));
-        masm.movq(rbp, rsp);
+        masm.movq(rbp, stackPointerRegister);
 
         /*
          * Allocate a full sized frame. Since return address and base pointer are already in place
          * (see above) we allocate two words less.
          */
-        masm.decrementq(rsp, totalFrameSize - 2 * crb.target.wordSize);
+        masm.decrementq(stackPointerRegister, totalFrameSize - 2 * crb.target.wordSize);
+
+        // Save return registers after moving the frame.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize), integerResultRegister);
+
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize), floatResultRegister);
 
         // Set up last Java values.
-        masm.movq(new AMD64Address(thread, threadLastJavaSpOffset), rsp);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaSpOffset), stackPointerRegister);
 
         /*
          * Save the PC since it cannot easily be retrieved using the last Java SP after we aligned
@@ -82,12 +102,12 @@
          * blob.
          */
         masm.leaq(rax, new AMD64Address(rip, 0));
-        masm.movq(new AMD64Address(thread, threadLastJavaPcOffset), rax);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaPcOffset), rax);
 
         // Use BP because the frames look interpreted now.
-        masm.movq(new AMD64Address(thread, threadLastJavaFpOffset), rbp);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaFpOffset), rbp);
 
         // Align the stack for the following unpackFrames call.
-        masm.andq(rsp, -(crb.target.stackAlignment));
+        masm.andq(stackPointerRegister, -(crb.target.stackAlignment));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -30,9 +30,8 @@
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
-import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.hotspot.replacements.CRC32Substitutions.*;
-import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -63,7 +62,8 @@
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
 
-        link(new AMD64DeoptimizationStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64DeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64UncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
 
         // When the java.ext.dirs property is modified then the crypto classes might not be found.
         // If that's the case we ignore the ClassNotFoundException and continue since we cannot
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Fri May 30 15:09:09 2014 +0200
@@ -25,10 +25,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 
 public class AMD64HotSpotLIRGenerationResult extends LIRGenerationResultBase {
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -24,39 +24,40 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.LoadCompressedPointer;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedConstantOp;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedPointer;
+import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.HotSpotStoreConstantOp;
+import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
-import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
@@ -64,6 +65,7 @@
 public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
 
     final HotSpotVMConfig config;
+    private HotSpotLockStack lockStack;
 
     protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
         super(providers, cc, lirGenRes);
@@ -130,7 +132,17 @@
 
     @Override
     public StackSlot getLockSlot(int lockDepth) {
-        return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth);
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert lockStack != null;
+        return lockStack;
+    }
+
+    protected void setLockStack(HotSpotLockStack lockStack) {
+        assert this.lockStack == null;
+        this.lockStack = lockStack;
     }
 
     private Register findPollOnReturnScratchRegister() {
@@ -159,7 +171,7 @@
     }
 
     @Override
-    protected boolean needOnlyOopMaps() {
+    public boolean needOnlyOopMaps() {
         // Stubs only need oop maps
         return ((AMD64HotSpotLIRGenerationResult) getResult()).getStub() != null;
     }
@@ -177,8 +189,8 @@
         super.emitForeignCall(linkage, result, arguments, temps, info);
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        append(new AMD64HotSpotLeaveCurrentStackFrameOp());
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        append(new AMD64HotSpotLeaveCurrentStackFrameOp(saveRegisterOp));
     }
 
     public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
@@ -187,18 +199,18 @@
         append(new AMD64HotSpotLeaveDeoptimizedStackFrameOp(frameSizeVariable, initialInfoVariable));
     }
 
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        Register thread = getProviders().getRegisters().getThreadRegister();
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
         Variable framePcVariable = load(framePc);
         Variable senderSpVariable = load(senderSp);
         Variable senderFpVariable = load(senderFp);
-        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
-                        senderSpVariable, senderFpVariable));
+        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
+                        senderSpVariable, senderFpVariable, saveRegisterOp));
     }
 
-    public void emitLeaveUnpackFramesStackFrame() {
-        Register thread = getProviders().getRegisters().getThreadRegister();
-        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset()));
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), saveRegisterOp));
     }
 
     /**
@@ -245,7 +257,7 @@
     }
 
     @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
         boolean destroysRegisters = hotspotLinkage.destroysRegisters();
 
@@ -260,9 +272,10 @@
         }
 
         Variable result;
-        DeoptimizingNode deoptInfo = null;
+        // TODO (je) check if we can remove this
+        LIRFrameState deoptInfo = null;
         if (hotspotLinkage.canDeoptimize()) {
-            deoptInfo = info;
+            deoptInfo = state;
             assert deoptInfo != null || getStub() != null;
             assert hotspotLinkage.needsJavaFrameAnchor();
         }
@@ -273,7 +286,8 @@
             result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
             append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
         } else {
-            result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
+            assert deoptInfo == null;
+            result = super.emitForeignCall(hotspotLinkage, null, args);
         }
 
         if (destroysRegisters) {
@@ -307,6 +321,21 @@
         return result;
     }
 
+    public Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO);
+
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(Kind.Long));
+        append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
     protected AMD64ZapRegistersOp emitZapRegisters(Register[] zappedRegisters, Constant[] zapValues) {
         AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappedRegisters, zapValues);
         append(zap);
@@ -371,9 +400,9 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         moveDeoptValuesToThread(actionAndReason, speculation);
-        append(new AMD64DeoptimizeOp(state(deopting)));
+        append(new AMD64DeoptimizeOp(state));
     }
 
     @Override
@@ -397,13 +426,6 @@
     }
 
     /**
-     * Returns whether or not the input access should be (de)compressed.
-     */
-    private boolean isCompressedOperation(PlatformKind kind, Access access) {
-        return access != null && access.isCompressible() && ((kind == Kind.Long && config.useCompressedClassPointers) || (kind == Kind.Object && config.useCompressedOops));
-    }
-
-    /**
      * @return a compressed version of the incoming constant
      */
     protected static Constant compress(Constant c, CompressEncoding encoding) {
@@ -444,85 +466,25 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         AMD64AddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(toStackKind(kind));
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        /**
-         * Currently, the (de)compression of pointers applies conditionally to some objects (oops,
-         * kind==Object) and some addresses (klass pointers, kind==Long). Initially, the input
-         * operation is checked to discover if it has been tagged as a potential "compression"
-         * candidate. Consequently, depending on the appropriate kind, the specific (de)compression
-         * functions are being called.
-         */
-        if (isCompressedOperation(kind, access)) {
-            if (kind == Kind.Object) {
-                append(new LoadCompressedPointer(Kind.Object, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, state, config.getOopEncoding()));
-            } else if (kind == Kind.Long) {
-                Variable scratch = config.getKlassEncoding().base != 0 ? newVariable(Kind.Long) : null;
-                append(new LoadCompressedPointer(Kind.Long, result, scratch, loadAddress, state, config.getKlassEncoding()));
-            } else {
-                throw GraalInternalError.shouldNotReachHere("can't handle: " + access);
-            }
-        } else {
-            append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
-        }
+        append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         AMD64AddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        boolean isCompressed = isCompressedOperation(kind, access);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
-            if (canStoreConstant(c, isCompressed)) {
-                if (isCompressed) {
-                    if (c.getKind() == Kind.Object) {
-                        append(new StoreCompressedConstantOp(Kind.Object, storeAddress, c, state));
-                    } else if (c.getKind() == Kind.Long) {
-                        // It's always a good idea to directly store compressed constants since they
-                        // have to be materialized as 64 bits encoded otherwise.
-                        Constant value = compress(c, config.getKlassEncoding());
-                        append(new StoreCompressedConstantOp(Kind.Long, storeAddress, value, state));
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("can't handle: " + access);
-                    }
-                    return;
-                } else {
-                    append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
-                    return;
-                }
+            if (canStoreConstant(c)) {
+                append(new HotSpotStoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
+                return;
             }
         }
         Variable input = load(inputVal);
-        if (isCompressed) {
-            if (kind == Kind.Object) {
-                if (input.getKind() == Kind.Object) {
-                    Variable scratch = newVariable(Kind.Long);
-                    Register heapBaseReg = getProviders().getRegisters().getHeapBaseRegister();
-                    append(new StoreCompressedPointer(Kind.Object, storeAddress, input, scratch, state, config.getOopEncoding(), heapBaseReg));
-                } else {
-                    // the input oop is already compressed
-                    append(new StoreOp(input.getKind(), storeAddress, input, state));
-                }
-            } else if (kind == Kind.Long) {
-                Variable scratch = newVariable(Kind.Long);
-                Register heapBaseReg = getProviders().getRegisters().getHeapBaseRegister();
-                append(new StoreCompressedPointer(Kind.Long, storeAddress, input, scratch, state, config.getKlassEncoding(), heapBaseReg));
-            } else {
-                append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
-            }
-        } else {
-            append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
-        }
+        append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
     }
 
     @Override
@@ -536,8 +498,7 @@
             Variable result = newVariable(Kind.Int);
             AllocatableValue base = Value.ILLEGAL;
             if (encoding.base != 0) {
-                base = newVariable(Kind.Long);
-                append(new AMD64Move.MoveToRegOp(Kind.Long, base, Constant.forLong(encoding.base)));
+                base = emitMove(Constant.forLong(encoding.base));
             }
             append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
             return result;
@@ -555,8 +516,7 @@
             Variable result = newVariable(Kind.Long);
             AllocatableValue base = Value.ILLEGAL;
             if (encoding.base != 0) {
-                base = newVariable(Kind.Long);
-                append(new AMD64Move.MoveToRegOp(Kind.Long, base, Constant.forLong(encoding.base)));
+                base = emitMove(Constant.forLong(encoding.base));
             }
             append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
             return result;
@@ -565,7 +525,9 @@
 
     @Override
     protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
-        if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
+        if (src instanceof Constant) {
+            return new AMD64HotSpotMove.HotSpotLoadConstantOp(dst, (Constant) src);
+        } else if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
             if (isRegister(src) || isStackSlot(dst)) {
                 return new MoveFromRegOp(Kind.Int, dst, src);
             } else {
@@ -576,7 +538,6 @@
         }
     }
 
-    @Override
     public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
         PlatformKind kind = newValue.getPlatformKind();
         assert kind == expectedValue.getPlatformKind();
@@ -592,4 +553,122 @@
         append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
         return result;
     }
+
+    public Value emitAtomicReadAndAdd(Value address, Value delta) {
+        PlatformKind kind = delta.getPlatformKind();
+        Kind memKind = getMemoryKind(kind);
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
+        return result;
+    }
+
+    public static Register asNarrowReg(Value value) {
+        if (value.getPlatformKind() != NarrowOopStamp.NarrowOop) {
+            throw new InternalError("needed NarrowOop got: " + value.getKind());
+        } else {
+            return asRegister(value);
+        }
+    }
+
+    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        PlatformKind kind = newValue.getPlatformKind();
+        Kind memKind = getMemoryKind(kind);
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
+        return result;
+    }
+
+    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
+        @Alive({COMPOSITE}) protected AMD64AddressValue x;
+        @Use({CONST, REG}) protected Value y;
+        @State protected LIRFrameState state;
+
+        public CompareMemoryCompressedOp(AMD64AddressValue x, Value y, LIRFrameState state) {
+            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        protected void verify() {
+            assert y instanceof Constant || y.getPlatformKind() == NarrowOopStamp.NarrowOop;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            if (y instanceof Constant) {
+                Constant constant = (Constant) y;
+                if (constant.isNull()) {
+                    masm.cmpl(x.toAddress(), 0);
+                } else {
+                    if (y.getKind() == Kind.Object) {
+                        crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
+                    } else if (y.getKind() == Kind.Long) {
+                        crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere();
+                    }
+                    masm.cmpl(x.toAddress(), 0xdeaddead);
+                }
+            } else {
+                masm.cmpl(asNarrowReg(y), x.toAddress());
+            }
+        }
+    }
+
+    protected void emitCompareBranchMemoryCompressed(Value left, Value right, Condition cond, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability, LIRFrameState state) {
+        boolean mirrored = false;
+        if (left instanceof AMD64AddressValue) {
+            append(new CompareMemoryCompressedOp((AMD64AddressValue) left, right, state));
+        } else {
+            assert right instanceof AMD64AddressValue;
+            append(new CompareMemoryCompressedOp((AMD64AddressValue) right, left, state));
+            mirrored = true;
+        }
+
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+    }
+
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        assert address.getKind() == Kind.Object : address + " - " + address.getKind() + " not an object!";
+        append(new AMD64Move.NullCheckOp(load(address), state));
+    }
+
+    @Override
+    protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) {
+        if (right instanceof HotSpotConstant) {
+            append(new AMD64HotSpotCompare.HotSpotCompareConstantOp(left, (Constant) right));
+        } else if (cmpKind == NarrowOopStamp.NarrowOop) {
+            append(new AMD64HotSpotCompare.HotSpotCompareNarrowOp(left, asAllocatable(right)));
+        } else {
+            super.emitCompareOp(cmpKind, left, right);
+        }
+    }
+
+    @Override
+    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Constant value, LIRFrameState state) {
+        if (value instanceof HotSpotConstant) {
+            append(new AMD64HotSpotCompare.HotSpotCompareMemoryConstantOp(kind, address, value, state));
+        } else {
+            super.emitCompareMemoryConOp(kind, address, value, state);
+        }
+    }
+
+    @Override
+    public boolean canInlineConstant(Constant c) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return true;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return HotSpotObjectConstant.isCompressed(c);
+        } else {
+            return super.canInlineConstant(c);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -24,19 +24,50 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Pops the current frame off the stack including the return address.
+ * Pops the current frame off the stack including the return address and restores the return
+ * registers stored on the stack.
  */
 @Opcode("LEAVE_CURRENT_STACK_FRAME")
 final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp {
 
+    private final SaveRegistersOp saveRegisterOp;
+
+    public AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) {
+        this.saveRegisterOp = saveRegisterOp;
+    }
+
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointer = registerConfig.getFrameRegister();
+
+        // Restore integer result register.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+        masm.movptr(rdx, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(rdx) * stackSlotSize));
+
+        // Restore float result register.
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
+
+        /*
+         * All of the register save area will be popped of the stack. Only the return address
+         * remains.
+         */
         leaveFrameAndRestoreRbp(crb, masm);
-        masm.addq(rsp, crb.target.arch.getReturnAddressSize());
+
+        // Remove return address.
+        masm.addq(stackPointer, crb.target.arch.getReturnAddressSize());
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,13 +26,14 @@
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Pops the current frame off the stack including the return address.
+ * Pops a deoptimized stack frame off the stack including the return address.
  */
 @Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
 final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp {
@@ -47,9 +48,13 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        masm.addq(rsp, asRegister(frameSize));
-        // Restore the frame pointer before stack bang because if a stack overflow is thrown it
-        // needs to be pushed (and preserved).
+        Register stackPointer = crb.frameMap.registerConfig.getFrameRegister();
+        masm.addq(stackPointer, asRegister(frameSize));
+
+        /*
+         * Restore the frame pointer before stack bang because if a stack overflow is thrown it
+         * needs to be pushed (and preserved).
+         */
         masm.movq(rbp, asRegister(framePointer));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -22,42 +22,58 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.amd64.AMD64.*;
-
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
  * Emits code that leaves a stack frame which is tailored to call the C++ method
- * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
  */
 @Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction {
 
-    private final Register thread;
+    private final Register threadRegister;
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
     private final int threadLastJavaFpOffset;
 
-    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset) {
-        this.thread = thread;
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, SaveRegistersOp saveRegisterOp) {
+        this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.saveRegisterOp = saveRegisterOp;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+
         // Restore stack pointer.
-        masm.movq(rsp, new AMD64Address(thread, threadLastJavaSpOffset));
+        masm.movq(stackPointerRegister, new AMD64Address(threadRegister, threadLastJavaSpOffset));
 
         // Clear last Java frame values.
-        masm.movslq(new AMD64Address(thread, threadLastJavaSpOffset), 0);
-        masm.movslq(new AMD64Address(thread, threadLastJavaPcOffset), 0);
-        masm.movslq(new AMD64Address(thread, threadLastJavaFpOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaPcOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaFpOffset), 0);
+
+        // Restore return values.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -31,12 +31,12 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.amd64.*;
 
-public class AMD64HotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     private AMD64ConvertSnippets.Templates convertSnippets;
 
-    public AMD64HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
-        super(runtime, metaAccess, foreignCalls, registers);
+    public AMD64HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, TargetDescription target) {
+        super(runtime, metaAccess, foreignCalls, registers, target);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.hotspot.amd64;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.data.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Specialized code gen for comparison with compressed memory.
- */
-
-public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole {
-    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
-        @Alive({COMPOSITE}) protected AMD64AddressValue x;
-        @Use({CONST}) protected Value y;
-        @State protected LIRFrameState state;
-
-        public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) {
-            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
-            this.x = x;
-            this.y = y;
-            this.state = state;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            Constant constant = (Constant) y;
-            if (constant.isNull()) {
-                masm.cmpl(x.toAddress(), 0);
-            } else {
-                if (y.getKind() == Kind.Object) {
-                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
-                } else if (y.getKind() == Kind.Long) {
-                    crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-                if (state != null) {
-                    crb.recordImplicitException(masm.position(), state);
-                }
-                masm.cmpl(x.toAddress(), 0xdeaddead);
-            }
-        }
-    }
-
-    AMD64HotSpotMemoryPeephole(AMD64NodeLIRBuilder gen) {
-        super(gen);
-    }
-
-    @Override
-    protected Kind getMemoryKind(Access access) {
-        PlatformKind kind = gen.getLIRGenerator().getPlatformKind(access.asNode().stamp());
-        if (kind == NarrowOopStamp.NarrowOop) {
-            return Kind.Int;
-        } else {
-            return (Kind) kind;
-        }
-    }
-
-    @Override
-    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
-                    double trueLabelProbability) {
-        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
-            ValueNode other = selectOtherInput(left, right, access);
-            Kind kind = getMemoryKind(access);
-
-            if (other.isConstant() && kind == Kind.Object && access.isCompressible()) {
-                ensureEvaluated(other);
-                gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access)));
-                Condition finalCondition = right == access ? cond.mirror() : cond;
-                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            }
-        }
-
-        return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
-    }
-}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Fri May 30 15:09:09 2014 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
@@ -36,41 +35,128 @@
 import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.asm.*;
 
 public class AMD64HotSpotMove {
 
-    public static class StoreCompressedConstantOp extends StoreConstantOp {
+    public static class HotSpotLoadConstantOp extends AMD64LIRInstruction implements MoveOp {
+
+        @Def({REG, STACK}) private AllocatableValue result;
+        private final Constant input;
+
+        public HotSpotLoadConstantOp(AllocatableValue result, Constant input) {
+            this.result = result;
+            this.input = input;
+        }
 
-        public StoreCompressedConstantOp(Kind kind, AMD64AddressValue address, Constant input, LIRFrameState state) {
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(input)) {
+                if (isRegister(result)) {
+                    masm.movl(asRegister(result), 0);
+                } else {
+                    assert isStackSlot(result);
+                    masm.movl((AMD64Address) crb.asAddress(result), 0);
+                }
+            } else if (input instanceof HotSpotObjectConstant) {
+                boolean compressed = HotSpotObjectConstant.isCompressed(input);
+                OopData data = new OopData(compressed ? 4 : 8, HotSpotObjectConstant.asObject(input), compressed);
+                if (crb.target.inlineObjects) {
+                    crb.recordInlineDataInCode(data);
+                    if (isRegister(result)) {
+                        if (compressed) {
+                            masm.movl(asRegister(result), 0xDEADDEAD);
+                        } else {
+                            masm.movq(asRegister(result), 0xDEADDEADDEADDEADL);
+                        }
+                    } else {
+                        assert isStackSlot(result);
+                        if (compressed) {
+                            masm.movl((AMD64Address) crb.asAddress(result), 0xDEADDEAD);
+                        } else {
+                            throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                        }
+                    }
+                } else {
+                    if (isRegister(result)) {
+                        AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(data);
+                        if (compressed) {
+                            masm.movl(asRegister(result), address);
+                        } else {
+                            masm.movq(asRegister(result), address);
+                        }
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere("Cannot directly store data patch to memory");
+                    }
+                }
+            } else if (input instanceof HotSpotMetaspaceConstant) {
+                assert input.getKind() == Kind.Int || input.getKind() == Kind.Long;
+                boolean compressed = input.getKind() == Kind.Int;
+                MetaspaceData data = new MetaspaceData(compressed ? 4 : 8, input.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(input), compressed);
+                crb.recordInlineDataInCode(data);
+                if (isRegister(result)) {
+                    if (compressed) {
+                        masm.movl(asRegister(result), input.asInt());
+                    } else {
+                        masm.movq(asRegister(result), input.asLong());
+                    }
+                } else {
+                    assert isStackSlot(result);
+                    if (compressed) {
+                        masm.movl((AMD64Address) crb.asAddress(result), input.asInt());
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                    }
+                }
+            } else {
+                AMD64Move.move(crb, masm, result, input);
+            }
+        }
+
+        public Value getInput() {
+            return input;
+        }
+
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static class HotSpotStoreConstantOp extends StoreConstantOp {
+
+        public HotSpotStoreConstantOp(Kind kind, AMD64AddressValue address, Constant input, LIRFrameState state) {
             super(kind, address, input, state);
         }
 
         @Override
         public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (kind == Kind.Long) {
-                if (NumUtil.isInt(input.asLong())) {
-                    if (input instanceof HotSpotMetaspaceConstant) {
-                        crb.recordInlineDataInCode(new MetaspaceData(0, input.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(input), true));
-                    }
-                    masm.movl(address.toAddress(), (int) input.asLong());
-                } else {
-                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                }
-            } else if (kind == Kind.Object) {
-                if (input.isNull()) {
-                    masm.movl(address.toAddress(), 0);
-                } else if (crb.target.inlineObjects) {
+            if (input.isNull() && kind == Kind.Int) {
+                // compressed null
+                masm.movl(address.toAddress(), 0);
+            } else if (input instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed(input) && crb.target.inlineObjects) {
+                    // compressed oop
                     crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(input), true));
                     masm.movl(address.toAddress(), 0xDEADDEAD);
                 } else {
+                    // uncompressed oop
+                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                }
+            } else if (input instanceof HotSpotMetaspaceConstant) {
+                if (input.getKind() == Kind.Int) {
+                    // compressed metaspace pointer
+                    crb.recordInlineDataInCode(new MetaspaceData(0, input.asInt(), HotSpotMetaspaceConstant.getMetaspaceObject(input), true));
+                    masm.movl(address.toAddress(), input.asInt());
+                } else {
+                    // uncompressed metaspace pointer
                     throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
                 }
             } else {
-                throw GraalInternalError.shouldNotReachHere("Attempt to store compressed constant of wrong type.");
+                // primitive value
+                super.emitMemAccess(crb, masm);
             }
         }
     }
@@ -156,175 +242,6 @@
         }
     }
 
-    public static class LoadCompressedPointer extends LoadOp {
-
-        private final CompressEncoding encoding;
-        @Temp({REG, ILLEGAL}) protected AllocatableValue scratch;
-
-        public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, AMD64AddressValue address, LIRFrameState state, CompressEncoding encoding) {
-            super(kind, result, address, state);
-            this.encoding = encoding;
-            this.scratch = scratch != null ? scratch : Value.ILLEGAL;
-            assert kind == Kind.Object || kind == Kind.Long;
-        }
-
-        @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            Register resRegister = asRegister(result);
-            if (kind == Kind.Object) {
-                masm.movl(resRegister, address.toAddress());
-                decodePointer(masm, resRegister, asRegister(scratch), encoding);
-            } else {
-                Register base = scratch.equals(Value.ILLEGAL) ? null : asRegister(scratch);
-                decodeKlassPointer(masm, resRegister, base, address.toAddress(), encoding);
-            }
-        }
-    }
-
-    public static class StoreCompressedPointer extends AMD64LIRInstruction {
-
-        protected final Kind kind;
-        private final Register heapBaseReg;
-        private final CompressEncoding encoding;
-        @Temp({REG}) private AllocatableValue scratch;
-        @Alive({REG}) protected Value input;
-        @Alive({COMPOSITE}) protected AMD64AddressValue address;
-        @State protected LIRFrameState state;
-
-        public StoreCompressedPointer(Kind kind, AMD64AddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, CompressEncoding encoding, Register heapBaseReg) {
-            this.encoding = encoding;
-            this.heapBaseReg = heapBaseReg;
-            this.scratch = scratch;
-            this.kind = kind;
-            this.address = address;
-            this.state = state;
-            this.input = input;
-            assert kind == Kind.Object || kind == Kind.Long;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            masm.movq(asRegister(scratch), asRegister(input));
-            if (kind == Kind.Long && (encoding.base & 0xffffffffL) == 0 && encoding.shift == 0) {
-                // Compressing the pointer won't change the low 32 bits, so just store it
-                masm.movl(address.toAddress(), asRegister(input));
-            } else if (kind == Kind.Object) {
-                encodePointer(masm, asRegister(scratch), heapBaseReg, encoding);
-            } else {
-                masm.movq(asRegister(scratch), asRegister(input));
-                if (kind == Kind.Object) {
-                    encodePointer(masm, asRegister(scratch), heapBaseReg, encoding);
-                } else {
-                    assert !asRegister(scratch).equals(heapBaseReg) : "need to restore value otherwise";
-                    encodeKlassPointer(masm, asRegister(scratch), heapBaseReg, encoding);
-                }
-                if (state != null) {
-                    crb.recordImplicitException(masm.position(), state);
-                }
-                masm.movl(address.toAddress(), asRegister(scratch));
-            }
-            if (state != null) {
-                crb.recordImplicitException(masm.position(), state);
-            }
-            masm.movl(address.toAddress(), asRegister(scratch));
-        }
-    }
-
-    @Opcode("CAS")
-    public static class CompareAndSwapCompressedOp extends AMD64LIRInstruction {
-
-        @Def protected AllocatableValue result;
-        @Alive({COMPOSITE}) protected AMD64AddressValue address;
-        @Alive protected AllocatableValue cmpValue;
-        @Alive protected AllocatableValue newValue;
-        @Temp({REG}) protected AllocatableValue scratch;
-
-        private CompressEncoding encoding;
-        private final Register heapBaseReg;
-
-        public CompareAndSwapCompressedOp(AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue, AllocatableValue scratch,
-                        CompressEncoding encoding, Register heapBaseReg) {
-            this.heapBaseReg = heapBaseReg;
-            this.scratch = scratch;
-            this.encoding = encoding;
-            this.result = result;
-            this.address = address;
-            this.cmpValue = cmpValue;
-            this.newValue = newValue;
-            assert cmpValue.getKind() == Kind.Object;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            compareAndSwapCompressed(crb, masm, result, address, cmpValue, newValue, scratch, encoding, heapBaseReg);
-        }
-    }
-
-    protected static void compareAndSwapCompressed(CompilationResultBuilder crb, AMD64MacroAssembler masm, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue,
-                    AllocatableValue newValue, AllocatableValue scratch, CompressEncoding encoding, Register heapBaseReg) {
-        assert AMD64.rax.equals(asRegister(cmpValue)) && AMD64.rax.equals(asRegister(result));
-        final Register scratchRegister = asRegister(scratch);
-        final Register cmpRegister = asRegister(cmpValue);
-        final Register newRegister = asRegister(newValue);
-        Register heapBase = heapBaseReg;
-        encodePointer(masm, cmpRegister, heapBase, encoding);
-        masm.movq(scratchRegister, newRegister);
-        encodePointer(masm, scratchRegister, heapBase, encoding);
-        if (crb.target.isMP) {
-            masm.lock();
-        }
-        masm.cmpxchgl(scratchRegister, address.toAddress());
-    }
-
-    private static void encodePointer(AMD64MacroAssembler masm, Register scratchRegister, Register heapBaseRegister, CompressEncoding encoding) {
-        // If the base is zero, the uncompressed address has to be shifted right
-        // in order to be compressed.
-        if (encoding.base == 0) {
-            if (encoding.shift != 0) {
-                assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
-                masm.shrq(scratchRegister, encoding.alignment);
-            }
-        } else {
-            // Otherwise the heap base, which resides always in register 12, is subtracted
-            // followed by right shift.
-            masm.testq(scratchRegister, scratchRegister);
-            // If the stored reference is null, move the heap to scratch
-            // register and then calculate the compressed oop value.
-            masm.cmovq(ConditionFlag.Equal, scratchRegister, heapBaseRegister);
-            masm.subq(scratchRegister, heapBaseRegister);
-            masm.shrq(scratchRegister, encoding.alignment);
-        }
-    }
-
-    public static void decodePointer(AMD64MacroAssembler masm, Register resRegister, Register heapBaseRegister, CompressEncoding encoding) {
-        // If the base is zero, the compressed address has to be shifted left
-        // in order to be uncompressed.
-        if (encoding.base == 0) {
-            if (encoding.shift != 0) {
-                assert encoding.alignment == encoding.shift : "Decode algorithm is wrong";
-                masm.shlq(resRegister, encoding.alignment);
-            }
-        } else {
-            Label done = new Label();
-            masm.shlq(resRegister, encoding.alignment);
-            masm.jccb(ConditionFlag.Equal, done);
-            // Otherwise the heap base is added to the shifted address.
-            masm.addq(resRegister, heapBaseRegister);
-            masm.bind(done);
-        }
-    }
-
-    private static void encodeKlassPointer(AMD64MacroAssembler masm, Register scratchRegister, Register heapBaseRegister, CompressEncoding encoding) {
-        if (encoding.base != 0) {
-            masm.movq(heapBaseRegister, encoding.base);
-            masm.subq(scratchRegister, heapBaseRegister);
-        }
-        if (encoding.shift != 0) {
-            assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
-            masm.shrq(scratchRegister, encoding.alignment);
-        }
-    }
-
     public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) {
         masm.movl(register, address);
         if (encoding.shift != 0) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -26,26 +26,30 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotLIRGenerator.SaveRbp;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
@@ -53,9 +57,68 @@
  */
 public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    private static ValueNode filterCompression(ValueNode node) {
+        ValueNode result = node;
+        if (result instanceof PiNode) {
+            result = ((PiNode) result).getOriginalNode();
+        }
+        if (result instanceof CompressionNode) {
+            result = ((CompressionNode) result).getInput();
+        }
+        return result;
+    }
+
+    private void emitCompareMemoryObject(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
+        Value value;
+        // This works by embedding the compressed form for constants, so force a constant instead of
+        // respecting what operand() would return.
+        if (valueNode.isConstant()) {
+            value = valueNode.asConstant();
+        } else {
+            value = gen.load(operand(valueNode));
+        }
+        AMD64AddressValue address = makeAddress(access);
+
+        Condition cond = compare.condition();
+        Value left;
+        Value right;
+        if (access == filterCompression(compare.x())) {
+            left = value;
+            right = address;
+        } else {
+            assert access == filterCompression(compare.y());
+            left = address;
+            right = value;
+            cond = cond.mirror();
+        }
+
+        LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+        double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+        getGen().emitCompareBranchMemoryCompressed(left, right, cond, trueLabel, falseLabel, trueLabelProbability, getState(access));
+    }
+
+    private void emitCompareCompressedMemory(Kind kind, IfNode ifNode, ValueNode valueNode, CompressionNode compress, ConstantLocationNode location, Access access, CompareNode compare) {
+        Value value = gen.load(operand(valueNode));
+        AMD64AddressValue address = makeCompressedAddress(compress, location);
+        Condition cond = compare.condition();
+        if (access == filterCompression(compare.x())) {
+            cond = cond.mirror();
+        } else {
+            assert access == filterCompression(compare.y());
+        }
+
+        LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+        double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+        getGen().emitCompareBranchMemory(kind, value, address, getState(access), cond, compare.unorderedIsTrue(), trueLabel, falseLabel, trueLabelProbability);
+    }
+
+    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         super(graph, gen);
-        memoryPeephole = new AMD64HotSpotMemoryPeephole(this);
+        assert gen instanceof AMD64HotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((AMD64HotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
     }
 
     private AMD64HotSpotLIRGenerator getGen() {
@@ -71,7 +134,7 @@
     }
 
     @Override
-    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
         HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMap(), Kind.Long);
         return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
     }
@@ -107,7 +170,7 @@
 
     @Override
     public void visitSafepointNode(SafepointNode i) {
-        LIRFrameState info = gen.state(i);
+        LIRFrameState info = state(i);
         append(new AMD64HotSpotSafepointOp(info, getGen().config, this));
     }
 
@@ -119,7 +182,7 @@
         } else {
             assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
-            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
+            assert !resolvedMethod.isAbstract() : "Cannot make direct call to abstract method.";
             append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
         }
     }
@@ -160,7 +223,7 @@
 
     @Override
     public void visitInfopointNode(InfopointNode i) {
-        if (i.getState() != null && i.getState().bci == FrameState.AFTER_BCI) {
+        if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) {
             Debug.log("Ignoring InfopointNode for AFTER_BCI");
         } else {
             super.visitInfopointNode(i);
@@ -199,4 +262,120 @@
         gen.emitMove(result, raxLocal);
         setResult(x, result);
     }
+
+    boolean canFormCompressedMemory(CompressionNode compress, ConstantLocationNode location) {
+        HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
+        if (config.useCompressedOops && compress.getEncoding().shift <= 3 && NumUtil.isInt(location.getDisplacement())) {
+            PlatformKind objectKind = compress.getInput().stamp().getPlatformKind(getGen());
+            if (objectKind == NarrowOopStamp.NarrowOop || objectKind == Kind.Int && config.narrowKlassBase == config.narrowOopBase) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private AMD64AddressValue makeCompressedAddress(CompressionNode compress, ConstantLocationNode location) {
+        assert canFormCompressedMemory(compress, location);
+        AMD64AddressValue address = getGen().emitAddress(getGen().getProviders().getRegisters().getHeapBaseRegister().asValue(), location.getDisplacement(), operand(compress.getInput()),
+                        1 << compress.getEncoding().shift);
+        return address;
+    }
+
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Pi (Compression Read=access))))")
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Pi (Compression FloatingRead=access))))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Pi (Compression Read=access))))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Pi (Compression FloatingRead=access))))")
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))")
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))")
+    public ComplexMatchResult ifCompareMemoryObject(IfNode root, CompareNode compare, ValueNode value, Access access) {
+        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
+            return builder -> {
+                emitCompareMemoryObject(root, value, access, compare);
+                return null;
+            };
+        }
+        return null;
+    }
+
+    @MatchRule("(If (IntegerEquals=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerLessThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerBelowThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatEquals=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatLessThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerEquals=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerLessThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerBelowThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatEquals=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatLessThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    public ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, CompressionNode compress, ValueNode value, ConstantLocationNode location, Access access) {
+        if (canFormCompressedMemory(compress, location)) {
+            PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp());
+            if (cmpKind instanceof Kind) {
+                Kind kind = (Kind) cmpKind;
+                return builder -> {
+                    emitCompareCompressedMemory(kind, root, value, compress, location, access, compare);
+                    return null;
+                };
+            }
+        }
+        return null;
+    }
+
+    @MatchRule("(IntegerAdd value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerSub value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerMul value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatAdd value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatSub value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatMul value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Or value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Xor value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(And value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerAdd value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerSub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerMul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatAdd value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatSub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatMul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Or value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Xor value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(And value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    public ComplexMatchResult binaryReadCompressed(BinaryNode root, ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        if (canFormCompressedMemory(compress, location)) {
+            AMD64Arithmetic op = getOp(root, access);
+            if (op != null) {
+                return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeCompressedAddress(compress, location),
+                                getState(access));
+            }
+        }
+        return null;
+    }
+
+    @MatchRule("(Read (Compression=compress object) ConstantLocation=location)")
+    @MatchRule("(Read (Pi (Compression=compress object)) ConstantLocation=location)")
+    @MatchRule("(FloatingRead (Compression=compress object) ConstantLocation=location)")
+    @MatchRule("(FloatingRead (Pi (Compression=compress object)) ConstantLocation=location)")
+    public ComplexMatchResult readCompressed(Access root, CompressionNode compress, ConstantLocationNode location) {
+        if (canFormCompressedMemory(compress, location)) {
+            PlatformKind readKind = getGen().getPlatformKind(root.asNode().stamp());
+            return builder -> {
+                return getGen().emitLoad(readKind, makeCompressedAddress(compress, location), getState(root));
+            };
+        }
+        return null;
+    }
+
+    @MatchRule("(Write (Compression=compress object) ConstantLocation=location value)")
+    @MatchRule("(Write (Pi (Compression=compress object)) ConstantLocation=location value)")
+    public ComplexMatchResult writeCompressed(Access root, CompressionNode compress, ConstantLocationNode location, ValueNode value) {
+        if (canFormCompressedMemory(compress, location)) {
+            PlatformKind readKind = getGen().getPlatformKind(value.asNode().stamp());
+            return builder -> {
+                getGen().emitStore(readKind, makeCompressedAddress(compress, location), operand(value), getState(root));
+                return null;
+            };
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.amd64.AMD64.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
@@ -34,7 +34,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.phases.*;
 
 public class AMD64HotSpotRegisterConfig implements RegisterConfig {
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Fri May 30 15:09:09 2014 +0200
@@ -24,7 +24,7 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.asm.NumUtil.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,13 +26,12 @@
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.amd64.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRGenLowerable {
+public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
 
     private final Constant functionPointer;
     @Input private final NodeInputList<ValueNode> args;
@@ -44,7 +43,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder generator) {
+    public void generate(NodeLIRBuilderTool generator) {
         AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
         Value[] parameter = new Value[args.count()];
         JavaType[] parameterTypes = new JavaType[args.count()];
@@ -55,7 +54,7 @@
         ResolvedJavaType returnType = stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess());
         CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes,
                         generator.getLIRGeneratorTool().target(), false);
-        ((AMD64LIRGenerator) gen.getLIRGeneratorTool()).emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
+        gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
         if (this.getKind() != Kind.Void) {
             generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64UncommonTrapStub.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.amd64.AMD64.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+
+final class AMD64UncommonTrapStub extends UncommonTrapStub {
+
+    private RegisterConfig registerConfig;
+
+    public AMD64UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        Register[] allocatable = new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14};
+        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), allocatable);
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Fri May 30 15:09:09 2014 +0200
@@ -32,6 +32,9 @@
 
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.Map.Entry;
+import java.util.function.*;
+import java.util.stream.*;
 
 import com.amd.okra.*;
 import com.oracle.graal.api.code.*;
@@ -48,7 +51,7 @@
 import com.oracle.graal.asm.hsail.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.gpu.*;
@@ -60,18 +63,20 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizingOp;
-import com.oracle.graal.lir.hsail.HSAILMove.AtomicGetAndAddOp;
+import com.oracle.graal.lir.hsail.HSAILMove.AtomicReadAndAddOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.virtual.nodes.*;
 
 /**
  * HSAIL specific backend.
@@ -144,7 +149,21 @@
      */
     public HotSpotNmethod compileAndInstallKernel(Method method) {
         ResolvedJavaMethod javaMethod = getProviders().getMetaAccess().lookupJavaMethod(method);
-        return installKernel(javaMethod, compileKernel(javaMethod, true));
+        HotSpotNmethod nm = installKernel(javaMethod, compileKernel(javaMethod, true));
+        try (Scope s = Debug.scope("HostCodeGen")) {
+            if (Debug.isLogEnabled()) {
+                DisassemblerProvider dis = getRuntime().getHostBackend().getDisassembler();
+                if (dis != null) {
+                    String disasm = dis.disassemble(nm);
+                    Debug.log("host code generated for %s%n%s", javaMethod, disasm);
+                } else {
+                    Debug.log("host code disassembler is null");
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        return nm;
     }
 
     /**
@@ -252,7 +271,7 @@
         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")) {
+            try (Scope ds = Debug.scope("GeneratingHostGraph", new DebugDumpScope("HostGraph"))) {
                 HotSpotBackend hostBackend = getRuntime().getHostBackend();
                 JavaType[] parameterTypes = new JavaType[hostGraph.getNodes(ParameterNode.class).count()];
                 Debug.log("Param count: %d", parameterTypes.length);
@@ -273,7 +292,8 @@
             }
         }
 
-        HotSpotNmethod code = new HotSpotNmethod(javaMethod, hsailCode.getName(), false, true);
+        HSAILHotSpotNmethod code = new HSAILHotSpotNmethod(javaMethod, hsailCode.getName(), false, true);
+        code.setOopMapArray(hsailCode.getOopMapArray());
         HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(getTarget(), javaMethod, compilationResult);
         CodeInstallResult result = getRuntime().getCompilerToVM().installCode(compiled, code, null);
         if (result != CodeInstallResult.OK) {
@@ -296,14 +316,12 @@
         // from host code
         result.setTotalFrameSize(hostCode.getTotalFrameSize());
         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);
+            result.recordMark(mark.pcOffset, mark.id);
         }
         for (ExceptionHandler handler : hostCode.getExceptionHandlers()) {
             result.recordExceptionHandler(handler.pcOffset, handler.handlerPos);
@@ -359,11 +377,21 @@
         if (!deviceInitialized) {
             throw new GraalInternalError("Cannot execute GPU kernel if device is not initialized");
         }
-        Object[] oopsSaveArea = new Object[maxDeoptIndex * 16];
-        return executeKernel0(kernel, jobSize, args, oopsSaveArea, donorThreadPool.get().getThreads(), HsailAllocBytesPerWorkitem.getValue());
+        int[] oopMapArray = ((HSAILHotSpotNmethod) kernel).getOopMapArray();
+        Object[] oopsSaveArea;
+        if (getRuntime().getConfig().useHSAILDeoptimization) {
+            int saveAreaCounts = OopMapArrayBuilder.getSaveAreaCounts(oopMapArray);
+            int numDRegs = (saveAreaCounts >> 8) & 0xff;
+            int numStackSlots = (saveAreaCounts >> 16);
+            // pessimistically assume that any of the DRegs or stackslots could be oops
+            oopsSaveArea = new Object[maxDeoptIndex * (numDRegs + numStackSlots)];
+        } else {
+            oopsSaveArea = null;
+        }
+        return executeKernel0(kernel, jobSize, args, oopsSaveArea, donorThreadPool.get().getThreads(), HsailAllocBytesPerWorkitem.getValue(), oopMapArray);
     }
 
-    private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Object[] oopsSave, Thread[] donorThreads, int allocBytesPerWorkitem)
+    private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Object[] oopsSave, Thread[] donorThreads, int allocBytesPerWorkitem, int[] oopMapArray)
                     throws InvalidInstalledCodeException;
 
     /**
@@ -375,17 +403,17 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new HSAILHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, ResolvedJavaMethod method, Object stub) {
         return new HSAILHotSpotLIRGenerationResult(lir, frameMap);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new HSAILHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
@@ -419,6 +447,22 @@
         }
     }
 
+    static class HSAILHotSpotNmethod extends HotSpotNmethod {
+        private int[] oopMapArray;
+
+        HSAILHotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault, boolean isExternal) {
+            super(method, name, isDefault, isExternal);
+        }
+
+        void setOopMapArray(int[] array) {
+            oopMapArray = array;
+        }
+
+        int[] getOopMapArray() {
+            return oopMapArray;
+        }
+    }
+
     @Override
     protected Assembler createAssembler(FrameMap frameMap) {
         return new HSAILHotSpotAssembler(getTarget());
@@ -445,13 +489,17 @@
         boolean useHSAILDeoptimization = config.useHSAILDeoptimization;
         boolean useHSAILSafepoints = config.useHSAILSafepoints;
 
+        if ((useHSAILSafepoints == true) && (useHSAILDeoptimization == false)) {
+            Debug.log("+UseHSAILSafepoints requires +UseHSAILDeoptimization");
+        }
+
         // see what graph nodes we have to see if we are using the thread register
         // if not, we don't have to emit the code that sets that up
         // maybe there is a better way to do this?
         boolean usesThreadRegister = false;
         search: for (AbstractBlock<?> b : lir.linearScanOrder()) {
             for (LIRInstruction op : lir.getLIRforBlock(b)) {
-                if (op instanceof AtomicGetAndAddOp && ((AtomicGetAndAddOp) op).getAddress().toAddress().getBase().equals(HSAIL.threadRegister)) {
+                if (op instanceof AtomicReadAndAddOp) {
                     usesThreadRegister = true;
                     assert useHSAILDeoptimization : "cannot use thread register if HSAIL deopt support is disabled";
                     break search;
@@ -468,7 +516,7 @@
         // We're subtracting 1 because we're not making the final gid as a parameter.
 
         int nonConstantParamCount = sigParamCount - 1;
-        boolean isStatic = (Modifier.isStatic(method.getModifiers()));
+        boolean isStatic = (method.isStatic());
         // Determine if this is an object lambda.
         boolean isObjectLambda = true;
 
@@ -686,18 +734,71 @@
         asm.emitString(spillsegStringFinal, spillsegDeclarationPosition);
         // Emit the epilogue.
 
-        // TODO: keep track of whether we need it
+        HSAILHotSpotLIRGenerationResult lirGenRes = ((HSAILCompilationResultBuilder) crb).lirGenRes;
+
+        int numSRegs = 0;
+        int numDRegs = 0;
+        int numStackSlotBytes = 0;
         if (useHSAILDeoptimization) {
-            final int offsetToDeoptSaveStates = config.hsailSaveStatesOffset0;
-            final int sizeofKernelDeopt = config.hsailSaveStatesOffset1 - config.hsailSaveStatesOffset0;
+            // get the union of registers and stack slots needed to be saved at the infopoints
+            // while doing this compute the highest register in each category
+            HSAILHotSpotRegisterConfig hsailRegConfig = (HSAILHotSpotRegisterConfig) regConfig;
+            Set<Register> infoUsedRegs = new TreeSet<>();
+            Set<StackSlot> infoUsedStackSlots = new HashSet<>();
+            List<Infopoint> infoList = crb.compilationResult.getInfopoints();
+            Queue<Value[]> workList = new LinkedList<>();
+            for (Infopoint info : infoList) {
+                BytecodeFrame frame = info.debugInfo.frame();
+                while (frame != null) {
+                    workList.add(frame.values);
+                    frame = frame.caller();
+                }
+            }
+            while (!workList.isEmpty()) {
+                Value[] values = workList.poll();
+                for (Value val : values) {
+                    if (isLegal(val)) {
+                        if (isRegister(val)) {
+                            Register reg = asRegister(val);
+                            infoUsedRegs.add(reg);
+                            if (hsailRegConfig.isAllocatableSReg(reg)) {
+                                numSRegs = Math.max(numSRegs, reg.encoding + 1);
+                            } else if (hsailRegConfig.isAllocatableDReg(reg)) {
+                                numDRegs = Math.max(numDRegs, reg.encoding + 1);
+                            }
+                        } else if (isStackSlot(val)) {
+                            StackSlot slot = asStackSlot(val);
+                            Kind slotKind = slot.getKind();
+                            int slotSizeBytes = (slotKind.isObject() ? 8 : slotKind.getByteCount());
+                            int slotOffsetMax = HSAIL.getStackOffsetStart(slot, slotSizeBytes * 8) + slotSizeBytes;
+                            numStackSlotBytes = Math.max(numStackSlotBytes, slotOffsetMax);
+                            infoUsedStackSlots.add(slot);
+                        } else if (isVirtualObject(val)) {
+                            workList.add(((VirtualObject) val).getValues());
+                        } else {
+                            assert isConstant(val) : "Unsupported value: " + val;
+                        }
+                    }
+                }
+            }
+
+            // round up numSRegs to even number so dregs start on aligned boundary
+            numSRegs += (numSRegs & 1);
+
+            // numStackSlots is the number of 8-byte locations used for stack variables
+            int numStackSlots = (numStackSlotBytes + 7) / 8;
+
+            final int offsetToDeoptSaveStates = config.hsailDeoptimizationInfoHeaderSize;
+            final int bytesPerSaveArea = 4 * numSRegs + 8 * numDRegs + 8 * numStackSlots;
+            final int sizeofKernelDeopt = config.hsailKernelDeoptimizationHeaderSize + config.hsailFrameHeaderSize + bytesPerSaveArea;
             final int offsetToNeverRanArray = config.hsailNeverRanArrayOffset;
             final int offsetToDeoptNextIndex = config.hsailDeoptNextIndexOffset;
             final int offsetToDeoptimizationWorkItem = config.hsailDeoptimizationWorkItem;
             final int offsetToDeoptimizationReason = config.hsailDeoptimizationReason;
-            final int offsetToDeoptimizationFrame = config.hsailDeoptimizationFrame;
+            final int offsetToDeoptimizationFrame = config.hsailKernelDeoptimizationHeaderSize;
             final int offsetToFramePc = config.hsailFramePcOffset;
             final int offsetToNumSaves = config.hsailFrameNumSRegOffset;
-            final int offsetToSaveArea = config.hsailFrameSaveAreaOffset;
+            final int offsetToSaveArea = config.hsailFrameHeaderSize;
 
             AllocatableValue scratch64 = HSAIL.d16.asValue(wordKind);
             AllocatableValue cuSaveAreaPtr = HSAIL.d17.asValue(wordKind);
@@ -708,7 +809,6 @@
             AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
             AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
             AllocatableValue workidreg = HSAIL.s35.asValue(Kind.Int);
-            AllocatableValue dregOopMapReg = HSAIL.dregOopMapReg.asValue(Kind.Int);
 
             HSAILAddress deoptNextIndexAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptNextIndex).toAddress();
             HSAILAddress neverRanArrayAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToNeverRanArray).toAddress();
@@ -769,8 +869,6 @@
             // 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);
@@ -778,58 +876,61 @@
             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);
+
+            asm.emitComment("// store regCounts (" + numSRegs + " $s registers, " + numDRegs + " $d registers, " + numStackSlots + " stack slots)");
+            asm.emitStore(Kind.Int, Constant.forInt(numSRegs + (numDRegs << 8) + (numStackSlots << 16)), regCountsAddr);
 
-            // get the union of registers needed to be saved at the infopoints
-            boolean[] infoUsedRegs = new boolean[HSAIL.threadRegister.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 thru the usedValues storing each of the registers that are used.
+            // we always store in a fixed location, even if some registers are skipped
+            asm.emitComment("// store used regs");
+            for (Register reg : infoUsedRegs) {
+                if (hsailRegConfig.isAllocatableSReg(reg)) {
+                    // 32 bit registers
+                    Kind kind = Kind.Int;
+                    int ofst = offsetToSaveArea + reg.encoding * 4;
+                    HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
+                    AllocatableValue regValue = reg.asValue(kind);
+                    asm.emitStore(kind, regValue, addr);
+                } else if (hsailRegConfig.isAllocatableDReg(reg)) {
+                    // 64 bit registers
+                    Kind kind = Kind.Long;
+                    // d reg ofst starts past the 32 sregs
+                    int ofst = offsetToSaveArea + (numSRegs * 4) + reg.encoding * 8;
+                    HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
+                    AllocatableValue regValue = reg.asValue(kind);
+                    asm.emitStore(kind, regValue, addr);
+                } else {
+                    throw GraalInternalError.unimplemented();
                 }
             }
 
-            // 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;
+            // loop thru the usedStackSlots creating instructions to save in the save area
+            if (numStackSlotBytes > 0) {
+                asm.emitComment("// store stack slots (uses " + numStackSlotBytes + " bytes)");
+                for (StackSlot slot : infoUsedStackSlots) {
+                    asm.emitComment("// store " + slot);
+                    Kind kind = slot.getKind();
+                    int sizeInBits = (kind.isObject() || kind.getByteCount() == 8 ? 64 : 32);
+                    int ofst = offsetToSaveArea + (numSRegs * 4) + (numDRegs * 8) + HSAIL.getStackOffsetStart(slot, sizeInBits);
                     HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
-                    AllocatableValue sregValue = sreg.asValue(kind);
-                    asm.emitStore(kind, sregValue, addr);
+                    if (sizeInBits == 64) {
+                        asm.emitSpillLoad(kind, scratch64, slot);
+                        asm.emitStore(kind, scratch64, addr);
+                    } else {
+                        asm.emitSpillLoad(kind, scratch32, slot);
+                        asm.emitStore(kind, scratch32, 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();
+            // build the oopMap Array
+            int[] oopMapArray = new OopMapArrayBuilder().build(infoList, numSRegs, numDRegs, numStackSlots, hsailRegConfig);
+            ((ExternalCompilationResult) crb.compilationResult).setOopMapArray(oopMapArray);
         } else {
             // Deoptimization is explicitly off, so emit simple return
             asm.emitString0(asm.getDeoptLabelName() + ":\n");
@@ -840,11 +941,117 @@
         asm.emitString0("}; \n");
 
         ExternalCompilationResult compilationResult = (ExternalCompilationResult) crb.compilationResult;
-        HSAILHotSpotLIRGenerationResult lirGenRes = ((HSAILCompilationResultBuilder) crb).lirGenRes;
-        compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), config));
+        if (useHSAILDeoptimization) {
+            compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), config, numSRegs, numDRegs));
+        }
     }
 
-    private static StructuredGraph prepareHostGraph(ResolvedJavaMethod method, List<DeoptimizingOp> deopts, HotSpotProviders providers, HotSpotVMConfig config) {
+    private static class OopMapArrayBuilder {
+        // oopMapArray struct
+        // int bytesPerSaveArea; (not strictly part of oopsmap but convenient to put here)
+        // int intsPerInfopoint;
+        static final int SAVEAREACOUNTS_OFST = 0;
+        static final int INTSPERINFOPOINT_OFST = 1;
+        static final int HEADERSIZE = 2;
+        // for each infopoint:
+        // int deoptId
+        // one or more ints of bits for the oopmap
+
+        private int[] array;
+        private int intsPerInfopoint;
+
+        int[] build(List<Infopoint> infoList, int numSRegs, int numDRegs, int numStackSlots, HSAILHotSpotRegisterConfig hsailRegConfig) {
+            // we are told that infoList is always sorted
+            // each infoPoint can have a different oopMap
+
+            // since numStackSlots is the number of 8-byte stack slots used, it is an upper limit on
+            // the number of oop stack slots
+            int bitsPerInfopoint = numDRegs + numStackSlots;
+            int intsForBits = (bitsPerInfopoint + 31) / 32;
+            int numInfopoints = infoList.size();
+            intsPerInfopoint = intsForBits + 1;  // +1 for the pcoffset
+            int arraySize = HEADERSIZE + (numInfopoints * intsPerInfopoint);
+            array = new int[arraySize];
+            array[INTSPERINFOPOINT_OFST] = intsPerInfopoint;
+            // compute saveAreaCounts
+            int saveAreaCounts = (numSRegs & 0xff) + (numDRegs << 8) + (numStackSlots << 16);
+            array[SAVEAREACOUNTS_OFST] = saveAreaCounts;
+
+            // loop thru the infoList
+            int infoIndex = 0;
+            for (Infopoint info : infoList) {
+                setOopMapPcOffset(infoIndex, info.pcOffset);
+                BytecodeFrame frame = info.debugInfo.frame();
+                while (frame != null) {
+                    for (int i = 0; i < frame.numLocals + frame.numStack; i++) {
+                        Value val = frame.values[i];
+                        if (isLegal(val)) {
+                            if (isRegister(val)) {
+                                Register reg = asRegister(val);
+                                if (val.getKind().isObject()) {
+                                    assert (hsailRegConfig.isAllocatableDReg(reg));
+                                    int bitIndex = reg.encoding();
+                                    setOopMapBit(infoIndex, bitIndex);
+                                }
+                            } else if (isStackSlot(val)) {
+                                StackSlot slot = asStackSlot(val);
+                                if (val.getKind().isObject()) {
+                                    assert (HSAIL.getStackOffsetStart(slot, 64) % 8 == 0);
+                                    int bitIndex = numDRegs + HSAIL.getStackOffsetStart(slot, 64) / 8;
+                                    setOopMapBit(infoIndex, bitIndex);
+                                }
+                            }
+                        }
+                    }
+                    frame = frame.caller();
+                }
+                infoIndex++;
+            }
+            try (Scope s = Debug.scope("CodeGen")) {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("numSRegs=%d, numDRegs=%d, numStackSlots=%d", numSRegs, numDRegs, numStackSlots);
+                    // show infopoint oopmap details
+                    for (infoIndex = 0; infoIndex < infoList.size(); infoIndex++) {
+                        String infoString = "Infopoint " + infoIndex + ", pcOffset=" + getOopMapPcOffset(infoIndex) + ",   oopmap=";
+                        for (int i = 0; i < intsForBits; i++) {
+                            infoString += (i != 0 ? ", " : "") + Integer.toHexString(getOopMapBitsAsInt(infoIndex, i));
+                        }
+                        Debug.log(infoString);
+                    }
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+
+            return array;
+        }
+
+        private void setOopMapPcOffset(int infoIndex, int pcOffset) {
+            int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint;
+            array[arrIndex] = pcOffset;
+        }
+
+        private int getOopMapPcOffset(int infoIndex) {
+            int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint;
+            return array[arrIndex];
+        }
+
+        private void setOopMapBit(int infoIndex, int bitIndex) {
+            int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint + 1 + bitIndex / 32;
+            array[arrIndex] |= (1 << (bitIndex % 32));
+        }
+
+        private int getOopMapBitsAsInt(int infoIndex, int intIndex) {
+            int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint + 1 + intIndex;
+            return array[arrIndex];
+        }
+
+        public static int getSaveAreaCounts(int[] array) {
+            return array[SAVEAREACOUNTS_OFST];
+        }
+    }
+
+    private static StructuredGraph prepareHostGraph(ResolvedJavaMethod method, List<DeoptimizingOp> deopts, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs) {
         if (deopts.isEmpty()) {
             return null;
         }
@@ -868,7 +1075,7 @@
             keyProbabilities[i] = 1.0 / deopts.size();
             keys[i] = deopt.getCodeBufferPos();
             assert keys[i] >= 0;
-            branches[i] = createHostDeoptBranch(deopt, hsailFrame, reasonAndAction, speculation, providers, config);
+            branches[i] = createHostDeoptBranch(deopt, hsailFrame, reasonAndAction, speculation, providers, config, numSRegs, numDRegs);
 
             i++;
         }
@@ -892,35 +1099,63 @@
         return BeginNode.begin(vmError);
     }
 
-    private static BeginNode createHostDeoptBranch(DeoptimizingOp deopt, ParameterNode hsailFrame, ValueNode reasonAndAction, ValueNode speculation, HotSpotProviders providers, HotSpotVMConfig config) {
+    private static BeginNode createHostDeoptBranch(DeoptimizingOp deopt, ParameterNode hsailFrame, ValueNode reasonAndAction, ValueNode speculation, HotSpotProviders providers,
+                    HotSpotVMConfig config, int numSRegs, int numDRegs) {
         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));
+        deoptimization.setStateBefore(createFrameState(deopt.getFrameState().topFrame, hsailFrame, providers, config, numSRegs, numDRegs));
         branch.setNext(deoptimization);
         return branch;
     }
 
-    private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config) {
+    private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs) {
+        return createFrameState(lowLevelFrame, hsailFrame, providers, config, numSRegs, numDRegs, new HashMap<VirtualObject, VirtualObjectNode>());
+    }
+
+    private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs,
+                    Map<VirtualObject, VirtualObjectNode> virtualObjects) {
+        FrameState outterFrameState = null;
+        if (lowLevelFrame.caller() != null) {
+            outterFrameState = createFrameState(lowLevelFrame.caller(), hsailFrame, providers, config, numSRegs, numDRegs, virtualObjects);
+        }
         StructuredGraph hostGraph = hsailFrame.graph();
+        Function<? super Value, ? extends ValueNode> lirValueToHirNode = v -> getNodeForValueFromFrame(v, hsailFrame, hostGraph, providers, config, numSRegs, numDRegs, virtualObjects);
         ValueNode[] locals = new ValueNode[lowLevelFrame.numLocals];
         for (int i = 0; i < lowLevelFrame.numLocals; i++) {
-            locals[i] = getNodeForValueFromFrame(lowLevelFrame.getLocalValue(i), hsailFrame, hostGraph, providers, config);
+            locals[i] = lirValueToHirNode.apply(lowLevelFrame.getLocalValue(i));
         }
         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));
+            stack.add(lirValueToHirNode.apply(lowLevelFrame.getStackValue(i)));
         }
         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);
+            locks[i] = lirValueToHirNode.apply(lockValue);
             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));
+        if (outterFrameState != null) {
+            frameState.setOuterFrameState(outterFrameState);
         }
+        Map<VirtualObject, VirtualObjectNode> virtualObjectsCopy;
+        // TODO this could be implemented more efficiently with a mark into the map
+        // unfortunately LinkedHashMap doesn't seem to provide that.
+        List<VirtualObjectState> virtualStates = new ArrayList<>(virtualObjects.size());
+        do {
+            virtualObjectsCopy = new HashMap<>(virtualObjects);
+            virtualStates.clear();
+            for (Entry<VirtualObject, VirtualObjectNode> entry : virtualObjectsCopy.entrySet()) {
+                VirtualObject virtualObject = entry.getKey();
+                VirtualObjectNode virtualObjectNode = entry.getValue();
+                List<ValueNode> fieldValues = Arrays.stream(virtualObject.getValues()).map(lirValueToHirNode).collect(Collectors.toList());
+                virtualStates.add(new VirtualObjectState(virtualObjectNode, fieldValues));
+            }
+            // New virtual objects may have been discovered while processing the previous set.
+            // Wait until a fixed point is reached
+        } while (virtualObjectsCopy.size() < virtualObjects.size());
+        virtualStates.forEach(vos -> frameState.addVirtualObjectMapping(hostGraph.unique(vos)));
         return frameState;
     }
 
@@ -932,21 +1167,23 @@
         throw GraalInternalError.unimplemented();
     }
 
-    private static ValueNode getNodeForValueFromFrame(Value localValue, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) {
+    private static ValueNode getNodeForValueFromFrame(Value localValue, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs,
+                    int numDRegs, Map<VirtualObject, VirtualObjectNode> virtualObjects) {
         ValueNode valueNode;
         if (localValue instanceof Constant) {
             valueNode = ConstantNode.forConstant((Constant) localValue, providers.getMetaAccess(), hostGraph);
         } else if (localValue instanceof VirtualObject) {
-            throw GraalInternalError.unimplemented();
+            valueNode = getNodeForVirtualObjectFromFrame((VirtualObject) localValue, virtualObjects, hostGraph);
         } else if (localValue instanceof StackSlot) {
-            throw GraalInternalError.unimplemented();
+            StackSlot slot = (StackSlot) localValue;
+            valueNode = getNodeForStackSlotFromFrame(slot, localValue.getKind(), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
         } else if (localValue instanceof HotSpotMonitorValue) {
             HotSpotMonitorValue hotSpotMonitorValue = (HotSpotMonitorValue) localValue;
-            return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config);
+            return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs, virtualObjects);
         } else if (localValue instanceof RegisterValue) {
             RegisterValue registerValue = (RegisterValue) localValue;
             int regNumber = registerValue.getRegister().number;
-            valueNode = getNodeForRegisterFromFrame(regNumber, localValue.getKind(), hsailFrame, hostGraph, providers, config);
+            valueNode = getNodeForRegisterFromFrame(regNumber, localValue.getKind(), hsailFrame, hostGraph, providers, config, numSRegs);
         } else if (Value.ILLEGAL.equals(localValue)) {
             valueNode = null;
         } else {
@@ -955,20 +1192,28 @@
         return valueNode;
     }
 
-    private static ValueNode getNodeForRegisterFromFrame(int regNumber, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) {
+    private static ValueNode getNodeForVirtualObjectFromFrame(VirtualObject virtualObject, Map<VirtualObject, VirtualObjectNode> virtualObjects, StructuredGraph hostGraph) {
+        return virtualObjects.computeIfAbsent(virtualObject, vo -> {
+            if (vo.getType().isArray()) {
+                return hostGraph.add(new VirtualArrayNode(vo.getType().getComponentType(), vo.getValues().length));
+            } else {
+                return hostGraph.add(new VirtualInstanceNode(vo.getType(), true));
+            }
+        });
+    }
+
+    private static ValueNode getNodeForRegisterFromFrame(int regNumber, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config,
+                    int numSRegs) {
         ValueNode valueNode;
         LocationNode location;
+        int longSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Long);
+        int intSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Int);
         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);
+            long offset = config.hsailFrameHeaderSize + 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.forInteger(8)));
-            numSRegs = SignExtendNode.convert(numSRegs, StampFactory.forKind(Kind.Byte));
-            location = IndexedLocationNode.create(FINAL_LOCATION, valueKind, offset, numSRegs, hostGraph, 4);
+            long offset = config.hsailFrameHeaderSize + intSize * numSRegs + longSize * (regNumber - HSAIL.d0.number);
+            location = ConstantLocationNode.create(FINAL_LOCATION, valueKind, offset, hostGraph);
         } else {
             throw GraalInternalError.shouldNotReachHere("unknown hsail register: " + regNumber);
         }
@@ -976,4 +1221,18 @@
         return valueNode;
     }
 
+    private static ValueNode getNodeForStackSlotFromFrame(StackSlot slot, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config,
+                    int numSRegs, int numDRegs) {
+        int slotSizeInBits = (valueKind == Kind.Object ? 64 : valueKind.getByteCount() * 8);
+        if ((slotSizeInBits == 32) || (slotSizeInBits == 64)) {
+            int longSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Long);
+            int intSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Int);
+            long offset = config.hsailFrameHeaderSize + (intSize * numSRegs) + (longSize * numDRegs) + HSAIL.getStackOffsetStart(slot, slotSizeInBits);
+            LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, valueKind, offset, hostGraph);
+            ValueNode valueNode = hostGraph.unique(new FloatingReadNode(hsailFrame, location, null, StampFactory.forKind(valueKind)));
+            return valueNode;
+        } else {
+            throw GraalInternalError.shouldNotReachHere("unsupported stack slot kind: " + valueKind);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -36,16 +36,22 @@
 @ServiceProvider(HotSpotBackendFactory.class)
 public class HSAILHotSpotBackendFactory implements HotSpotBackendFactory {
 
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
+                    TargetDescription target) {
+        return new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, target);
+    }
+
     @Override
     public HSAILHotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend hostBackend) {
         HotSpotProviders host = hostBackend.getProviders();
 
         HotSpotRegisters registers = new HotSpotRegisters(HSAIL.threadRegister, Register.None, Register.None);
         HotSpotMetaAccessProvider metaAccess = host.getMetaAccess();
-        HSAILHotSpotCodeCacheProvider codeCache = new HSAILHotSpotCodeCacheProvider(runtime, createTarget());
+        TargetDescription target = createTarget();
+        HSAILHotSpotCodeCacheProvider codeCache = new HSAILHotSpotCodeCacheProvider(runtime, target);
         ConstantReflectionProvider constantReflection = host.getConstantReflection();
         HotSpotForeignCallsProvider foreignCalls = new HSAILHotSpotForeignCallsProvider(runtime, metaAccess, codeCache);
-        LoweringProvider lowerer = new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
+        HotSpotLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
         // Replacements cannot have speculative optimizations since they have
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
@@ -53,7 +59,8 @@
         Replacements replacements = new HSAILHotSpotReplacementsImpl(p, host.getSnippetReflection(), assumptions, codeCache.getTarget(), host.getReplacements());
         HotSpotDisassemblerProvider disassembler = host.getDisassembler();
         SuitesProvider suites = new HotSpotSuitesProvider(runtime);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection());
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
+                        host.getMethodHandleAccess());
 
         // pass registers info down to ReplacementsUtil (maybe a better way to do this?)
         HSAILHotSpotReplacementsUtil.initialize(providers.getRegisters());
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerationResult.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerationResult.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,8 @@
 
 import java.util.*;
 
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizingOp;
 
 public class HSAILHotSpotLIRGenerationResult extends LIRGenerationResultBase {
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.hsail.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
@@ -37,6 +36,7 @@
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp;
@@ -44,15 +44,11 @@
 import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall2ArgOp;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCallNoArgOp;
 import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapOp;
-import com.oracle.graal.lir.hsail.HSAILMove.LoadCompressedPointer;
 import com.oracle.graal.lir.hsail.HSAILMove.LoadOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
-import com.oracle.graal.lir.hsail.HSAILMove.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.extended.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -96,20 +92,18 @@
         return config.narrowKlassBase;
     }
 
-    private static boolean isCompressCandidate(Access access) {
-        return access != null && access.isCompressible();
+    @Override
+    public boolean canStoreConstant(Constant c) {
+        return !(c instanceof HotSpotObjectConstant);
     }
 
     @Override
-    public boolean canStoreConstant(Constant c, boolean isCompressed) {
-        return true;
-    }
-
-    /**
-     * Returns whether or not the input access should be (de)compressed.
-     */
-    private boolean isCompressedOperation(PlatformKind kind, Access access) {
-        return access != null && access.isCompressible() && ((kind == Kind.Long && config.useCompressedClassPointers) || (kind == Kind.Object && config.useCompressedOops));
+    public boolean canInlineConstant(Constant c) {
+        if (c instanceof HotSpotObjectConstant) {
+            return c.isNull();
+        } else {
+            return super.canInlineConstant(c);
+        }
     }
 
     private static Kind getMemoryKind(PlatformKind kind) {
@@ -121,20 +115,10 @@
     }
 
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         HSAILAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new LoadCompressedPointer(Kind.Object, result, scratch, loadAddress, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
-        } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new LoadCompressedPointer(Kind.Object, result, scratch, loadAddress, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment()));
-        } else if (kind == NarrowOopStamp.NarrowOop) {
+        if (kind == NarrowOopStamp.NarrowOop) {
             append(new LoadOp(Kind.Int, result, loadAddress, state));
         } else {
             append(new LoadOp(getMemoryKind(kind), result, loadAddress, state));
@@ -143,43 +127,20 @@
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         HSAILAddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        boolean isCompressed = isCompressedOperation(kind, access);
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
-            if (canStoreConstant(c, isCompressed)) {
-                if (isCompressed) {
-                    if ((c.getKind() == Kind.Object) && c.isNull()) {
-                        // Constant value = c.isNull() ? c : compress(c, config.getOopEncoding());
-                        append(new StoreConstantOp(Kind.Int, storeAddress, Constant.forInt(0), state));
-                    } else if (c.getKind() == Kind.Long) {
-                        // It's always a good idea to directly store compressed constants since they
-                        // have to be materialized as 64 bits encoded otherwise.
-                        Constant value = compress(c, config.getKlassEncoding());
-                        append(new StoreConstantOp(Kind.Int, storeAddress, value, state));
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("can't handle: " + access);
-                    }
-                    return;
-                } else {
-                    append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
-                    return;
-                }
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+                c = Constant.INT_0;
+            }
+            if (canStoreConstant(c)) {
+                append(new StoreConstantOp(getMemoryKind(kind), storeAddress, c, state));
+                return;
             }
         }
         Variable input = load(inputVal);
-        if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new StoreCompressedPointer(Kind.Object, storeAddress, input, scratch, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
-        } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) {
-            Variable scratch = newVariable(Kind.Long);
-            append(new StoreCompressedPointer(Kind.Object, storeAddress, input, scratch, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment()));
-        } else if (kind == NarrowOopStamp.NarrowOop) {
+        if (kind == NarrowOopStamp.NarrowOop) {
             append(new StoreOp(Kind.Int, storeAddress, input, state));
         } else {
             append(new StoreOp(getMemoryKind(kind), storeAddress, input, state));
@@ -203,15 +164,35 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting) {
-        emitDeoptimizeInner(actionAndReason, state(deopting), "emitDeoptimize");
+    public Value emitAtomicReadAndAdd(Value address, Value delta) {
+        PlatformKind kind = delta.getPlatformKind();
+        Kind memKind = getMemoryKind(kind);
+        Variable result = newVariable(kind);
+        HSAILAddressValue addressValue = asAddressValue(address);
+        append(new HSAILMove.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
+        return result;
+    }
+
+    @Override
+    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        PlatformKind kind = newValue.getPlatformKind();
+        Kind memKind = getMemoryKind(kind);
+        Variable result = newVariable(kind);
+        HSAILAddressValue addressValue = asAddressValue(address);
+        append(new HSAILMove.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
+        return result;
+    }
+
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
+        emitDeoptimizeInner(actionAndReason, state, "emitDeoptimize");
     }
 
     /***
      * 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());
+        DeoptimizeOp deopt = new DeoptimizeOp(actionAndReason, lirFrameState, emitName, config.useHSAILDeoptimization, getMetaAccess());
         ((HSAILHotSpotLIRGenerationResult) getResult()).addDeopt(deopt);
         append(deopt);
     }
@@ -222,7 +203,7 @@
      * emitting a comment as to what Foreign call they would have made.
      */
     @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
         Variable result = newVariable(Kind.Object);  // linkage.getDescriptor().getResultType());
 
         // to make the LIRVerifier happy, we move any constants into registers
@@ -255,7 +236,18 @@
     @Override
     protected HSAILLIRInstruction createMove(AllocatableValue dst, Value src) {
         if (dst.getPlatformKind() == NarrowOopStamp.NarrowOop) {
-            if (isRegister(src) || isStackSlot(dst)) {
+            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) {
+                return new MoveToRegOp(Kind.Int, dst, Constant.INT_0);
+            } else if (src instanceof HotSpotObjectConstant) {
+                if (HotSpotObjectConstant.isCompressed((Constant) src)) {
+                    Variable uncompressed = newVariable(Kind.Object);
+                    append(new MoveToRegOp(Kind.Object, uncompressed, src));
+                    CompressEncoding oopEncoding = config.getOopEncoding();
+                    return new HSAILMove.CompressPointer(dst, newVariable(Kind.Object), uncompressed, oopEncoding.base, oopEncoding.shift, oopEncoding.alignment, true);
+                } else {
+                    return new MoveToRegOp(Kind.Object, dst, src);
+                }
+            } else if (isRegister(src) || isStackSlot(dst)) {
                 return new MoveFromRegOp(Kind.Int, dst, src);
             } else {
                 return new MoveToRegOp(Kind.Int, dst, src);
@@ -312,31 +304,14 @@
         return result;
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveUnpackFramesStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
     public SaveRegistersOp emitSaveAllRegisters() {
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        throw GraalInternalError.unimplemented();
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        assert address.getKind() == Kind.Object : address + " - " + address.getKind() + " not an object!";
+        Variable obj = newVariable(Kind.Object);
+        emitMove(obj, address);
+        append(new HSAILMove.NullCheckOp(obj, state));
     }
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -33,12 +33,11 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.hotspot.hsail.nodes.*;
 import com.oracle.graal.hotspot.hsail.replacements.*;
 
 import java.util.HashMap;
 
-public class HSAILHotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class HSAILHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     private HSAILNewObjectSnippets.Templates hsailNewObjectSnippets;
 
@@ -104,29 +103,6 @@
         }
     };
 
-    LoweringStrategy AtomicGetAndAddStrategy = new LoweringStrategy() {
-        @Override
-        void lower(Node n, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) n.graph();
-
-            // Note: this code adapted from CompareAndSwapNode
-            // lowering but since we are not dealing with an object
-            // but a word (thread passed in), I wasn't sure what
-            // should be done with the Location stuff so leaving it
-            // out for now
-
-            AtomicGetAndAddNode getAdd = (AtomicGetAndAddNode) n;
-            // LocationNode location = IndexedLocationNode.create(ANY_LOCATION, Kind.Long, 0,
-            // getAdd.offset(), graph, 1);
-            LocationNode location = IndexedLocationNode.create(getAdd.getLocationIdentity(), Kind.Long, 0, getAdd.offset(), graph, 1);
-            // note: getAdd.base() used to be getAdd.object()
-            LoweredAtomicGetAndAddNode loweredAtomicGetAdd = graph.add(new LoweredAtomicGetAndAddNode(getAdd.base(), location, getAdd.delta(), HeapAccess.BarrierType.NONE,
-                            getAdd.getKind() == Kind.Object));
-            loweredAtomicGetAdd.setStateAfter(getAdd.stateAfter());
-            graph.replaceFixedWithFixed(getAdd, loweredAtomicGetAdd);
-        }
-    };
-
     private HashMap<Class<?>, LoweringStrategy> strategyMap = new HashMap<>();
 
     void initStrategyMap() {
@@ -139,22 +115,20 @@
         strategyMap.put(MonitorEnterNode.class, RejectStrategy);
         strategyMap.put(MonitorExitNode.class, RejectStrategy);
         strategyMap.put(UnwindNode.class, UnwindNodeStrategy);
-        strategyMap.put(AtomicGetAndAddNode.class, AtomicGetAndAddStrategy);
     }
 
     private LoweringStrategy getStrategy(Node n) {
         return strategyMap.get(n.getClass());
     }
 
-    public HSAILHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
-        super(runtime, metaAccess, foreignCalls, registers);
+    public HSAILHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, TargetDescription target) {
+        super(runtime, metaAccess, foreignCalls, registers, target);
         initStrategyMap();
     }
 
     @Override
     public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
         super.initialize(providers, config);
-        TargetDescription target = providers.getCodeCache().getTarget();
         hsailNewObjectSnippets = new HSAILNewObjectSnippets.Templates(providers, target);
     }
 
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,17 +27,15 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.hsail.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
-import com.oracle.graal.hotspot.hsail.nodes.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
-import com.oracle.graal.lir.hsail.HSAILMove.AtomicGetAndAddOp;
 import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapOp;
 import com.oracle.graal.nodes.*;
 
@@ -46,7 +44,7 @@
  */
 public class HSAILHotSpotNodeLIRBuilder extends HSAILNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
@@ -79,14 +77,6 @@
         }
     }
 
-    public void visitAtomicGetAndAdd(LoweredAtomicGetAndAddNode node, Value address) {
-        Variable nodeResult = newVariable(node.getKind());
-        Value delta = getGen().loadNonConst(operand(node.getDelta()));
-        HSAILAddressValue addressValue = getGen().asAddressValue(address);
-        append(new AtomicGetAndAddOp(nodeResult, addressValue, delta));
-        setResult(node, nodeResult);
-    }
-
     public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
         Kind kind = x.newValue().getKind();
         assert kind == x.expectedValue().getKind();
@@ -114,8 +104,8 @@
     @Override
     public void visitSafepointNode(SafepointNode i) {
         HotSpotVMConfig config = getGen().config;
-        if (config.useHSAILSafepoints == true) {
-            LIRFrameState info = gen.state(i);
+        if ((config.useHSAILSafepoints == true) && (config.useHSAILDeoptimization == true)) {
+            LIRFrameState info = state(i);
             HSAILHotSpotSafepointOp safepoint = new HSAILHotSpotSafepointOp(info, config, this);
             ((HSAILHotSpotLIRGenerationResult) getGen().getResult()).addDeopt(safepoint);
             append(safepoint);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotRegisterConfig.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotRegisterConfig.java	Fri May 30 15:09:09 2014 +0200
@@ -194,6 +194,14 @@
         throw new UnsupportedOperationException();
     }
 
+    public boolean isAllocatableSReg(Register reg) {
+        return (reg.number >= HSAIL.s0.number && reg.number <= HSAIL.s31.number);
+    }
+
+    public boolean isAllocatableDReg(Register reg) {
+        return (reg.number >= HSAIL.d0.number && reg.number <= HSAIL.d15.number);
+    }
+
     public HSAILHotSpotRegisterConfig() {
 
     }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -59,16 +59,16 @@
 
     public void completeInitialization() {
         // Register the substitutions for java.lang.Math routines.
-        registerSubstitutions(HSAILMathSubstitutions.class);
+        registerSubstitutions(Math.class, HSAILMathSubstitutions.class);
 
         // Register the ignored substitutions
         addIgnoredResolvedMethod(String.class, "equals", Object.class);
     }
 
     @Override
-    protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) {
+    protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMethod, Method substituteMethod) {
         // TODO: decide if we want to override this in any way
-        return super.registerMethodSubstitution(originalMethod, substituteMethod);
+        return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotSafepointOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotSafepointOp.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.hsail;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.hsail.*;
@@ -42,64 +40,55 @@
     private Constant actionAndReason;
     @State protected LIRFrameState frameState;
     protected int codeBufferPos = -1;
-    protected int dregOopMap = 0;
     final int offsetToNoticeSafepoints;
+    final HotSpotVMConfig config;
 
     public HSAILHotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, NodeLIRBuilderTool tool) {
         actionAndReason = tool.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(DeoptimizationAction.None, DeoptimizationReason.None, 0);
         frameState = state;
         offsetToNoticeSafepoints = config.hsailNoticeSafepointsOffset;
+        this.config = config;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+        if (config.useHSAILDeoptimization) {
+            // 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 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();
-
-        masm.emitComment(" /* HSAIL safepoint bci=" + frameState.debugInfo().getBytecodePosition().getBCI() + ", frameState=" + frameState + " */");
-        String afterSafepointLabel = "@LAfterSafepoint_at_pos_" + codeBufferPos;
+            masm.emitComment(" /* HSAIL safepoint bci=" + frameState.debugInfo().getBytecodePosition().getBCI() + ", frameState=" + frameState + " */");
+            String afterSafepointLabel = "@LAfterSafepoint_at_pos_" + codeBufferPos;
 
-        AllocatableValue scratch64 = HSAIL.d16.asValue(Kind.Object);
-        AllocatableValue spAddrReg = HSAIL.d17.asValue(Kind.Object);
-        AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
-        masm.emitLoadKernelArg(scratch64, masm.getDeoptInfoName(), "u64");
+            AllocatableValue scratch64 = HSAIL.d16.asValue(Kind.Object);
+            AllocatableValue spAddrReg = HSAIL.d17.asValue(Kind.Object);
+            AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
+            masm.emitLoadKernelArg(scratch64, masm.getDeoptInfoName(), "u64");
 
-        // Build address of noticeSafepoints field
-        HSAILAddress noticeSafepointsAddr = new HSAILAddressValue(Kind.Object, scratch64, offsetToNoticeSafepoints).toAddress();
-        masm.emitLoad(Kind.Object, spAddrReg, noticeSafepointsAddr);
-
-        // Load int value from that field
-        HSAILAddress noticeSafepointsIntAddr = new HSAILAddressValue(Kind.Int, spAddrReg, 0).toAddress();
-        masm.emitLoadAcquire(scratch32, noticeSafepointsIntAddr);
-        masm.emitCompare(Kind.Int, scratch32, Constant.forInt(0), "eq", false, false);
-        masm.cbr(afterSafepointLabel);
+            // Build address of noticeSafepoints field
+            HSAILAddress noticeSafepointsAddr = new HSAILAddressValue(Kind.Object, scratch64, offsetToNoticeSafepoints).toAddress();
+            masm.emitLoad(Kind.Object, spAddrReg, noticeSafepointsAddr);
 
-        BytecodeFrame frame = frameState.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);
-                if (val.getKind() == Kind.Object) {
-                    dregOopMap |= 1 << (reg.encoding());
-                }
-            }
-        }
+            // Load int value from that field
+            HSAILAddress noticeSafepointsIntAddr = new HSAILAddressValue(Kind.Int, spAddrReg, 0).toAddress();
+            masm.emitLoadAcquire(scratch32, noticeSafepointsIntAddr);
+            masm.emitCompare(Kind.Int, scratch32, Constant.forInt(0), "eq", false, false);
+            masm.cbr(afterSafepointLabel);
 
-        AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
-        AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
-        AllocatableValue dregOopMapReg = HSAIL.dregOopMapReg.asValue(Kind.Int);
-        masm.emitMov(Kind.Int, actionAndReasonReg, actionAndReason);
-        masm.emitMov(Kind.Int, codeBufferOffsetReg, Constant.forInt(codeBufferPos));
-        masm.emitMov(Kind.Int, dregOopMapReg, Constant.forInt(dregOopMap));
-        masm.emitJumpToLabelName(masm.getDeoptLabelName());
+            AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
+            AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
+            masm.emitMov(Kind.Int, actionAndReasonReg, actionAndReason);
+            masm.emitMov(Kind.Int, codeBufferOffsetReg, Constant.forInt(codeBufferPos));
+            masm.emitJumpToLabelName(masm.getDeoptLabelName());
 
-        masm.emitString0(afterSafepointLabel + ":\n");
+            masm.emitString0(afterSafepointLabel + ":\n");
 
-        // now record the debuginfo
-        crb.recordInfopoint(codeBufferPos, frameState, InfopointReason.SAFEPOINT);
+            // now record the debuginfo
+            crb.recordInfopoint(codeBufferPos, frameState, InfopointReason.SAFEPOINT);
+        } else {
+            masm.emitComment("/* HSAIL safepoint would have been here. */");
+        }
     }
 
     public LIRFrameState getFrameState() {
@@ -109,4 +98,4 @@
     public int getCodeBufferPos() {
         return codeBufferPos;
     }
-}
\ No newline at end of file
+}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/nodes/AtomicGetAndAddNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.hsail.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * Represents an atomic get-and-add operation. The result is the get value (before the delta is
- * added)
- */
-public class AtomicGetAndAddNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
-
-    @Input private ValueNode base;
-    @Input private ValueNode offset;
-    @Input private ValueNode delta;
-    @Input private LocationIdentity locationIdentity;
-
-    public ValueNode base() {
-        return base;
-    }
-
-    public ValueNode offset() {
-        return offset;
-    }
-
-    public ValueNode delta() {
-        return delta;
-    }
-
-    @SuppressWarnings("unused")
-    public AtomicGetAndAddNode(ValueNode base, ValueNode offset, ValueNode location /* ignored */, ValueNode delta) {
-        super(StampFactory.forKind(Kind.Long.getStackKind()));
-        this.base = base;
-        this.offset = offset;
-        this.delta = delta;
-    }
-
-    @Override
-    public LocationIdentity getLocationIdentity() {
-        return locationIdentity;
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, tool);
-    }
-
-    @NodeIntrinsic
-    public native static long atomicGetAndAdd(long base, int offset, LocationIdentity locationIdentity, int delta);
-
-    public MemoryCheckpoint asMemoryCheckpoint() {
-        return this;
-    }
-
-    public MemoryPhiNode asMemoryPhi() {
-        return null;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/nodes/LoweredAtomicGetAndAddNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +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.hotspot.hsail.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.hotspot.hsail.*;
-
-/**
- * Represents the lowered version of an atomic get-and-add operation{@code AtomicGetAndAddNode}.
- */
-public class LoweredAtomicGetAndAddNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
-
-    @Input private ValueNode delta;
-    @Input(InputType.State) private FrameState stateAfter;
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
-        return true;
-    }
-
-    public ValueNode getDelta() {
-        return delta;
-    }
-
-    public LoweredAtomicGetAndAddNode(ValueNode object, LocationNode location, ValueNode delta, BarrierType barrierType, boolean compressible) {
-        super(object, location, StampFactory.forKind(Kind.Long.getStackKind()), barrierType, compressible);
-        this.delta = delta;
-    }
-
-    @Override
-    public LocationIdentity getLocationIdentity() {
-        return location().getLocationIdentity();
-    }
-
-    @Override
-    public boolean canNullCheck() {
-        return false;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        HSAILHotSpotNodeLIRBuilder hsailGen = (HSAILHotSpotNodeLIRBuilder) gen;
-        hsailGen.visitAtomicGetAndAdd(this, location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object())));
-    }
-
-    @Override
-    public MemoryCheckpoint asMemoryCheckpoint() {
-        return this;
-    }
-
-    @Override
-    public MemoryPhiNode asMemoryPhi() {
-        return null;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILHotSpotReplacementsUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILHotSpotReplacementsUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,11 +24,11 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.word.*;
 import com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.hsail.nodes.*;
 
 //JaCoCo Exclude
 
@@ -56,7 +56,7 @@
     }
 
     public static Word atomicGetAndAddTlabTop(Word thread, int size) {
-        return Word.unsigned(AtomicGetAndAddNode.atomicGetAndAdd(thread.rawValue(), threadTlabTopOffset(), TLAB_TOP_LOCATION, size));
+        return Word.unsigned(AtomicReadAndAddNode.getAndAddLong(null, thread.rawValue() + threadTlabTopOffset(), size, TLAB_TOP_LOCATION));
     }
 
     public static final LocationIdentity TLAB_PFTOP_LOCATION = new NamedLocationIdentity("TlabPfTop");
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -23,15 +23,16 @@
 package com.oracle.graal.hotspot.hsail.replacements;
 
 import static com.oracle.graal.api.code.UnsignedMath.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.hsail.replacements.HSAILHotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.hsail.replacements.HSAILNewObjectSnippets.Options.*;
 import static com.oracle.graal.nodes.PiArrayNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -40,7 +41,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -221,7 +221,7 @@
             final int headerSize = HotSpotGraalRuntime.getArrayBaseOffset(elementKind);
             // lowerer extends HotSpotLoweringProvider so we can just use that
             HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
-            int log2ElementSize = CodeUtil.log2(lowerer.getScalingFactor(elementKind));
+            int log2ElementSize = CodeUtil.log2(lowerer.arrayScalingFactor(elementKind));
 
             Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("hub", hub);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.jfr/src/com/oracle/graal/hotspot/jfr/events/JFREventProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,158 @@
+/*
+ * 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.jfr.events;
+
+import java.net.*;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.hotspot.events.*;
+import com.oracle.jrockit.jfr.*;
+
+/**
+ * A JFR implementation for {@link EventProvider}. This implementation is used when Flight Recorder
+ * is turned on.
+ */
+@ServiceProvider(EventProvider.class)
+public final class JFREventProvider implements EventProvider {
+
+    @SuppressWarnings("deprecation") private final Producer producer;
+
+    @SuppressWarnings("deprecation")
+    public JFREventProvider() {
+        try {
+            /*
+             * The "HotSpot JVM" producer is a native producer and we cannot use it. So we create
+             * our own. This has the downside that Mission Control is confused and doesn't show
+             * Graal's events in the "Code" tab. There are plans to revise the JFR code for JDK 9.
+             */
+            producer = new Producer("HotSpot JVM", "Oracle Hotspot JVM", "http://www.oracle.com/hotspot/jvm/");
+            producer.register();
+        } catch (URISyntaxException e) {
+            throw new InternalError(e);
+        }
+
+        // Register event classes with Producer.
+        for (Class<?> c : JFREventProvider.class.getDeclaredClasses()) {
+            if (c.isAnnotationPresent(EventDefinition.class)) {
+                assert com.oracle.jrockit.jfr.InstantEvent.class.isAssignableFrom(c) : c;
+                registerEvent(c);
+            }
+        }
+    }
+
+    /**
+     * Register an event class with the {@link Producer}.
+     *
+     * @param c event class
+     * @return the {@link EventToken event token}
+     */
+    @SuppressWarnings({"deprecation", "javadoc", "unchecked"})
+    private final EventToken registerEvent(Class<?> c) {
+        try {
+            return producer.addEvent((Class<? extends com.oracle.jrockit.jfr.InstantEvent>) c);
+        } catch (InvalidEventDefinitionException | InvalidValueException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    public CompilationEvent newCompilationEvent() {
+        return new JFRCompilationEvent();
+    }
+
+    /**
+     * A JFR compilation event.
+     *
+     * <p>
+     * See: event {@code Compilation} in {@code src/share/vm/trace/trace.xml}
+     */
+    @SuppressWarnings("deprecation")
+    @EventDefinition(name = "Compilation", path = "vm/compiler/compilation")
+    public static class JFRCompilationEvent extends com.oracle.jrockit.jfr.DurationEvent implements CompilationEvent {
+
+        /*
+         * FIXME method should be a Method* but we can't express that in Java.
+         */
+        @ValueDefinition(name = "Java Method") public String method;
+        @ValueDefinition(name = "Compilation ID", relationKey = "COMP_ID") public int compileId;
+        @ValueDefinition(name = "Compilation Level") public short compileLevel;
+        @ValueDefinition(name = "Succeeded") public boolean succeeded;
+        @ValueDefinition(name = "On Stack Replacement") public boolean isOsr;
+        @ValueDefinition(name = "Compiled Code Size", contentType = ContentType.Bytes) public int codeSize;
+        @ValueDefinition(name = "Inlined Code Size", contentType = ContentType.Bytes) public int inlinedBytes;
+
+        public void setMethod(String method) {
+            this.method = method;
+        }
+
+        public void setCompileId(int id) {
+            this.compileId = id;
+        }
+
+        public void setCompileLevel(int compileLevel) {
+            this.compileLevel = (short) compileLevel;
+        }
+
+        public void setSucceeded(boolean succeeded) {
+            this.succeeded = succeeded;
+        }
+
+        public void setIsOsr(boolean isOsr) {
+            this.isOsr = isOsr;
+        }
+
+        public void setCodeSize(int codeSize) {
+            this.codeSize = codeSize;
+        }
+
+        public void setInlinedBytes(int inlinedBytes) {
+            this.inlinedBytes = inlinedBytes;
+        }
+    }
+
+    public CompilerFailureEvent newCompilerFailureEvent() {
+        return new JFRCompilerFailureEvent();
+    }
+
+    /**
+     * A JFR compiler failure event.
+     *
+     * <p>
+     * See: event {@code CompilerFailure} in {@code src/share/vm/trace/trace.xml}
+     */
+    @SuppressWarnings("deprecation")
+    @EventDefinition(name = "Compilation Failure", path = "vm/compiler/failure")
+    public static class JFRCompilerFailureEvent extends com.oracle.jrockit.jfr.InstantEvent implements CompilerFailureEvent {
+
+        @ValueDefinition(name = "Compilation ID", relationKey = "COMP_ID") public int compileId;
+        @ValueDefinition(name = "Message", description = "The failure message") public String failure;
+
+        public void setCompileId(int id) {
+            this.compileId = id;
+        }
+
+        public void setMessage(String message) {
+            this.failure = message;
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Fri May 30 15:09:09 2014 +0200
@@ -38,7 +38,6 @@
 import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.gpu.*;
@@ -50,10 +49,12 @@
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXControlFlow.PTXPredicatedLIRInstruction;
 import com.oracle.graal.lir.ptx.PTXMemOp.LoadReturnAddrOp;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -345,7 +346,7 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, ResolvedJavaMethod method, Object stub) {
         return new LIRGenerationResultBase(lir, frameMap);
     }
 
@@ -355,12 +356,12 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new PTXHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new PTXHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.hotspot.ptx;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,18 +40,50 @@
 
     public HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend hostBackend) {
         HotSpotProviders host = hostBackend.getProviders();
-
-        HotSpotMetaAccessProvider metaAccess = host.getMetaAccess();
-        PTXHotSpotCodeCacheProvider codeCache = new PTXHotSpotCodeCacheProvider(runtime, createTarget());
-        ConstantReflectionProvider constantReflection = host.getConstantReflection();
-        HotSpotForeignCallsProvider foreignCalls = new PTXHotSpotForeignCallsProvider();
-        LoweringProvider lowerer = new PTXHotSpotLoweringProvider(host.getLowerer());
-        Replacements replacements = host.getReplacements();
-        HotSpotDisassemblerProvider disassembler = host.getDisassembler();
-        SuitesProvider suites = new DefaultSuitesProvider();
-        HotSpotRegistersProvider registers = new HotSpotRegisters(PTX.tid, Register.None, Register.None);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection());
-        return new PTXHotSpotBackend(runtime, providers);
+        HotSpotMetaAccessProvider metaAccess;
+        PTXHotSpotCodeCacheProvider codeCache;
+        ConstantReflectionProvider constantReflection;
+        HotSpotForeignCallsProvider foreignCalls;
+        LoweringProvider lowerer;
+        Replacements replacements;
+        HotSpotDisassemblerProvider disassembler;
+        SuitesProvider suites;
+        HotSpotRegistersProvider registers;
+        HotSpotProviders providers;
+        try (InitTimer t = timer("create providers")) {
+            try (InitTimer rt = timer("create MetaAccess provider")) {
+                metaAccess = host.getMetaAccess();
+            }
+            try (InitTimer rt = timer("create CodeCache provider")) {
+                codeCache = new PTXHotSpotCodeCacheProvider(runtime, createTarget());
+            }
+            try (InitTimer rt = timer("create ConstantReflection provider")) {
+                constantReflection = host.getConstantReflection();
+            }
+            try (InitTimer rt = timer("create ForeignCalls provider")) {
+                foreignCalls = new PTXHotSpotForeignCallsProvider();
+            }
+            try (InitTimer rt = timer("create Lowerer provider")) {
+                lowerer = new PTXHotSpotLoweringProvider(host.getLowerer());
+            }
+            try (InitTimer rt = timer("create Replacements provider")) {
+                replacements = host.getReplacements();
+            }
+            try (InitTimer rt = timer("create Disassembler provider")) {
+                disassembler = host.getDisassembler();
+            }
+            try (InitTimer rt = timer("create Suites provider")) {
+                suites = new DefaultSuitesProvider();
+            }
+            try (InitTimer rt = timer("create HotSpotRegisters provider")) {
+                registers = new HotSpotRegisters(PTX.tid, Register.None, Register.None);
+            }
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
+                            host.getMethodHandleAccess());
+        }
+        try (InitTimer rt = timer("instantiate backend")) {
+            return new PTXHotSpotBackend(runtime, providers);
+        }
     }
 
     protected Architecture createArchitecture() {
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -26,12 +26,12 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.ptx.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * LIR generator specialized for PTX HotSpot.
@@ -72,31 +72,8 @@
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveUnpackFramesStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
     public SaveRegistersOp emitSaveAllRegisters() {
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        throw GraalInternalError.unimplemented();
-    }
 }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,10 @@
 package com.oracle.graal.hotspot.ptx;
 
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.ptx.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -35,7 +35,7 @@
  */
 public class PTXHotSpotNodeLIRBuilder extends PTXNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -31,8 +31,6 @@
 import static com.oracle.graal.hotspot.ptx.PTXWrapperBuilder.LaunchArg.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -48,7 +46,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
@@ -62,8 +59,8 @@
  * <li>PINNED: a buffer into which the address of pinned objects is saved.</li>
  * <li>OBJECT_OFFSETS: the offsets of the object values in PARAMS.</li>
  * </ul>
- * 
- * 
+ *
+ *
  * The PARAMS buffer is the {@code CU_LAUNCH_PARAM_BUFFER_POINTER} buffer passed in the
  * {@code extra} argument to the {@code cuLaunchKernel} function. This buffer contains the
  * parameters to the call. The buffer is word aligned and each parameter is aligned in the buffer
@@ -75,13 +72,13 @@
  * The object pointers in PARAMS are specified by OBJECT_OFFSETS.
  * <p>
  * As a concrete example, for a kernel whose Java method signature is:
- * 
+ *
  * <pre>
  *     static int kernel(int p1, short p2, Object p3, long p4)
  * </pre>
- * 
+ *
  * the graph created is shown below as psuedo-code:
- * 
+ *
  * <pre>
  *     int kernel_wrapper(int p1, short p2, oop p3, long p4) {
  *         address kernelAddr = kernel.start;
@@ -122,7 +119,7 @@
     /**
      * The size of the buffer holding the kernel parameters and the extra word for storing the
      * pointer to device memory for the return value.
-     * 
+     *
      * @see LaunchArg#ParametersAndReturnValueBufferSize
      */
     int bufSize;
@@ -153,7 +150,7 @@
 
     /**
      * Creates the graph implementing the CPU to GPU transition.
-     * 
+     *
      * @param method a method that has been compiled to GPU binary code
      * @param kernel the installed GPU binary for {@code method}
      * @see PTXWrapperBuilder
@@ -164,7 +161,7 @@
         int intSize = Integer.SIZE / Byte.SIZE;
         Kind wordKind = providers.getCodeCache().getTarget().wordKind;
         Signature sig = method.getSignature();
-        boolean isStatic = isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         int sigCount = sig.getParameterCount(false);
         javaParameters = new ParameterNode[(!isStatic ? 1 : 0) + sigCount];
         javaParameterOffsetsInKernelParametersBuffer = new int[javaParameters.length];
@@ -214,7 +211,7 @@
             for (int slot : objectSlots) {
                 int offset = slot * wordSize;
                 LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, index * intSize, getGraph());
-                append(new WriteNode(objectParametersOffsets, ConstantNode.forInt(offset, getGraph()), location, BarrierType.NONE, false, false));
+                append(new WriteNode(objectParametersOffsets, ConstantNode.forInt(offset, getGraph()), location, BarrierType.NONE, false));
                 index++;
             }
         }
@@ -237,12 +234,12 @@
             ParameterNode javaParameter = javaParameters[javaParametersIndex];
             int javaParameterOffset = javaParameterOffsetsInKernelParametersBuffer[javaParametersIndex];
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.getKind(), javaParameterOffset, getGraph());
-            append(new WriteNode(buf, javaParameter, location, BarrierType.NONE, false, false));
+            append(new WriteNode(buf, javaParameter, location, BarrierType.NONE, false));
             updateDimArg(method, sig, sigIndex++, args, javaParameter);
         }
         if (returnKind != Kind.Void) {
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, bufSize - wordSize, getGraph());
-            append(new WriteNode(buf, nullWord, location, BarrierType.NONE, false, false));
+            append(new WriteNode(buf, nullWord, location, BarrierType.NONE, false));
         }
 
         HIRFrameStateBuilder fsb = new HIRFrameStateBuilder(method, getGraph(), true);
@@ -301,7 +298,7 @@
 
     /**
      * Computes offset and size of space in PARAMS for a Java parameter.
-     * 
+     *
      * @param kind the kind of the parameter
      * @param javaParametersIndex the index of the Java parameter
      */
--- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.server;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
@@ -32,7 +34,7 @@
 
 public class ReplacingStreams {
 
-    private IdentityHashMap<Object, Placeholder> objectMap = new IdentityHashMap<>();
+    private Map<Object, Placeholder> objectMap = newIdentityMap();
     private ArrayList<Object> objectList = new ArrayList<>();
 
     private ReplacingOutputStream output;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/GenGraalRuntimeInlineHpp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sourcegen;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.zip.*;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.options.*;
+
+/**
+ * Command line utility for generating the source code of {@code GraalRuntime.inline.hpp}.
+ */
+public class GenGraalRuntimeInlineHpp {
+
+    public static void main(String[] args) {
+        PrintStream out = System.out;
+        try {
+            genGetServiceImpls(out);
+            genSetOption(out);
+        } catch (Throwable t) {
+            t.printStackTrace(out);
+        }
+        out.flush();
+    }
+
+    /**
+     * Generates code for {@code GraalRuntime::get_service_impls()}.
+     */
+    private static void genGetServiceImpls(PrintStream out) throws Exception {
+        String graalJar = null;
+        String classPath = System.getProperty("java.class.path");
+        for (String e : classPath.split(File.pathSeparator)) {
+            if (e.endsWith("graal.jar")) {
+                graalJar = e;
+                break;
+            }
+        }
+        final List<Class<? extends Service>> services = new ArrayList<>();
+        final ZipFile zipFile = new ZipFile(new File(Objects.requireNonNull(graalJar, "Could not find graal.jar on class path: " + classPath)));
+        for (final Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) {
+            final ZipEntry zipEntry = e.nextElement();
+            String name = zipEntry.getName();
+            if (name.startsWith("META-INF/services/")) {
+                String serviceName = name.substring("META-INF/services/".length());
+                Class<?> c = Class.forName(serviceName);
+                if (Service.class.isAssignableFrom(c)) {
+                    @SuppressWarnings("unchecked")
+                    Class<? extends Service> sc = (Class<? extends Service>) c;
+
+                    services.add(sc);
+                }
+            }
+        }
+
+        Set<Integer> lengths = new TreeSet<>();
+        for (Class<?> service : services) {
+            lengths.add(toInternalName(service).length());
+        }
+
+        out.println("Handle GraalRuntime::get_service_impls(KlassHandle serviceKlass, TRAPS) {");
+        out.println("  switch (serviceKlass->name()->utf8_length()) {");
+        for (int len : lengths) {
+            boolean printedCase = false;
+            for (Class<?> service : services) {
+                String serviceName = toInternalName(service);
+                if (len == serviceName.length()) {
+                    if (!printedCase) {
+                        printedCase = true;
+                        out.println("  case " + len + ":");
+                    }
+                    out.printf("    if (serviceKlass->name()->equals(\"%s\", %d)) {%n", serviceName, serviceName.length());
+                    List<Class<?>> impls = new ArrayList<>();
+                    for (Object impl : ServiceLoader.load(service)) {
+                        impls.add(impl.getClass());
+                    }
+
+                    out.printf("      objArrayOop servicesOop = oopFactory::new_objArray(serviceKlass(), %d, CHECK_NH);%n", impls.size());
+                    out.println("      objArrayHandle services(THREAD, servicesOop);");
+                    for (int i = 0; i < impls.size(); i++) {
+                        String name = toInternalName(impls.get(i));
+                        out.printf("      %sservice = create_Service(\"%s\", CHECK_NH);%n", (i == 0 ? "Handle " : ""), name);
+                        out.printf("      services->obj_at_put(%d, service());%n", i);
+                    }
+                    out.println("      return services;");
+                    out.println("    }");
+                }
+            }
+
+        }
+        out.println("  }");
+        out.println("  return Handle();");
+        out.println("}");
+    }
+
+    /**
+     * Generates code for {@code GraalRuntime::set_option()}.
+     */
+    private static void genSetOption(PrintStream out) throws Exception {
+        SortedMap<String, OptionDescriptor> options = getOptions();
+
+        Set<Integer> lengths = new TreeSet<>();
+        for (String s : options.keySet()) {
+            lengths.add(s.length());
+        }
+        lengths.add("PrintFlags".length());
+
+        out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS) {");
+        out.println("  if (value[0] == '+' || value[0] == '-') {");
+        out.println("    // boolean options");
+        genMatchers(out, lengths, options, true);
+        out.println("  } else {");
+        out.println("    // non-boolean options");
+        genMatchers(out, lengths, options, false);
+        out.println("  }");
+        out.println("  return false;");
+        out.println("}");
+    }
+
+    protected static void genMatchers(PrintStream out, Set<Integer> lengths, SortedMap<String, OptionDescriptor> options, boolean isBoolean) throws Exception {
+        out.println("    switch (name_len) {");
+        for (int len : lengths) {
+            boolean printedCase = false;
+
+            // The use of strncmp is required (instead of strcmp) as the option name will not be
+            // null terminated for <name>=<value> style options.
+            if (len == "PrintFlags".length() && isBoolean) {
+                printedCase = true;
+                out.println("    case " + len + ":");
+                out.printf("      if (strncmp(name, \"PrintFlags\", %d) == 0) {%n", len);
+                out.println("        if (value[0] == '+') {");
+                out.println("          VMToCompiler::setOption(hotSpotOptionsClass, name_handle, Handle(), '?', Handle(), 0L);");
+                out.println("        }");
+                out.println("        return true;");
+                out.println("      }");
+            }
+            for (Map.Entry<String, OptionDescriptor> e : options.entrySet()) {
+                OptionDescriptor desc = e.getValue();
+                if (e.getKey().length() == len && ((desc.getType() == Boolean.class) == isBoolean)) {
+                    if (!printedCase) {
+                        printedCase = true;
+                        out.println("    case " + len + ":");
+                    }
+                    out.printf("      if (strncmp(name, \"%s\", %d) == 0) {%n", e.getKey(), len);
+                    Class<?> declaringClass = desc.getDeclaringClass();
+                    out.printf("        Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(),
+                                    toInternalName(getFieldType(desc)));
+                    if (isBoolean) {
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, value[0], Handle(), 0L);");
+                    } else if (desc.getType() == String.class) {
+                        out.println("        Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));");
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, 's', stringValue, 0L);");
+                    } else {
+                        char spec = getPrimitiveSpecChar(desc);
+                        out.println("        jlong primitiveValue = parse_primitive_option_value('" + spec + "', name_handle, value, CHECK_(true));");
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, '" + spec + "', Handle(), primitiveValue);");
+                    }
+                    out.println("        return true;");
+                    out.println("      }");
+                }
+            }
+        }
+        out.println("    }");
+    }
+
+    @SuppressWarnings("unchecked")
+    static SortedMap<String, OptionDescriptor> getOptions() throws Exception {
+        Field field = Class.forName("com.oracle.graal.hotspot.HotSpotOptionsLoader").getDeclaredField("options");
+        field.setAccessible(true);
+        return (SortedMap<String, OptionDescriptor>) field.get(null);
+    }
+
+    private static Class<?> getFieldType(OptionDescriptor desc) throws Exception {
+        return desc.getDeclaringClass().getDeclaredField(desc.getFieldName()).getType();
+    }
+
+    private static String toInternalName(Class<?> c) {
+        return c.getName().replace('.', '/');
+    }
+
+    /**
+     * @see HotSpotOptions#setOption(String, OptionValue, char, String, long)
+     */
+    @SuppressWarnings("javadoc")
+    private static char getPrimitiveSpecChar(OptionDescriptor desc) {
+        if (desc.getType() == Integer.class) {
+            return 'i';
+        }
+        if (desc.getType() == Float.class) {
+            return 'f';
+        }
+        if (desc.getType() == Double.class) {
+            return 'd';
+        }
+        throw GraalInternalError.shouldNotReachHere("Unexpected primitive option type: " + desc.getType().getName());
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,11 +35,14 @@
 
     public SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, target, linkage);
-        registerConfig = new SPARCHotSpotRegisterConfig(target, new Register[]{o0, o1, o2, o3, o4, o5, o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, f0, f1, f2, f3, f4, f5, f6, f7});
+        // This is basically the maximum we can spare. All other G and O register are used.
+        Register[] allocatable = new Register[]{g1, g3, g4, g5, o0, o1, o2, o3, o4};
+        registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable);
     }
 
     @Override
     public RegisterConfig getRegisterConfig() {
         return registerConfig;
     }
+
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri May 30 15:09:09 2014 +0200
@@ -24,9 +24,8 @@
 
 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.compiler.common.GraalOptions.*;
 import static com.oracle.graal.sparc.SPARC.*;
-import static java.lang.reflect.Modifier.*;
 
 import java.util.*;
 
@@ -46,7 +45,6 @@
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.RestoreWindow;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
@@ -54,8 +52,10 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
 /**
  * HotSpot SPARC specific backend.
@@ -79,12 +79,17 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, ResolvedJavaMethod method, Object stub) {
+        return new SPARCHotSpotLIRGenerationResult(lir, frameMap, stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new SPARCHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
@@ -191,17 +196,12 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
-        return new LIRGenerationResultBase(lir, frameMap);
-    }
-
-    @Override
     public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
         SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
         FrameMap frameMap = crb.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
         HotSpotVMConfig config = getRuntime().getConfig();
-        Label unverifiedStub = installedCodeOwner == null || isStatic(installedCodeOwner.getModifiers()) ? null : new Label();
+        Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label();
 
         // Emit the prefix
 
@@ -233,7 +233,7 @@
             MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
             SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
-            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null);
+            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -55,7 +55,7 @@
         HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime);
         Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
-        LoweringProvider lowerer = new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
+        LoweringProvider lowerer = new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, target);
         // Replacements cannot have speculative optimizations since they have
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
@@ -64,7 +64,9 @@
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), assumptions, target);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
         HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
+        HotSpotMethodHandleAccessProvider methodHandleAccess = new HotSpotMethodHandleAccessProvider();
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection,
+                        methodHandleAccess);
 
         return new SPARCHotSpotBackend(runtime, providers);
     }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,9 +48,8 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-
         // Save last Java frame.
-        new Add(stackPointer, new SPARCAddress(stackPointer, 0).getDisplacement(), g4).emit(masm);
+        new Add(stackPointer, STACK_BIAS, g4).emit(masm);
         new Stx(g4, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
 
         // Save the thread register when calling out to the runtime.
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that enters a stack frame which is tailored to call the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Temp(REG) AllocatableValue scratch;
+
+    SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.scratch = scratch;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        Register framePcRegister = asRegister(framePc);
+        Register senderSpRegister = asRegister(senderSp);
+        Register scratchRegister = asRegister(scratch);
+
+        // Save final sender SP to O5_savedSP.
+        new Mov(senderSpRegister, o5).emit(masm);
+
+        // Load final frame PC.
+        new Mov(framePcRegister, o7).emit(masm);
+
+        // Allocate a full sized frame.
+        new Save(sp, -totalFrameSize, sp).emit(masm);
+
+        new Mov(i0, o0).emit(masm);
+        new Mov(i1, o1).emit(masm);
+        new Mov(i2, o2).emit(masm);
+        new Mov(i3, o3).emit(masm);
+        new Mov(i4, o4).emit(masm);
+
+        // Set up last Java values.
+        new Add(sp, STACK_BIAS, scratchRegister).emit(masm);
+        new Stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+
+        // Clear last Java PC.
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        new Mov(thread, l7).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,10 @@
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,10 +25,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.gen.*;
 
 public class SPARCHotSpotLIRGenerationResult extends LIRGenerationResultBase {
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,12 +23,13 @@
 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 com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.sparc.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
@@ -36,16 +37,17 @@
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.lir.sparc.SPARCMove.LoadOp;
+import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 
 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
 
     final HotSpotVMConfig config;
+    private HotSpotLockStack lockStack;
 
     public SPARCHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
         super(providers, cc, lirGenRes);
@@ -66,11 +68,21 @@
 
     @Override
     public StackSlot getLockSlot(int lockDepth) {
-        return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth);
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert lockStack != null;
+        return lockStack;
+    }
+
+    protected void setLockStack(HotSpotLockStack lockStack) {
+        assert this.lockStack == null;
+        this.lockStack = lockStack;
     }
 
     @Override
-    protected boolean needOnlyOopMaps() {
+    public boolean needOnlyOopMaps() {
         // Stubs only need oop maps
         return getStub() != null;
     }
@@ -80,12 +92,13 @@
     }
 
     @Override
-    public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) {
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
         Variable result;
-        DeoptimizingNode deoptInfo = null;
+        // TODO (je) check if this can be removed
+        LIRFrameState deoptInfo = null;
         if (hotspotLinkage.canDeoptimize()) {
-            deoptInfo = info;
+            deoptInfo = state;
             assert deoptInfo != null || getStub() != null;
         }
 
@@ -142,9 +155,9 @@
     }
 
     @Override
-    public void emitDeoptimize(Value actionAndReason, Value speculation, DeoptimizingNode deopting) {
+    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
         moveDeoptValuesToThread(actionAndReason, speculation);
-        append(new SPARCDeoptimizeOp(state(deopting)));
+        append(new SPARCDeoptimizeOp(state));
     }
 
     @Override
@@ -153,89 +166,31 @@
         append(new SPARCHotSpotDeoptimizeCallerOp());
     }
 
-    private static boolean isCompressCandidate(Access access) {
-        return access != null && access.isCompressible();
-    }
-
     @Override
-    public Variable emitLoad(PlatformKind kind, Value address, Access access) {
+    public Variable emitLoad(PlatformKind kind, Value address, LIRFrameState state) {
         SPARCAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
-        if (isCompressCandidate(access)) {
-            if (config.useCompressedOops && kind == Kind.Object) {
-                // append(new LoadCompressedPointer(kind, result, loadAddress, access != null ?
-                // state(access) :
-                // null, config.narrowOopBase, config.narrowOopShift,
-                // config.logMinObjAlignment));
-                throw GraalInternalError.unimplemented();
-            } else if (config.useCompressedClassPointers && kind == Kind.Long) {
-                // append(new LoadCompressedPointer(kind, result, loadAddress, access != null ?
-                // state(access) :
-                // null, config.narrowKlassBase, config.narrowKlassShift,
-                // config.logKlassAlignment));
-                throw GraalInternalError.unimplemented();
-            } else {
-                append(new LoadOp((Kind) kind, result, loadAddress, state));
-            }
-        } else {
-            append(new LoadOp((Kind) kind, result, loadAddress, state));
-        }
+        append(new LoadOp((Kind) kind, result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(PlatformKind kind, Value address, Value inputVal, Access access) {
+    public void emitStore(PlatformKind kind, Value address, Value inputVal, LIRFrameState state) {
         SPARCAddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = null;
-        if (access instanceof DeoptimizingNode) {
-            state = state((DeoptimizingNode) access);
-        }
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
-            if (canStoreConstant(c, isCompressCandidate(access))) {
-                if (inputVal.getKind() == Kind.Object) {
-                    append(new StoreConstantOp((Kind) kind, storeAddress, c, state, config.useCompressedOops && isCompressCandidate(access)));
-                } else if (inputVal.getKind() == Kind.Long) {
-                    append(new StoreConstantOp((Kind) kind, storeAddress, c, state, config.useCompressedClassPointers && isCompressCandidate(access)));
-                } else {
-                    append(new StoreConstantOp((Kind) kind, storeAddress, c, state, false));
-                }
+            if (canStoreConstant(c)) {
+                append(new StoreConstantOp((Kind) kind, storeAddress, c, state));
                 return;
             }
         }
         Variable input = load(inputVal);
-        if (isCompressCandidate(access)) {
-            if (config.useCompressedOops && kind == Kind.Object) {
-                // if (input.getKind() == Kind.Object) {
-                // Variable scratch = newVariable(Kind.Long);
-                // append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state,
-                // config.narrowOopBase, config.narrowOopShift,
-                // config.logMinObjAlignment));
-                // } else {
-                // // the input oop is already compressed
-                // append(new StoreOp(input.getKind(), storeAddress, input, state));
-                // }
-                throw GraalInternalError.unimplemented();
-            } else if (config.useCompressedClassPointers && kind == Kind.Long) {
-                // Variable scratch = newVariable(Kind.Long);
-                // append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state,
-                // config.narrowKlassBase, config.narrowKlassShift,
-                // config.logKlassAlignment));
-                throw GraalInternalError.unimplemented();
-            } else {
-                append(new StoreOp((Kind) kind, storeAddress, input, state));
-            }
-        } else {
-            append(new StoreOp((Kind) kind, storeAddress, input, state));
-        }
+        append(new StoreOp((Kind) kind, storeAddress, input, state));
     }
 
     public Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
-        throw new InternalError("NYI");
+        // TODO Auto-generated method stub
+        throw GraalInternalError.unimplemented();
     }
 
     @Override
@@ -260,38 +215,83 @@
         throw GraalInternalError.unimplemented();
     }
 
-    public SaveRegistersOp emitSaveAllRegisters() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    /**
+     * @param savedRegisters the registers saved by this operation which may be subject to pruning
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be pruned
+     */
+    protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations, boolean supportsRemove) {
+        SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+        append(save);
+        return save;
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    public SaveRegistersOp emitSaveAllRegisters() {
+        // We save all registers that were not saved by the save instruction.
+        // @formatter:off
+        Register[] savedRegisters = {
+                        // CPU
+                        g1, g3, g4, g5,
+                        // FPU
+                        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+                        f8,  f9,  f10, f11, f12, f13, f14, f15,
+                        f16, f17, f18, f19, f20, f21, f22, f23,
+                        f24, f25, f26, f27, f28, f29, f30, f31
+        };
+        // @formatter:on
+        StackSlot[] savedRegisterLocations = new StackSlot[savedRegisters.length];
+        for (int i = 0; i < savedRegisters.length; i++) {
+            PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+            assert kind != Kind.Illegal;
+            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
+            savedRegisterLocations[i] = spillSlot;
+        }
+        return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
+    }
+
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        append(new SPARCHotSpotLeaveCurrentStackFrameOp());
     }
 
     public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp());
     }
 
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable scratchVariable = newVariable(getHostWordKind());
+        append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable));
     }
 
-    public void emitLeaveUnpackFramesStackFrame() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset()));
     }
 
     public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        Variable frameSizeVariable = load(frameSize);
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable));
     }
 
     public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
+
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
+        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(Kind.Long), trapRequest);
+        append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister));
+
+        return result;
+    }
+
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        assert address.getKind() == Kind.Object : address + " - " + address.getKind() + " not an object!";
+        append(new NullCheckOp(load(address), state));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack.
+ */
+@Opcode("LEAVE_CURRENT_STACK_FRAME")
+final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        new Mov(o0, i0).emit(masm);
+        new Mov(o1, i1).emit(masm);
+        new Mov(o2, i2).emit(masm);
+        new Mov(o3, i3).emit(masm);
+        new Mov(o4, i4).emit(masm);
+
+        leaveFrame(crb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack including the return address.
+ */
+@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
+final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        new Mov(o0, i0).emit(masm);
+        new Mov(o1, i1).emit(masm);
+        new Mov(o2, i2).emit(masm);
+        new Mov(o3, i3).emit(masm);
+        new Mov(o4, i4).emit(masm);
+
+        new RestoreWindow().emit(masm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that leaves a stack frame which is tailored to call the C++ method
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadJavaFrameAnchorFlagsOffset;
+
+    SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        new Mov(l7, thread).emit(masm);
+
+        // Clear last Java frame values.
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+        new Stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -30,10 +30,10 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class SPARCHotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
-    public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
-        super(runtime, metaAccess, foreignCalls, registers);
+    public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, TargetDescription target) {
+        super(runtime, metaAccess, foreignCalls, registers, target);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,6 @@
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
@@ -37,6 +35,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
 import com.oracle.graal.nodes.*;
@@ -44,12 +43,15 @@
 
 public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
+        assert gen instanceof SPARCHotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((SPARCHotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
     }
 
     @Override
-    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeMap<Value> nodeOperands) {
         HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMap(), Kind.Long);
         return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
     }
@@ -60,7 +62,7 @@
 
     @Override
     public void visitSafepointNode(SafepointNode i) {
-        LIRFrameState info = gen.state(i);
+        LIRFrameState info = state(i);
         append(new SPARCHotSpotSafepointOp(info, getGen().config, gen));
     }
 
@@ -100,7 +102,7 @@
         } else {
             assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
             HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
-            assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method.";
+            assert !resolvedMethod.isAbstract() : "Cannot make direct call to abstract method.";
             append(new SPARCHotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pushes an interpreter frame to the stack.
+ */
+@Opcode("PUSH_INTERPRETER_FRAME")
+final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction {
+
+    @Alive(REG) AllocatableValue frameSize;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue initialInfo;
+
+    SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) {
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final Register frameSizeRegister = asRegister(frameSize);
+        final Register framePcRegister = asRegister(framePc);
+        final Register senderSpRegister = asRegister(senderSp);
+
+        // Save sender SP to O5_savedSP.
+        new Mov(senderSpRegister, o5).emit(masm);
+
+        new Neg(frameSizeRegister).emit(masm);
+        new Save(sp, frameSizeRegister, sp).emit(masm);
+
+        new Mov(i0, o0).emit(masm);
+        new Mov(i1, o1).emit(masm);
+        new Mov(i2, o2).emit(masm);
+        new Mov(i3, o3).emit(masm);
+        new Mov(i4, o4).emit(masm);
+
+        // NOTE: Don't touch I5 as it contains valuable saved SP!
+
+        // Move frame's new PC into i7
+        new Mov(framePcRegister, i7).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import java.util.*;
@@ -98,25 +98,27 @@
 
     private static Register[] initAllocatable(boolean reserveForHeapBase) {
         Register[] registers = null;
-        // @formatter:off
         if (reserveForHeapBase) {
-            registers = new Register[] {
+            // @formatter:off
+            registers = new Register[]{
                         // TODO this is not complete
                         o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
                         f0, f1, f2, f3, f4, f5, f6, f7
-                      };
+            };
+            // @formatter:on
         } else {
-            registers = new Register[] {
+            // @formatter:off
+            registers = new Register[]{
                         // TODO this is not complete
                         o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
                         f0, f1, f2, f3, f4, f5, f6, f7
-                      };
+            };
+            // @formatter:on
         }
-       // @formatter:on
 
         if (RegisterPressure.getValue() != null) {
             String[] names = RegisterPressure.getValue().split(",");
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Fri May 30 15:09:09 2014 +0200
@@ -33,8 +33,10 @@
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.nodes.spi.*;
+
+import edu.umd.cs.findbugs.annotations.*;
 
 /**
  * Emits a safepoint poll.
@@ -43,7 +45,7 @@
 public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
 
     @State protected LIRFrameState state;
-    @Temp({OperandFlag.REG}) private AllocatableValue temp;
+    @SuppressFBWarnings(value = "BC_IMPOSSIBLE_CAST", justification = "changed by the register allocator") @Temp({OperandFlag.REG}) private AllocatableValue temp;
 
     private final HotSpotVMConfig config;
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,8 @@
 
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import org.junit.*;
 
@@ -66,19 +66,19 @@
     @Test
     public void testStaticFinalObjectAOT() {
         StructuredGraph result = compile("getStaticFinalObject", true);
-        assertEquals(1, getConstantNodes(result).count());
-        assertEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().getKind());
-        assertEquals(2, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+        assertDeepEquals(1, getConstantNodes(result).count());
+        assertDeepEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().getKind());
+        assertDeepEquals(2, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     @Test
     public void testStaticFinalObject() {
         StructuredGraph result = compile("getStaticFinalObject", false);
-        assertEquals(1, getConstantNodes(result).count());
-        assertEquals(Kind.Object, getConstantNodes(result).first().getKind());
-        assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+        assertDeepEquals(1, getConstantNodes(result).count());
+        assertDeepEquals(Kind.Object, getConstantNodes(result).first().getKind());
+        assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static Class<AheadOfTimeCompilationTest> getClassObject() {
@@ -90,12 +90,12 @@
         StructuredGraph result = compile("getClassObject", true);
 
         NodeIterable<ConstantNode> filter = getConstantNodes(result);
-        assertEquals(1, filter.count());
+        assertDeepEquals(1, filter.count());
         HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(AheadOfTimeCompilationTest.class);
-        assertEquals(type.klass(), filter.first().asConstant());
+        assertDeepEquals(type.klass(), filter.first().asConstant());
 
-        assertEquals(1, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+        assertDeepEquals(1, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     @Test
@@ -103,13 +103,13 @@
         StructuredGraph result = compile("getClassObject", false);
 
         NodeIterable<ConstantNode> filter = getConstantNodes(result);
-        assertEquals(1, filter.count());
+        assertDeepEquals(1, filter.count());
         Object mirror = HotSpotObjectConstant.asObject(filter.first().asConstant());
-        assertEquals(Class.class, mirror.getClass());
-        assertEquals(AheadOfTimeCompilationTest.class, mirror);
+        assertDeepEquals(Class.class, mirror.getClass());
+        assertDeepEquals(AheadOfTimeCompilationTest.class, mirror);
 
-        assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+        assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static Class<Integer> getPrimitiveClassObject() {
@@ -120,24 +120,24 @@
     public void testPrimitiveClassObjectAOT() {
         StructuredGraph result = compile("getPrimitiveClassObject", true);
         NodeIterable<ConstantNode> filter = getConstantNodes(result);
-        assertEquals(1, filter.count());
-        assertEquals(getCodeCache().getTarget().wordKind, filter.first().getKind());
+        assertDeepEquals(1, filter.count());
+        assertDeepEquals(getCodeCache().getTarget().wordKind, filter.first().getKind());
 
-        assertEquals(2, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+        assertDeepEquals(2, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     @Test
     public void testPrimitiveClassObject() {
         StructuredGraph result = compile("getPrimitiveClassObject", false);
         NodeIterable<ConstantNode> filter = getConstantNodes(result);
-        assertEquals(1, filter.count());
+        assertDeepEquals(1, filter.count());
         Object mirror = HotSpotObjectConstant.asObject(filter.first().asConstant());
-        assertEquals(Class.class, mirror.getClass());
-        assertEquals(Integer.TYPE, mirror);
+        assertDeepEquals(Class.class, mirror.getClass());
+        assertDeepEquals(Integer.TYPE, mirror);
 
-        assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+        assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static String getStringObject() {
@@ -159,13 +159,13 @@
         StructuredGraph result = compile("getStringObject", compileAOT);
 
         NodeIterable<ConstantNode> filter = getConstantNodes(result);
-        assertEquals(1, filter.count());
+        assertDeepEquals(1, filter.count());
         Object mirror = HotSpotObjectConstant.asObject(filter.first().asConstant());
-        assertEquals(String.class, mirror.getClass());
-        assertEquals("test string", mirror);
+        assertDeepEquals(String.class, mirror.getClass());
+        assertDeepEquals("test string", mirror);
 
-        assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes().filter(ReadNode.class).count());
+        assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
 
     public static Boolean getBoxedBoolean() {
@@ -177,23 +177,23 @@
     public void testBoxedBooleanAOT() {
         StructuredGraph result = compile("getBoxedBoolean", true);
 
-        assertEquals(2, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(1, result.getNodes(PiNode.class).count());
-        assertEquals(1, getConstantNodes(result).count());
+        assertDeepEquals(2, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(1, result.getNodes(PiNode.class).count());
+        assertDeepEquals(1, getConstantNodes(result).count());
         ConstantNode constant = getConstantNodes(result).first();
-        assertEquals(Kind.Long, constant.getKind());
-        assertEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant());
+        assertDeepEquals(Kind.Long, constant.getKind());
+        assertDeepEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant());
     }
 
     @Test
     public void testBoxedBoolean() {
         StructuredGraph result = compile("getBoxedBoolean", false);
-        assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(PiNode.class).count());
-        assertEquals(1, getConstantNodes(result).count());
+        assertDeepEquals(0, result.getNodes(FloatingReadNode.class).count());
+        assertDeepEquals(0, result.getNodes(PiNode.class).count());
+        assertDeepEquals(1, getConstantNodes(result).count());
         ConstantNode constant = getConstantNodes(result).first();
-        assertEquals(Kind.Object, constant.getKind());
-        assertEquals(Boolean.TRUE, HotSpotObjectConstant.asObject(constant.asConstant()));
+        assertDeepEquals(Kind.Object, constant.getKind());
+        assertDeepEquals(Boolean.TRUE, HotSpotObjectConstant.asObject(constant.asConstant()));
     }
 
     private StructuredGraph compile(String test, boolean compileAOT) {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import org.junit.*;
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ExplicitExceptionTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ExplicitExceptionTest.java	Fri May 30 15:09:09 2014 +0200
@@ -37,7 +37,7 @@
     @Override
     protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) {
         InstalledCode installedCode = super.getCode(method, graph);
-        assertEquals(expectedForeignCallCount, graph.getNodes().filter(ForeignCallNode.class).count());
+        assertDeepEquals(expectedForeignCallCount, graph.getNodes().filter(ForeignCallNode.class).count());
         return installedCode;
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java	Fri May 30 15:09:09 2014 +0200
@@ -45,8 +45,8 @@
 
         Object obj = new Object();
 
-        assertEquals("a string".getClass(), ObjectSubstitutions.getClass("a string"));
-        assertEquals(obj.hashCode(), ObjectSubstitutions.hashCode(obj));
+        assertDeepEquals("a string".getClass(), ObjectSubstitutions.getClass("a string"));
+        assertDeepEquals(obj.hashCode(), ObjectSubstitutions.hashCode(obj));
     }
 
     @SuppressWarnings("all")
@@ -75,14 +75,14 @@
         test("getComponentType");
 
         for (Class<?> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
-            assertEquals(c.getModifiers(), ClassSubstitutions.getModifiers(c));
-            assertEquals(c.isInterface(), ClassSubstitutions.isInterface(c));
-            assertEquals(c.isArray(), ClassSubstitutions.isArray(c));
-            assertEquals(c.isPrimitive(), ClassSubstitutions.isPrimitive(c));
-            assertEquals(c.getSuperclass(), ClassSubstitutions.getSuperclass(c));
-            assertEquals(c.getComponentType(), ClassSubstitutions.getComponentType(c));
+            assertDeepEquals(c.getModifiers(), ClassSubstitutions.getModifiers(c));
+            assertDeepEquals(c.isInterface(), ClassSubstitutions.isInterface(c));
+            assertDeepEquals(c.isArray(), ClassSubstitutions.isArray(c));
+            assertDeepEquals(c.isPrimitive(), ClassSubstitutions.isPrimitive(c));
+            assertDeepEquals(c.getSuperclass(), ClassSubstitutions.getSuperclass(c));
+            assertDeepEquals(c.getComponentType(), ClassSubstitutions.getComponentType(c));
             for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
-                assertEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o));
+                assertDeepEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o));
             }
         }
     }
@@ -134,8 +134,8 @@
         test("threadInterrupted");
 
         Thread currentThread = Thread.currentThread();
-        assertEquals(currentThread, ThreadSubstitutions.currentThread());
-        assertEquals(currentThread.isInterrupted(), ThreadSubstitutions.isInterrupted(currentThread, false));
+        assertDeepEquals(currentThread, ThreadSubstitutions.currentThread());
+        assertDeepEquals(currentThread.isInterrupted(), ThreadSubstitutions.isInterrupted(currentThread, false));
     }
 
     @SuppressWarnings("all")
@@ -161,7 +161,7 @@
         SystemSubstitutions.currentTimeMillis();
         SystemSubstitutions.nanoTime();
         for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
-            assertEquals(System.identityHashCode(o), SystemSubstitutions.identityHashCode(o));
+            assertDeepEquals(System.identityHashCode(o), SystemSubstitutions.identityHashCode(o));
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMonitorValueTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMonitorValueTest.java	Fri May 30 15:09:09 2014 +0200
@@ -51,8 +51,8 @@
                         BytecodeFrame caller = frame.caller();
                         assertNotNull(caller);
                         assertNull(caller.caller());
-                        assertEquals(2, frame.numLocks);
-                        assertEquals(2, caller.numLocks);
+                        assertDeepEquals(2, frame.numLocks);
+                        assertDeepEquals(2, caller.numLocks);
                         HotSpotMonitorValue lock1 = (HotSpotMonitorValue) frame.getLockValue(0);
                         HotSpotMonitorValue lock2 = (HotSpotMonitorValue) frame.getLockValue(1);
                         HotSpotMonitorValue lock3 = (HotSpotMonitorValue) caller.getLockValue(0);
@@ -67,7 +67,7 @@
                                 }
                             }
                         }
-                        assertEquals(lock3.getOwner(), lock4.getOwner());
+                        assertDeepEquals(lock3.getOwner(), lock4.getOwner());
                         assertThat(lock1.getOwner(), not(lock2.getOwner()));
                         return super.addMethod(method, compResult);
                     }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java	Fri May 30 15:09:09 2014 +0200
@@ -43,7 +43,7 @@
         Object result;
         try {
             result = nmethod.executeVarargs(null, "b", "c");
-            assertEquals(43, result);
+            assertDeepEquals(43, result);
         } catch (InvalidInstalledCodeException e) {
             Assert.fail("Code was invalidated");
         }
@@ -66,7 +66,7 @@
         Object result;
         try {
             result = nmethod.executeVarargs(nmethod, null, null);
-            assertEquals(43, result);
+            assertDeepEquals(43, result);
         } catch (InvalidInstalledCodeException e) {
             Assert.fail("Code was invalidated");
         }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedJavaFieldTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedJavaFieldTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType.*;
-import static java.lang.reflect.Modifier.*;
 
 import java.lang.reflect.*;
 
@@ -79,7 +78,7 @@
     public void testIsInObject() {
         for (Field f : String.class.getDeclaredFields()) {
             HotSpotResolvedJavaField rf = (HotSpotResolvedJavaField) runtime().getHostProviders().getMetaAccess().lookupJavaField(f);
-            Assert.assertEquals(rf.toString(), rf.isInObject("a string"), !isStatic(rf.getModifiers()));
+            Assert.assertEquals(rf.toString(), rf.isInObject("a string"), !rf.isStatic());
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Fri May 30 15:09:09 2014 +0200
@@ -27,11 +27,14 @@
 import java.lang.ref.*;
 import java.lang.reflect.*;
 
+import com.oracle.graal.phases.common.inlining.policy.InlineEverythingPolicy;
+
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -44,6 +47,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.runtime.*;
 
@@ -159,7 +163,7 @@
     }
 
     public static Object test5Snippet() throws Exception {
-        return UnsafeLoadNode.load(wr, useCompressedOops() ? 12 : 16, Kind.Object, LocationIdentity.ANY_LOCATION);
+        return UnsafeAccess.unsafe.getObject(wr, useCompressedOops() ? 12L : 16L);
     }
 
     /**
@@ -249,7 +253,7 @@
             StructuredGraph graph = parse(snippet);
             HighTierContext highContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
-            new InliningPhase(new InliningPhase.InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
+            new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
             new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
             new GuardLoweringPhase().apply(graph, midContext);
             new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -40,6 +40,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 import com.oracle.graal.phases.tiers.*;
@@ -691,9 +692,9 @@
             };
 
             DebugConfig debugConfig = DebugScope.getConfig();
-            DebugConfig fixedConfig = Debug.fixedConfig(false, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+            DebugConfig fixedConfig = Debug.fixedConfig(false, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
             try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
-                ReentrantNodeIterator.apply(closure, graph.start(), false, null);
+                ReentrantNodeIterator.apply(closure, graph.start(), false);
                 new WriteBarrierVerificationPhase().apply(graph);
             } catch (AssertionError error) {
                 /*
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 30 15:09:09 2014 +0200
@@ -25,14 +25,14 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-import static com.oracle.graal.phases.common.InliningUtil.*;
+import static com.oracle.graal.phases.common.inlining.InliningUtil.*;
 
 import java.io.*;
 import java.lang.management.*;
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
@@ -40,12 +40,17 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.baseline.*;
 import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.common.*;
 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.events.*;
+import com.oracle.graal.hotspot.events.EventProvider.CompilationEvent;
+import com.oracle.graal.hotspot.events.EventProvider.CompilerFailureEvent;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
@@ -102,6 +107,13 @@
     private final int id;
     private final AtomicReference<CompilationStatus> status;
 
+    /**
+     * The executor processing the Graal compilation queue this task was placed on. This will be
+     * null for blocking compilations or if compilations are scheduled as native HotSpot
+     * {@linkplain #ctask CompileTask}s.
+     */
+    private final ExecutorService executor;
+
     private StructuredGraph graph;
 
     /**
@@ -115,13 +127,26 @@
      * 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();
+    private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
 
-    public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) {
+    /**
+     * The address of the native CompileTask associated with this compilation. If 0L, then this
+     * compilation is being managed by a Graal compilation queue otherwise its managed by a native
+     * HotSpot compilation queue.
+     */
+    private final long ctask;
+
+    public CompilationTask(ExecutorService executor, HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long ctask, boolean blocking) {
+        this.executor = executor;
         this.backend = backend;
         this.method = method;
         this.entryBCI = entryBCI;
-        this.id = method.allocateCompileId(entryBCI);
+        if (ctask == 0L) {
+            this.id = method.allocateCompileId(entryBCI);
+        } else {
+            this.id = unsafe.getInt(ctask + backend.getRuntime().getConfig().compileTaskCompileIdOffset);
+        }
+        this.ctask = ctask;
         this.blocking = blocking;
         this.taskId = uniqueTaskIds.incrementAndGet();
         this.status = new AtomicReference<>(CompilationStatus.Queued);
@@ -131,6 +156,11 @@
         return method;
     }
 
+    /**
+     * Returns the compilation id of this task.
+     *
+     * @return compile id
+     */
     public int getId() {
         return id;
     }
@@ -143,7 +173,7 @@
     public void run() {
         withinEnqueue.set(Boolean.FALSE);
         try {
-            runCompilation(true);
+            runCompilation();
         } finally {
             withinEnqueue.set(Boolean.TRUE);
             status.set(CompilationStatus.Finished);
@@ -213,7 +243,14 @@
         return method.getCompilationProfilingInfo(osrCompilation);
     }
 
-    public void runCompilation(boolean clearFromCompilationQueue) {
+    public void runCompilation() {
+        if (executor != null && executor.isShutdown()) {
+            // We don't want to do any unnecessary compilation if the Graal compilation
+            // queue has been shutdown. Note that we leave the JVM_ACC_QUEUED bit set
+            // for the method so that it won't be re-scheduled for compilation.
+            return;
+        }
+
         /*
          * no code must be outside this try/finally because it could happen otherwise that
          * clearQueuedForCompilation() is not executed
@@ -224,12 +261,16 @@
         long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue();
         long previousCompilationTime = CompilationTime.getCurrentValue();
         HotSpotInstalledCode installedCode = null;
+        final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
+
+        // Log a compilation event.
+        EventProvider eventProvider = Graal.getRequiredCapability(EventProvider.class);
+        CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
 
         try (TimerCloseable a = CompilationTime.start()) {
             if (!tryToChangeStatus(CompilationStatus.Queued, CompilationStatus.Running)) {
                 return;
             }
-            boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
 
             // If there is already compiled code for this method on our level we simply return.
             // Graal compiles are always at the highest compile level, even in non-tiered mode so we
@@ -253,6 +294,8 @@
             final long allocatedBytesBefore = threadMXBean.getThreadAllocatedBytes(threadId);
 
             try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
+                // Begin the compilation event.
+                compilationEvent.begin();
 
                 if (UseBaselineCompiler.getValue() == true) {
                     HotSpotProviders providers = backend.getProviders();
@@ -294,6 +337,9 @@
             } catch (Throwable e) {
                 throw Debug.handle(e);
             } finally {
+                // End the compilation event.
+                compilationEvent.end();
+
                 filter.remove();
                 final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
 
@@ -333,20 +379,45 @@
             if (PrintStackTraceOnException.getValue() || ExitVMOnException.getValue()) {
                 t.printStackTrace(TTY.cachedOut);
             }
+
+            // Log a failure event.
+            CompilerFailureEvent event = eventProvider.newCompilerFailureEvent();
+            if (event.shouldWrite()) {
+                event.setCompileId(getId());
+                event.setMessage(t.getMessage());
+                event.commit();
+            }
+
             if (ExitVMOnException.getValue()) {
                 System.exit(-1);
             }
         } finally {
+            final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+
+            // Log a compilation event.
+            if (compilationEvent.shouldWrite()) {
+                compilationEvent.setMethod(MetaUtil.format("%H.%n(%p)", method));
+                compilationEvent.setCompileId(getId());
+                compilationEvent.setCompileLevel(config.compilationLevelFullOptimization);
+                compilationEvent.setSucceeded(true);
+                compilationEvent.setIsOsr(isOSR);
+                compilationEvent.setCodeSize(installedCode.getSize());
+                compilationEvent.setInlinedBytes(processedBytes);
+                compilationEvent.commit();
+            }
+
+            if (ctask != 0L) {
+                unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
+            }
             if ((config.ciTime || config.ciTimeEach || PrintCompRate.getValue() != 0) && installedCode != null) {
-                long processedBytes = InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes;
                 long time = CompilationTime.getCurrentValue() - previousCompilationTime;
                 TimeUnit timeUnit = CompilationTime.getTimeUnit();
                 long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
                 CompilerToVM c2vm = backend.getRuntime().getCompilerToVM();
-                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, (int) processedBytes, time, timeUnitsPerSecond, installedCode);
+                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode);
             }
 
-            if (clearFromCompilationQueue) {
+            if (executor != null) {
                 assert method.isQueuedForCompilation();
                 method.clearQueuedForCompilation();
             }
@@ -363,7 +434,6 @@
      */
     private void printCompilation() {
         final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
-        final int mod = method.getModifiers();
         String compilerName = "";
         if (HotSpotCIPrintCompilerName.getValue()) {
             compilerName = "Graal:";
@@ -380,16 +450,16 @@
             compLevelString = "";
         }
         boolean hasExceptionHandlers = method.getExceptionHandlers().length > 0;
-        TTY.println(String.format("%s%7d %4d %c%c%c%c%c %s      %s %s(%d bytes)", compilerName, backend.getRuntime().compilerToVm.getTimeStamp(), id, isOSR ? '%' : ' ',
-                        Modifier.isSynchronized(mod) ? 's' : ' ', hasExceptionHandlers ? '!' : ' ', blocking ? 'b' : ' ', Modifier.isNative(mod) ? 'n' : ' ', compLevelString,
-                        MetaUtil.format("%H::%n(%p)", method), isOSR ? "@ " + entryBCI + " " : "", method.getCodeSize()));
+        TTY.println(String.format("%s%7d %4d %c%c%c%c%c %s      %s %s(%d bytes)", compilerName, backend.getRuntime().compilerToVm.getTimeStamp(), id, isOSR ? '%' : ' ', method.isSynchronized() ? 's'
+                        : ' ', hasExceptionHandlers ? '!' : ' ', blocking ? 'b' : ' ', method.isNative() ? 'n' : ' ', compLevelString, MetaUtil.format("%H::%n(%p)", method), isOSR ? "@ " + entryBCI +
+                        " " : "", method.getCodeSize()));
     }
 
     private InstalledCode installMethod(final CompilationResult compResult) {
         final HotSpotCodeCacheProvider codeCache = backend.getProviders().getCodeCache();
         InstalledCode installedCode = null;
         try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) {
-            installedCode = codeCache.installMethod(method, compResult);
+            installedCode = codeCache.installMethod(method, compResult, ctask);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -317,7 +317,7 @@
     class CTWCompilationTask extends CompilationTask {
 
         CTWCompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method) {
-            super(backend, method, INVOCATION_ENTRY_BCI, false);
+            super(null, backend, method, INVOCATION_ENTRY_BCI, 0L, false);
         }
 
         /**
@@ -349,7 +349,7 @@
 
             HotSpotBackend backend = runtime.getHostBackend();
             CompilationTask task = new CTWCompilationTask(backend, method);
-            task.runCompilation(false);
+            task.runCompilation();
 
             compileTime += (System.currentTimeMillis() - start);
             compiledMethodsCounter++;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.hotspot.stubs.StubUtil.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -30,6 +32,8 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
@@ -45,11 +49,6 @@
 public abstract class HotSpotBackend extends Backend {
 
     /**
-     * Descriptor for {@link DeoptimizationStub}.
-     */
-    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
-
-    /**
      * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
      * {@linkplain HotSpotVMConfig#codeInstallerMarkIdExceptionHandlerEntry exception handler} in a
      * compiled method.
@@ -57,11 +56,6 @@
     public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class);
 
     /**
-     * Descriptor for SharedRuntime::deopt_blob()-&gt;unpack().
-     */
-    public static final ForeignCallDescriptor DEOPT_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class);
-
-    /**
      * Descriptor for SharedRuntime::get_ic_miss_stub().
      */
     public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class);
@@ -79,6 +73,61 @@
 
     private final HotSpotGraalRuntime runtime;
 
+    /**
+     * @see DeoptimizationFetchUnrollInfoCallNode
+     */
+    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = new ForeignCallDescriptor("fetchUnrollInfo", Word.class, long.class);
+
+    /**
+     * @see DeoptimizationStub#unpackFrames(ForeignCallDescriptor, Word, int)
+     */
+    public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(DeoptimizationStub.class, "unpackFrames", int.class, Word.class, int.class);
+
+    /**
+     * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Word)
+     */
+    public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Word.class);
+
+    /**
+     * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Word)
+     */
+    public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Word.class);
+
+    /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+
+    /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
+
+    /**
+     * @see VMErrorNode
+     */
+    public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
+
+    /**
+     * @see NewMultiArrayStubCall
+     */
+    public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class);
+
+    /**
+     * @see NewArrayStubCall
+     */
+    public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class);
+
+    /**
+     * @see NewInstanceStubCall
+     */
+    public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class);
+
+    /**
+     * @see UncommonTrapCallNode
+     */
+    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class);
+
     public HotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) {
         super(providers);
         this.runtime = runtime;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackendFactory.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackendFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.hotspot.HotSpotGraalRuntime.Options;
 
-public interface HotSpotBackendFactory {
+public interface HotSpotBackendFactory extends Service {
 
     HotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend host);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Fri May 30 15:09:09 2014 +0200
@@ -34,11 +34,17 @@
     public final HotSpotResolvedJavaMethod method;
     public final int entryBCI;
     public final int id;
+    public final long ctask;
 
     public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult) {
+        this(target, method, compResult, 0L);
+    }
+
+    public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) {
         super(target, compResult);
         this.method = method;
         this.entryBCI = compResult.getEntryBCI();
         this.id = compResult.getId();
+        this.ctask = ctask;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CompilationResult.Call;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -64,4 +64,10 @@
     protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
         return new HotSpotLIRFrameState(frame, virtualObjectsArray, exceptionEdge);
     }
+
+    @Override
+    protected BytecodeFrame computeFrameForState(FrameState state) {
+        assert state.bci >= 0 || state.bci == BytecodeFrame.BEFORE_BCI;
+        return super.computeFrameForState(state);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,11 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static sun.reflect.Reflection.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -34,12 +36,16 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.stack.*;
+import com.oracle.graal.api.collections.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.events.*;
 import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.options.*;
@@ -52,9 +58,75 @@
  */
 public final class HotSpotGraalRuntime implements GraalRuntime, RuntimeProvider, StackIntrospection {
 
-    private static final HotSpotGraalRuntime instance = new HotSpotGraalRuntime();
+    /**
+     * A facility for timing a step in the initialization sequence for the runtime. This exists
+     * separate from {@link DebugTimer} as it must be independent from all other Graal code so as to
+     * not perturb the initialization sequence.
+     */
+    public static class InitTimer implements AutoCloseable {
+        final String name;
+        final long start;
+
+        private InitTimer(String name) {
+            this.name = name;
+            this.start = System.currentTimeMillis();
+            System.out.println("START: " + SPACES.substring(0, timerDepth * 2) + name);
+            assert Thread.currentThread() == initializingThread;
+            timerDepth++;
+        }
+
+        public void close() {
+            final long end = System.currentTimeMillis();
+            timerDepth--;
+            System.out.println(" DONE: " + SPACES.substring(0, timerDepth * 2) + name + " [" + (end - start) + " ms]");
+        }
+
+        public static InitTimer timer(String name) {
+            return ENABLED ? new InitTimer(name) : null;
+        }
+
+        public static InitTimer timer(String name, Object suffix) {
+            return ENABLED ? new InitTimer(name + suffix) : null;
+        }
+
+        /**
+         * Specified initialization timing is enabled. This must only be set via a system property
+         * as the timing facility is used to time initialization of {@link HotSpotOptions}.
+         */
+        private static final boolean ENABLED = Boolean.getBoolean("graal.runtime.TimeInit");
+        public static int timerDepth = 0;
+        public static final String SPACES = "                                            ";
+        public static final Thread initializingThread = Thread.currentThread();
+    }
+
+    private static final HotSpotGraalRuntime instance;
+
+    /**
+     * Initializes the native part of the Graal runtime.
+     */
+    private static native void init(Class<?> compilerToVMClass);
+
     static {
-        instance.completeInitialization();
+        try (InitTimer t = timer("initialize natives")) {
+            init(CompilerToVMImpl.class);
+        }
+
+        try (InitTimer t = timer("initialize HotSpotOptions")) {
+            // The options must be processed before any code using them...
+            HotSpotOptions.initialize();
+        }
+
+        try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
+            // ... including code in the constructor
+            instance = new HotSpotGraalRuntime();
+        }
+
+        try (InitTimer t = timer("HotSpotGraalRuntime.completeInitialization")) {
+            // Why deferred initialization? See comment in completeInitialization().
+            instance.completeInitialization();
+        }
+
+        registerFieldsToFilter(HotSpotGraalRuntime.class, "instance");
     }
 
     /**
@@ -73,10 +145,6 @@
         return instance;
     }
 
-    static {
-        Reflection.registerFieldsToFilter(HotSpotGraalRuntime.class, "instance");
-    }
-
     /**
      * Do deferred initialization.
      */
@@ -102,6 +170,8 @@
 
         this.vmToCompiler = toCompiler;
         this.compilerToVm = toVM;
+
+        this.vmToCompiler.startRuntime();
     }
 
     // Options must not be directly declared in HotSpotGraalRuntime - see VerifyOptionsPhase
@@ -119,7 +189,7 @@
         HotSpotBackendFactory nonBasic = null;
         int nonBasicCount = 0;
 
-        for (HotSpotBackendFactory factory : ServiceLoader.loadInstalled(HotSpotBackendFactory.class)) {
+        for (HotSpotBackendFactory factory : Services.load(HotSpotBackendFactory.class)) {
             if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
                 if (factory.getGraalRuntimeName().equals(GraalRuntime.getValue())) {
                     assert selected == null || checkFactoryOverriding(selected, factory);
@@ -225,7 +295,9 @@
 
         compilerToVm = toVM;
         vmToCompiler = toCompiler;
-        config = new HotSpotVMConfig(compilerToVm);
+        try (InitTimer t = timer("HotSpotVMConfig<init>")) {
+            config = new HotSpotVMConfig(compilerToVm);
+        }
 
         CompileTheWorld.Options.overrideWithNativeOptions(config);
 
@@ -246,15 +318,30 @@
         }
 
         String hostArchitecture = config.getHostArchitectureName();
-        hostBackend = registerBackend(findFactory(hostArchitecture).createBackend(this, null));
+
+        HotSpotBackendFactory factory;
+        try (InitTimer t = timer("find factory:", hostArchitecture)) {
+            factory = findFactory(hostArchitecture);
+        }
+        try (InitTimer t = timer("create backend:", hostArchitecture)) {
+            hostBackend = registerBackend(factory.createBackend(this, null));
+        }
 
         String[] gpuArchitectures = getGPUArchitectureNames(compilerToVm);
         for (String arch : gpuArchitectures) {
-            HotSpotBackendFactory factory = findFactory(arch);
+            try (InitTimer t = timer("find factory:", arch)) {
+                factory = findFactory(arch);
+            }
             if (factory == null) {
                 throw new GraalInternalError("No backend available for specified GPU architecture \"%s\"", arch);
             }
-            registerBackend(factory.createBackend(this, hostBackend));
+            try (InitTimer t = timer("create backend:", arch)) {
+                registerBackend(factory.createBackend(this, hostBackend));
+            }
+        }
+
+        try (InitTimer t = timer("createEventProvider")) {
+            eventProvider = createEventProvider();
         }
     }
 
@@ -359,15 +446,39 @@
         return getClass().getSimpleName();
     }
 
+    private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider();
+
+    private final EventProvider eventProvider;
+
+    private EventProvider createEventProvider() {
+        if (config.flightRecorder) {
+            Iterable<EventProvider> sl = Services.load(EventProvider.class);
+            EventProvider singleProvider = null;
+            for (EventProvider ep : sl) {
+                assert singleProvider == null : String.format("multiple %s service implementations found: %s and %s", EventProvider.class.getName(), singleProvider.getClass().getName(),
+                                ep.getClass().getName());
+                singleProvider = ep;
+            }
+            return singleProvider;
+        }
+        return new EmptyEventProvider();
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public <T> T getCapability(Class<T> clazz) {
         if (clazz == RuntimeProvider.class) {
             return (T) this;
+        } else if (clazz == CollectionsProvider.class || clazz == NodeCollectionsProvider.class) {
+            return (T) nodeCollectionsProvider;
         } else if (clazz == StackIntrospection.class) {
             return (T) this;
         } else if (clazz == SnippetReflectionProvider.class) {
             return (T) getHostProviders().getSnippetReflection();
+        } else if (clazz == MethodHandleAccessProvider.class) {
+            return (T) getHostProviders().getMethodHandleAccess();
+        } else if (clazz == EventProvider.class) {
+            return (T) eventProvider;
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Fri May 30 15:09:09 2014 +0200
@@ -22,15 +22,17 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.phases.GraalOptions.*;
-
-import java.util.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -39,6 +41,16 @@
 public abstract class HotSpotHostBackend extends HotSpotBackend implements HostBackend {
 
     /**
+     * Descriptor for {@link DeoptimizationStub#deoptimizationHandler}.
+     */
+    public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptimizationHandler", void.class);
+
+    /**
+     * Descriptor for {@link UncommonTrapStub#uncommonTrapHandler}.
+     */
+    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
+
+    /**
      * This will be 0 if stack banging is disabled.
      */
     protected final int pagesToBang;
@@ -54,16 +66,23 @@
         HotSpotVMConfig config = getRuntime().getConfig();
         HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls();
         final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
-        foreignCalls.initialize(providers, config);
-        lowerer.initialize(providers, config);
+
+        try (InitTimer st = timer("foreignCalls.initialize")) {
+            foreignCalls.initialize(providers, config);
+        }
+        try (InitTimer st = timer("lowerer.initialize")) {
+            lowerer.initialize(providers, config);
+        }
         HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
 
         // Install intrinsics.
         if (Intrinsify.getValue()) {
             try (Scope s = Debug.scope("RegisterReplacements", new DebugDumpScope("RegisterReplacements"))) {
-                ServiceLoader<ReplacementsProvider> sl = ServiceLoader.loadInstalled(ReplacementsProvider.class);
-                for (ReplacementsProvider replacementsProvider : sl) {
-                    replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, replacements, providers.getCodeCache().getTarget());
+                try (InitTimer st = timer("replacementsProviders.registerReplacements")) {
+                    Iterable<ReplacementsProvider> sl = Services.load(ReplacementsProvider.class);
+                    for (ReplacementsProvider replacementsProvider : sl) {
+                        replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, providers.getSnippetReflection(), replacements, providers.getCodeCache().getTarget());
+                    }
                 }
                 if (BootstrapReplacements.getValue()) {
                     for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -24,11 +24,12 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
@@ -44,21 +45,87 @@
      */
     void emitTailcall(Value[] args, Value address);
 
-    void emitLeaveCurrentStackFrame();
-
-    void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo);
+    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
 
-    void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp);
-
-    void emitLeaveUnpackFramesStackFrame();
-
+    /**
+     * Emits code for a {@link SaveAllRegistersNode}.
+     *
+     * @return a {@link SaveRegistersOp} operation
+     */
     SaveRegistersOp emitSaveAllRegisters();
 
-    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
+    /**
+     * Emits code for a {@link LeaveCurrentStackFrameNode}.
+     *
+     * @param saveRegisterOp saved registers
+     */
+    default void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link LeaveDeoptimizedStackFrameNode}.
+     *
+     * @param frameSize
+     * @param initialInfo
+     */
+    default void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link EnterUnpackFramesStackFrameNode}.
+     *
+     * @param framePc
+     * @param senderSp
+     * @param senderFp
+     * @param saveRegisterOp
+     */
+    default void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 
-    void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo);
+    /**
+     * Emits code for a {@link LeaveUnpackFramesStackFrameNode}.
+     *
+     * @param saveRegisterOp
+     */
+    default void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link PushInterpreterFrameNode}.
+     *
+     * @param frameSize
+     * @param framePc
+     * @param senderSp
+     * @param initialInfo
+     */
+    default void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
 
-    Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp);
+    /**
+     * Emits code for a {@link UncommonTrapCallNode}.
+     *
+     * @param trapRequest
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link DeoptimizationFetchUnrollInfoCallNode}.
+     *
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 
     /**
      * Gets a stack slot for a lock at a given lock nesting depth.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.hotspot;
 
-import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -31,6 +32,7 @@
  * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
  * to abstract methods from {@link LIRGenerator} and {@link NodeLIRBuilderTool}.
  */
+@MatchableNode(nodeClass = CompressionNode.class, inputs = {"input"})
 public interface HotSpotNodeLIRBuilder {
 
     void emitPatchReturnAddress(ValueNode address);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri May 30 15:09:09 2014 +0200
@@ -20,91 +20,52 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
+import static com.oracle.graal.hotspot.HotSpotOptionsLoader.*;
 import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*;
-import static java.nio.file.Files.*;
+import static java.lang.Double.*;
 
-import java.io.*;
 import java.lang.reflect.*;
-import java.nio.charset.*;
-import java.nio.file.*;
 import java.util.*;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 
 /**
- * Called from {@code graalCompiler.cpp} to parse any Graal specific options. Such options are
- * (currently) distinguished by a {@code "-G:"} prefix.
+ * Called from {@code graalCompiler.cpp} to set Graal options from the HotSpot command line. Such
+ * options are (currently) distinguished by a {@code "-G:"} prefix.
  */
 public class HotSpotOptions {
 
-    private static final Map<String, OptionDescriptor> options = new HashMap<>();
-
     /**
-     * Initializes {@link #options} from {@link Options} services.
+     * Parses the Graal specific options specified to HotSpot (e.g., on the command line).
+     *
+     * @return true if the CITime or CITimeEach HotSpot VM options are set
      */
-    private static void initializeOptions() {
-        ServiceLoader<Options> sl = ServiceLoader.loadInstalled(Options.class);
-        for (Options opts : sl) {
-            for (OptionDescriptor desc : opts) {
-                if (isHotSpotOption(desc)) {
-                    String name = desc.getName();
-                    OptionDescriptor existing = options.put(name, desc);
-                    assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation();
-                }
-            }
+    private static native boolean parseVMOptions();
+
+    static {
+        boolean timeCompilations = parseVMOptions();
+        if (timeCompilations || PrintCompRate.getValue() != 0) {
+            unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes");
+            unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime");
+        }
+        assert !Debug.Initialization.isDebugInitialized() : "The class " + Debug.class.getName() + " must not be initialized before the Graal runtime has been initialized. " +
+                        "This can be fixed by placing a call to " + Graal.class.getName() + ".runtime() on the path that triggers initialization of " + Debug.class.getName();
+        if (areDebugScopePatternsEnabled()) {
+            System.setProperty(Debug.Initialization.INITIALIZER_PROPERTY_NAME, "true");
         }
     }
 
     /**
-     * Determines if a given option is a HotSpot command line option.
-     */
-    public static boolean isHotSpotOption(OptionDescriptor desc) {
-        return desc.getClass().getName().startsWith("com.oracle.graal");
-    }
-
-    /**
-     * Loads default option value overrides from a {@code graal.options} file if it exists. Each
-     * line in this file starts with {@code "#"} and is ignored or must have the format of a Graal
-     * command line option without the leading {@code "-G:"} prefix. These option value are set
-     * prior to processing of any Graal options present on the command line.
+     * Ensures {@link HotSpotOptions} is initialized.
      */
-    private static void loadOptionOverrides() throws InternalError {
-        String javaHome = System.getProperty("java.home");
-        Path graalDotOptions = Paths.get(javaHome, "lib", "graal.options");
-        if (!exists(graalDotOptions)) {
-            graalDotOptions = Paths.get(javaHome, "jre", "lib", "graal.options");
-        }
-        if (exists(graalDotOptions)) {
-            try {
-                for (String line : Files.readAllLines(graalDotOptions, Charset.defaultCharset())) {
-                    if (!line.startsWith("#")) {
-                        if (!setOption(line)) {
-                            throw new InternalError("Invalid option \"" + line + "\" specified in " + graalDotOptions);
-                        }
-                    }
-                }
-            } catch (IOException e) {
-                throw (InternalError) new InternalError().initCause(e);
-            }
-        }
-    }
-
-    static {
-        initializeOptions();
-        loadOptionOverrides();
-    }
-
-    // Called from VM code
-    public static boolean setOption(String option) {
-        return parseOption(option, null);
+    public static void initialize() {
     }
 
     interface OptionConsumer {
@@ -112,8 +73,44 @@
     }
 
     /**
+     * Helper for the VM code called by {@link #parseVMOptions()}.
+     *
+     * @param name the name of a parsed option
+     * @param option the object encapsulating the option
+     * @param spec specification of boolean option value, type of option value or action to take
+     */
+    static void setOption(String name, OptionValue<?> option, char spec, String stringValue, long primitiveValue) {
+        switch (spec) {
+            case '+':
+                option.setValue(Boolean.TRUE);
+                break;
+            case '-':
+                option.setValue(Boolean.FALSE);
+                break;
+            case '?':
+                printFlags();
+                break;
+            case ' ':
+                printNoMatchMessage(name);
+                break;
+            case 'i':
+                option.setValue((int) primitiveValue);
+                break;
+            case 'f':
+                option.setValue((float) longBitsToDouble(primitiveValue));
+                break;
+            case 'd':
+                option.setValue(longBitsToDouble(primitiveValue));
+                break;
+            case 's':
+                option.setValue(stringValue);
+                break;
+        }
+    }
+
+    /**
      * Parses a given option value specification.
-     * 
+     *
      * @param option the specification of an option and its value
      * @param setter the object to notify of the parsed option and value. If null, the
      *            {@link OptionValue#setValue(Object)} method of the specified option is called
@@ -150,15 +147,7 @@
 
         OptionDescriptor desc = options.get(optionName);
         if (desc == null) {
-            Logger.info("Could not find option " + optionName + " (use -G:+PrintFlags to see Graal options)");
-            List<OptionDescriptor> matches = fuzzyMatch(optionName);
-            if (!matches.isEmpty()) {
-                Logger.info("Did you mean one of the following?");
-                for (OptionDescriptor match : matches) {
-                    boolean isBoolean = match.getType() == boolean.class;
-                    Logger.info(String.format("    %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "=<value>"));
-                }
-            }
+            printNoMatchMessage(optionName);
             return false;
         }
 
@@ -166,12 +155,12 @@
 
         if (value == null) {
             if (optionType == Boolean.TYPE || optionType == Boolean.class) {
-                Logger.info("Value for boolean option '" + optionName + "' must use '-G:+" + optionName + "' or '-G:-" + optionName + "' format");
+                System.err.println("Value for boolean option '" + optionName + "' must use '-G:+" + optionName + "' or '-G:-" + optionName + "' format");
                 return false;
             }
 
             if (valueString == null) {
-                Logger.info("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
+                System.err.println("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
                 return false;
             }
 
@@ -186,7 +175,7 @@
             }
         } else {
             if (optionType != Boolean.class) {
-                Logger.info("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
+                System.err.println("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
                 return false;
             }
         }
@@ -197,23 +186,35 @@
             } else {
                 OptionValue<?> optionValue = desc.getOptionValue();
                 optionValue.setValue(value);
-                // Logger.info("Set option " + desc.getName() + " to " + value);
+                // System.err.println("Set option " + desc.getName() + " to " + value);
             }
         } else {
-            Logger.info("Wrong value \"" + valueString + "\" for option " + optionName);
+            System.err.println("Wrong value \"" + valueString + "\" for option " + optionName);
             return false;
         }
 
         return true;
     }
 
+    protected static void printNoMatchMessage(String optionName) {
+        System.err.println("Could not find option " + optionName + " (use -G:+PrintFlags to see Graal options)");
+        List<OptionDescriptor> matches = fuzzyMatch(optionName);
+        if (!matches.isEmpty()) {
+            System.err.println("Did you mean one of the following?");
+            for (OptionDescriptor match : matches) {
+                boolean isBoolean = match.getType() == boolean.class;
+                System.err.println(String.format("    %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "=<value>"));
+            }
+        }
+    }
+
     /**
      * Sets the relevant system property such that a {@link DebugTimer} or {@link DebugMetric}
      * associated with a field in a class will be unconditionally enabled when it is created.
      * <p>
      * This method verifies that the named field exists and is of an expected type. However, it does
      * not verify that the timer or metric created has the same name of the field.
-     * 
+     *
      * @param c the class in which the field is declared
      * @param name the name of the field
      */
@@ -229,7 +230,7 @@
             }
             String previous = System.setProperty(propertyName, "true");
             if (previous != null) {
-                Logger.info("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\"");
+                System.err.println("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\"");
             }
         } catch (Exception e) {
             throw new GraalInternalError(e);
@@ -237,25 +238,8 @@
     }
 
     /**
-     * Called from VM code once all Graal command line options have been processed by
-     * {@link #setOption(String)}.
-     * 
-     * @param timeCompilations true if the CITime or CITimeEach HotSpot VM options are set
-     */
-    public static void finalizeOptions(boolean timeCompilations) {
-        if (timeCompilations || PrintCompRate.getValue() != 0) {
-            unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes");
-            unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime");
-        }
-        if (areDebugScopePatternsEnabled()) {
-            assert !Debug.Initialization.isDebugInitialized();
-            System.setProperty(Debug.Initialization.INITIALIZER_PROPERTY_NAME, "true");
-        }
-    }
-
-    /**
      * Wraps some given text to one or more lines of a given maximum width.
-     * 
+     *
      * @param text text to wrap
      * @param width maximum width of an output line, exception for words in {@code text} longer than
      *            this value
@@ -296,16 +280,16 @@
     }
 
     private static void printFlags() {
-        Logger.info("[Graal flags]");
-        SortedMap<String, OptionDescriptor> sortedOptions = new TreeMap<>(options);
+        System.out.println("[Graal flags]");
+        SortedMap<String, OptionDescriptor> sortedOptions = options;
         for (Map.Entry<String, OptionDescriptor> e : sortedOptions.entrySet()) {
             e.getKey();
             OptionDescriptor desc = e.getValue();
             Object value = desc.getOptionValue().getValue();
             List<String> helpLines = wrap(desc.getHelp(), 70);
-            Logger.info(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, helpLines.get(0)));
+            System.out.println(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, helpLines.get(0)));
             for (int i = 1; i < helpLines.size(); i++) {
-                Logger.info(String.format("%67s %s", " ", helpLines.get(i)));
+                System.out.println(String.format("%67s %s", " ", helpLines.get(i)));
             }
         }
 
@@ -314,7 +298,7 @@
 
     /**
      * Compute string similarity based on Dice's coefficient.
-     * 
+     *
      * Ported from str_similar() in globals.cpp.
      */
     static float stringSimiliarity(String str1, String str2) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptionsLoader.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import java.util.*;
+
+import com.oracle.graal.options.*;
+
+/**
+ * Helper class for separating loading of options from option initialization at runtime.
+ */
+class HotSpotOptionsLoader {
+    static final SortedMap<String, OptionDescriptor> options = new TreeMap<>();
+
+    /**
+     * Initializes {@link #options} from {@link Options} services.
+     */
+    static {
+        ServiceLoader<Options> sl = ServiceLoader.load(Options.class);
+        for (Options opts : sl) {
+            for (OptionDescriptor desc : opts) {
+                if (isHotSpotOption(desc)) {
+                    String name = desc.getName();
+                    OptionDescriptor existing = options.put(name, desc);
+                    assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation();
+                }
+            }
+        }
+    }
+
+    /**
+     * Determines if a given option is a HotSpot command line option.
+     */
+    private static boolean isHotSpotOption(OptionDescriptor desc) {
+        return desc.getClass().getName().startsWith("com.oracle.graal");
+    }
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -27,10 +27,10 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 
@@ -48,7 +48,7 @@
     }
 
     @Override
-    protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) {
+    protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMethod, Method substituteMethod) {
         final Class<?> substituteClass = substituteMethod.getDeclaringClass();
         if (substituteClass.getDeclaringClass() == BoxingSubstitutions.class) {
             if (config.useHeapProfiler) {
@@ -78,7 +78,7 @@
                 return null;
             }
         }
-        return super.registerMethodSubstitution(originalMethod, substituteMethod);
+        return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
 
     @Override
@@ -86,16 +86,14 @@
         HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
         int intrinsicId = hsMethod.intrinsicId();
         if (intrinsicId != 0) {
-            if (intrinsicId == config.vmIntrinsicInvokeBasic) {
-                return MethodHandleInvokeBasicNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
-                return MethodHandleLinkToInterfaceNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
-                return MethodHandleLinkToSpecialNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
-                return MethodHandleLinkToStaticNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
-                return MethodHandleLinkToVirtualNode.class;
+            /*
+             * The methods of MethodHandle that need substitution are signature-polymorphic, i.e.,
+             * the VM replicates them for every signature that they are actually used for.
+             * Therefore, we cannot use the usual annotation-driven mechanism to define the
+             * substitution.
+             */
+            if (MethodHandleNode.lookupMethodHandleIntrinsic(method) != null) {
+                return MethodHandleNode.class;
             }
         }
         return super.getMacroSubstitution(method);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSymbol.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +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.hotspot;
-
-import static com.oracle.graal.graph.UnsafeAccess.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-
-import java.io.*;
-
-import com.oracle.graal.compiler.common.*;
-
-/**
- * Represents a metaspace {@code Symbol}.
- */
-public class HotSpotSymbol {
-
-    private final long metaspaceSymbol;
-
-    public HotSpotSymbol(long metaspaceSymbol) {
-        assert metaspaceSymbol != 0;
-        this.metaspaceSymbol = metaspaceSymbol;
-    }
-
-    /**
-     * Decodes this {@code Symbol} and returns the symbol string as {@link java.lang.String}.
-     */
-    public String asString() {
-        return readModifiedUTF8(asByteArray());
-    }
-
-    private static String readModifiedUTF8(byte[] buf) {
-        try {
-            final int length = buf.length;
-            byte[] tmp = new byte[length + 2];
-            // write modified UTF-8 length as short in big endian
-            tmp[0] = (byte) ((length >>> 8) & 0xFF);
-            tmp[1] = (byte) ((length >>> 0) & 0xFF);
-            // copy the data
-            System.arraycopy(buf, 0, tmp, 2, length);
-            DataInputStream dis = new DataInputStream(new ByteArrayInputStream(tmp));
-            return dis.readUTF();
-        } catch (IOException e) {
-            // This should never happen so let's fail hard here.
-            throw GraalInternalError.shouldNotReachHere("error reading symbol: " + e);
-        }
-    }
-
-    private byte[] asByteArray() {
-        final int length = getLength();
-        byte[] result = new byte[length];
-        for (int index = 0; index < length; index++) {
-            result[index] = getByteAt(index);
-        }
-        return result;
-    }
-
-    private int getLength() {
-        return unsafe.getShort(metaspaceSymbol + runtime().getConfig().symbolLengthOffset);
-    }
-
-    private byte getByteAt(int index) {
-        return unsafe.getByte(metaspaceSymbol + runtime().getConfig().symbolBodyOffset + index);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -30,6 +30,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspotvmconfig.*;
 
 /**
  * Used to access native configuration details.
@@ -65,14 +66,21 @@
     public final int maxFrameSize = 16 * 1024;
 
     HotSpotVMConfig(CompilerToVM compilerToVm) {
+        compilerToVm.initializeConfiguration(this);
+        assert verifyInitialization();
+
+        oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment());
+        klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment);
+
+        assert check();
+    }
+
+    /**
+     * Check that the initialization produces the same result as the values captured through
+     * vmStructs.
+     */
+    private boolean verifyInitialization() {
         /** These fields are set in {@link CompilerToVM#initializeConfiguration}. */
-        gHotSpotVMStructs = 0;
-        gHotSpotVMTypes = 0;
-        gHotSpotVMIntConstants = 0;
-        gHotSpotVMLongConstants = 0;
-
-        compilerToVm.initializeConfiguration(this);
-
         assert gHotSpotVMStructs != 0;
         assert gHotSpotVMTypes != 0;
         assert gHotSpotVMIntConstants != 0;
@@ -114,7 +122,7 @@
                 String type = annotation.type();
                 VMFields.Field entry = vmFields.get(name);
                 if (entry == null) {
-                    if (annotation.optional() || !isRequired(currentArch, annotation.archs())) {
+                    if (!isRequired(currentArch, annotation.archs())) {
                         continue;
                     }
                     throw new IllegalArgumentException("field not found: " + name);
@@ -129,13 +137,13 @@
 
                 switch (annotation.get()) {
                     case OFFSET:
-                        setField(f, entry.getOffset());
+                        checkField(f, entry.getOffset());
                         break;
                     case ADDRESS:
-                        setField(f, entry.getAddress());
+                        checkField(f, entry.getAddress());
                         break;
                     case VALUE:
-                        setField(f, entry.getValue());
+                        checkField(f, entry.getValue());
                         break;
                     default:
                         throw GraalInternalError.shouldNotReachHere("unknown kind " + annotation.get());
@@ -149,7 +157,7 @@
                 }
                 switch (annotation.get()) {
                     case SIZE:
-                        setField(f, entry.getSize());
+                        checkField(f, entry.getSize());
                         break;
                     default:
                         throw GraalInternalError.shouldNotReachHere("unknown kind " + annotation.get());
@@ -164,26 +172,22 @@
                     }
                     throw new IllegalArgumentException("constant not found: " + name);
                 }
-                setField(f, entry.getValue());
+                checkField(f, entry.getValue());
             } else if (f.isAnnotationPresent(HotSpotVMFlag.class)) {
                 HotSpotVMFlag annotation = f.getAnnotation(HotSpotVMFlag.class);
                 String name = annotation.name();
                 Flags.Flag entry = flags.get(name);
                 if (entry == null) {
-                    if (!isRequired(currentArch, annotation.archs())) {
+                    if (annotation.optional() || !isRequired(currentArch, annotation.archs())) {
                         continue;
                     }
                     throw new IllegalArgumentException("flag not found: " + name);
 
                 }
-                setField(f, entry.getValue());
+                checkField(f, entry.getValue());
             }
         }
-
-        oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment());
-        klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment);
-
-        assert check();
+        return true;
     }
 
     private final CompressEncoding oopEncoding;
@@ -197,29 +201,29 @@
         return klassEncoding;
     }
 
-    private void setField(Field field, Object value) {
+    private void checkField(Field field, Object value) {
         try {
             Class<?> fieldType = field.getType();
             if (fieldType == boolean.class) {
                 if (value instanceof String) {
-                    field.setBoolean(this, Boolean.valueOf((String) value));
+                    assert field.getBoolean(this) == Boolean.valueOf((String) value) : field + " " + value + " " + field.getBoolean(this);
                 } else if (value instanceof Boolean) {
-                    field.setBoolean(this, (boolean) value);
+                    assert field.getBoolean(this) == (boolean) value : field + " " + value + " " + field.getBoolean(this);
                 } else if (value instanceof Long) {
-                    field.setBoolean(this, ((long) value) != 0);
+                    assert field.getBoolean(this) == (((long) value) != 0) : field + " " + value + " " + field.getBoolean(this);
                 } else {
                     GraalInternalError.shouldNotReachHere(value.getClass().getSimpleName());
                 }
             } else if (fieldType == int.class) {
                 if (value instanceof Integer) {
-                    field.setInt(this, (int) value);
+                    assert field.getInt(this) == (int) value : field + " " + value + " " + field.getInt(this);
                 } else if (value instanceof Long) {
-                    field.setInt(this, (int) (long) value);
+                    assert field.getInt(this) == (int) (long) value : field + " " + value + " " + field.getInt(this);
                 } else {
                     GraalInternalError.shouldNotReachHere(value.getClass().getSimpleName());
                 }
             } else if (fieldType == long.class) {
-                field.setLong(this, (long) value);
+                assert field.getLong(this) == (long) value : field + " " + value + " " + field.getLong(this);
             } else {
                 GraalInternalError.shouldNotReachHere(field.toString());
             }
@@ -248,14 +252,14 @@
     /**
      * VMStructEntry (see vmStructs.hpp).
      */
-    private long gHotSpotVMStructs;
-    private long gHotSpotVMStructEntryTypeNameOffset;
-    private long gHotSpotVMStructEntryFieldNameOffset;
-    private long gHotSpotVMStructEntryTypeStringOffset;
-    private long gHotSpotVMStructEntryIsStaticOffset;
-    private long gHotSpotVMStructEntryOffsetOffset;
-    private long gHotSpotVMStructEntryAddressOffset;
-    private long gHotSpotVMStructEntryArrayStride;
+    @HotSpotVMValue(expression = "gHotSpotVMStructs", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMStructs;
+    @HotSpotVMValue(expression = "gHotSpotVMStructEntryTypeNameOffset") @Stable private long gHotSpotVMStructEntryTypeNameOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMStructEntryFieldNameOffset") @Stable private long gHotSpotVMStructEntryFieldNameOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMStructEntryTypeStringOffset") @Stable private long gHotSpotVMStructEntryTypeStringOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMStructEntryIsStaticOffset") @Stable private long gHotSpotVMStructEntryIsStaticOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMStructEntryOffsetOffset") @Stable private long gHotSpotVMStructEntryOffsetOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMStructEntryAddressOffset") @Stable private long gHotSpotVMStructEntryAddressOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMStructEntryArrayStride") @Stable private long gHotSpotVMStructEntryArrayStride;
 
     class VMFields implements Iterable<VMFields.Field> {
 
@@ -364,14 +368,14 @@
     /**
      * VMTypeEntry (see vmStructs.hpp).
      */
-    private long gHotSpotVMTypes;
-    private long gHotSpotVMTypeEntryTypeNameOffset;
-    private long gHotSpotVMTypeEntrySuperclassNameOffset;
-    private long gHotSpotVMTypeEntryIsOopTypeOffset;
-    private long gHotSpotVMTypeEntryIsIntegerTypeOffset;
-    private long gHotSpotVMTypeEntryIsUnsignedOffset;
-    private long gHotSpotVMTypeEntrySizeOffset;
-    private long gHotSpotVMTypeEntryArrayStride;
+    @HotSpotVMValue(expression = "gHotSpotVMTypes", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMTypes;
+    @HotSpotVMValue(expression = "gHotSpotVMTypeEntryTypeNameOffset") @Stable private long gHotSpotVMTypeEntryTypeNameOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMTypeEntrySuperclassNameOffset") @Stable private long gHotSpotVMTypeEntrySuperclassNameOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMTypeEntryIsOopTypeOffset") @Stable private long gHotSpotVMTypeEntryIsOopTypeOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMTypeEntryIsIntegerTypeOffset") @Stable private long gHotSpotVMTypeEntryIsIntegerTypeOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMTypeEntryIsUnsignedOffset") @Stable private long gHotSpotVMTypeEntryIsUnsignedOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMTypeEntrySizeOffset") @Stable private long gHotSpotVMTypeEntrySizeOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMTypeEntryArrayStride") @Stable private long gHotSpotVMTypeEntryArrayStride;
 
     class VMTypes implements Iterable<VMTypes.Type> {
 
@@ -476,10 +480,10 @@
     /**
      * VMIntConstantEntry (see vmStructs.hpp).
      */
-    private long gHotSpotVMIntConstants;
-    private long gHotSpotVMIntConstantEntryNameOffset;
-    private long gHotSpotVMIntConstantEntryValueOffset;
-    private long gHotSpotVMIntConstantEntryArrayStride;
+    @HotSpotVMValue(expression = "gHotSpotVMIntConstants", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMIntConstants;
+    @HotSpotVMValue(expression = "gHotSpotVMIntConstantEntryNameOffset") @Stable private long gHotSpotVMIntConstantEntryNameOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMIntConstantEntryValueOffset") @Stable private long gHotSpotVMIntConstantEntryValueOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMIntConstantEntryArrayStride") @Stable private long gHotSpotVMIntConstantEntryArrayStride;
 
     class VMIntConstants implements Iterable<VMIntConstants.Constant> {
 
@@ -540,10 +544,10 @@
     /**
      * VMLongConstantEntry (see vmStructs.hpp).
      */
-    private long gHotSpotVMLongConstants;
-    private long gHotSpotVMLongConstantEntryNameOffset;
-    private long gHotSpotVMLongConstantEntryValueOffset;
-    private long gHotSpotVMLongConstantEntryArrayStride;
+    @HotSpotVMValue(expression = "gHotSpotVMLongConstants", get = HotSpotVMValue.Type.ADDRESS) @Stable private long gHotSpotVMLongConstants;
+    @HotSpotVMValue(expression = "gHotSpotVMLongConstantEntryNameOffset") @Stable private long gHotSpotVMLongConstantEntryNameOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMLongConstantEntryValueOffset") @Stable private long gHotSpotVMLongConstantEntryValueOffset;
+    @HotSpotVMValue(expression = "gHotSpotVMLongConstantEntryArrayStride") @Stable private long gHotSpotVMLongConstantEntryArrayStride;
 
     class VMLongConstants implements Iterable<VMLongConstants.Constant> {
 
@@ -699,7 +703,7 @@
     }
 
     // os information, register layout, code generation, ...
-    @HotSpotVMConstant(name = "ASSERT") @Stable public boolean cAssertions;
+    @HotSpotVMValue(expression = "DEBUG_ONLY(1) NOT_DEBUG(0)") @Stable public boolean cAssertions;
     public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
 
     @HotSpotVMFlag(name = "CodeEntryAlignment") @Stable public int codeEntryAlignment;
@@ -708,14 +712,15 @@
     @HotSpotVMFlag(name = "CITimeEach") @Stable public boolean ciTimeEach;
     @HotSpotVMFlag(name = "CompileThreshold") @Stable public long compileThreshold;
     @HotSpotVMFlag(name = "CompileTheWorld") @Stable public boolean compileTheWorld;
-    @HotSpotVMFlag(name = "CompileTheWorldStartAt") @Stable public int compileTheWorldStartAt;
-    @HotSpotVMFlag(name = "CompileTheWorldStopAt") @Stable public int compileTheWorldStopAt;
+    @HotSpotVMFlag(name = "CompileTheWorldStartAt", optional = true) @Stable public int compileTheWorldStartAt;
+    @HotSpotVMFlag(name = "CompileTheWorldStopAt", optional = true) @Stable public int compileTheWorldStopAt;
     @HotSpotVMFlag(name = "DontCompileHugeMethods") @Stable public boolean dontCompileHugeMethods;
     @HotSpotVMFlag(name = "HugeMethodLimit") @Stable public int hugeMethodLimit;
     @HotSpotVMFlag(name = "PrintCompilation") @Stable public boolean printCompilation;
     @HotSpotVMFlag(name = "CIPrintCompilerName") @Stable public boolean printCompilerName;
     @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining;
     @HotSpotVMFlag(name = "GraalUseFastLocking") @Stable public boolean useFastLocking;
+    @HotSpotVMFlag(name = "UseGraalCompilationQueue", optional = true) @Stable public boolean useGraalCompilationQueue;
     @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable;
     @HotSpotVMFlag(name = "GPUOffload") @Stable public boolean gpuOffload;
     @HotSpotVMFlag(name = "TieredCompilation") @Stable public boolean tieredCompilation;
@@ -736,6 +741,8 @@
     @HotSpotVMFlag(name = "AllocatePrefetchStepSize") @Stable public int allocatePrefetchStepSize;
     @HotSpotVMFlag(name = "AllocatePrefetchDistance") @Stable public int allocatePrefetchDistance;
 
+    @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder;
+
     @HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap;
     @HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset;
 
@@ -794,6 +801,7 @@
     // offsets, ...
     @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages;
     @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging;
+    @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias;
 
     @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset;
     @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset;
@@ -844,12 +852,12 @@
 
     @HotSpotVMType(name = "vtableEntry", get = HotSpotVMType.Type.SIZE) @Stable public int vtableEntrySize;
     @HotSpotVMField(name = "vtableEntry::_method", type = "Method*", get = HotSpotVMField.Type.OFFSET) @Stable public int vtableEntryMethodOffset;
-    @Stable public int instanceKlassVtableStartOffset;
+    @HotSpotVMValue(expression = "InstanceKlass::vtable_start_offset() * HeapWordSize") @Stable public int instanceKlassVtableStartOffset;
 
     /**
      * The offset of the array length word in an array object's header.
      */
-    @Stable public int arrayLengthOffset;
+    @HotSpotVMValue(expression = "arrayOopDesc::length_offset_in_bytes()") @Stable public int arrayLengthOffset;
 
     @HotSpotVMField(name = "Array<int>::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1LengthOffset;
     @HotSpotVMField(name = "Array<u1>::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1DataOffset;
@@ -891,7 +899,7 @@
     @HotSpotVMField(name = "JavaThread::_is_method_handle_return", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int threadIsMethodHandleReturnOffset;
     @HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "ObjPtrQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset;
     @HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset;
-    @HotSpotVMField(name = "JavaThread::_graal_counters[0]", type = "jlong", get = HotSpotVMField.Type.OFFSET, optional = true) @Stable public int graalCountersThreadOffset;
+    @HotSpotVMValue(expression = "in_bytes(JavaThread::graal_counters_offset())") @Stable public int graalCountersThreadOffset;
 
     /**
      * An invalid value for {@link #rtldDefault}.
@@ -905,7 +913,7 @@
      *     void* (const char *filename, char *ebuf, int ebuflen)
      * </pre>
      */
-    @Stable public long dllLoad;
+    @HotSpotVMValue(expression = "os::dll_load", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dllLoad;
 
     /**
      * Address of the library lookup routine. The C signature of this routine is:
@@ -914,7 +922,7 @@
      *     void* (void* handle, const char* name)
      * </pre>
      */
-    @Stable public long dllLookup;
+    @HotSpotVMValue(expression = "os::dll_lookup", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dllLookup;
 
     /**
      * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will
@@ -922,7 +930,7 @@
      * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on
      * the current platform.
      */
-    @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE;
+    @HotSpotVMValue(expression = "RTLD_DEFAULT", defines = {"TARGET_OS_FAMILY_bsd", "TARGET_OS_FAMILY_linux"}, get = HotSpotVMValue.Type.ADDRESS) @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE;
 
     /**
      * This field is used to pass exception objects into and out of the runtime system during
@@ -1020,8 +1028,6 @@
      * exceptions from Hsail back to C++ runtime.
      */
     @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_notice_safepoints", type = "jint*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNoticeSafepointsOffset;
-    @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 hsailDeoptOccurredOffset;
     @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;
@@ -1029,11 +1035,13 @@
 
     @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;
+    @HotSpotVMField(name = "HSAILFrame::_num_d_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumDRegOffset;
+    @HotSpotVMType(name = "HSAILFrame", get = HotSpotVMType.Type.SIZE) @Stable public int hsailFrameHeaderSize;
+    @HotSpotVMType(name = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMType.Type.SIZE) @Stable public int hsailKernelDeoptimizationHeaderSize;
+    @HotSpotVMType(name = "Hsail::HSAILDeoptimizationInfo", get = HotSpotVMType.Type.SIZE) @Stable public int hsailDeoptimizationInfoHeaderSize;
 
     /**
      * Mark word right shift to get identity hash code.
@@ -1062,14 +1070,18 @@
     @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline;
     @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden;
     @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex;
+    @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex;
 
     @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
     @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
 
+    @HotSpotVMField(name = "CompileTask::_compile_id", type = "uint", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskCompileIdOffset;
+    @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset;
+
     /**
      * Value of Method::extra_stack_entries().
      */
-    @Stable public int extraStackEntries;
+    @HotSpotVMValue(expression = "Method::extra_stack_entries()") @Stable public int extraStackEntries;
 
     @HotSpotVMField(name = "ConstMethod::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodConstantsOffset;
     @HotSpotVMField(name = "ConstMethod::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodFlagsOffset;
@@ -1150,8 +1162,8 @@
     @HotSpotVMField(name = "Universe::_non_oop_bits", type = "intptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits;
 
     @HotSpotVMField(name = "StubRoutines::_verify_oop_count", type = "jint", get = HotSpotVMField.Type.ADDRESS) @Stable public long verifyOopCounterAddress;
-    @Stable public long verifyOopMask;
-    @Stable public long verifyOopBits;
+    @HotSpotVMValue(expression = "Universe::verify_oop_mask()") @Stable public long verifyOopMask;
+    @HotSpotVMValue(expression = "Universe::verify_oop_bits()") @Stable public long verifyOopBits;
 
     @HotSpotVMField(name = "CollectedHeap::_barrier_set", type = "BarrierSet*", get = HotSpotVMField.Type.OFFSET) @Stable public int collectedHeapBarrierSetOffset;
 
@@ -1241,13 +1253,13 @@
     @HotSpotVMType(name = "BasicLock", get = HotSpotVMType.Type.SIZE) @Stable public int basicLockSize;
     @HotSpotVMField(name = "BasicLock::_displaced_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int basicLockDisplacedHeaderOffset;
 
-    @Stable public long heapEndAddress;
-    @Stable public long heapTopAddress;
+    @HotSpotVMValue(expression = "Universe::heap()->end_addr()", get = HotSpotVMValue.Type.ADDRESS) @Stable public long heapEndAddress;
+    @HotSpotVMValue(expression = "Universe::heap()->top_addr()", get = HotSpotVMValue.Type.ADDRESS) @Stable public long heapTopAddress;
 
     @HotSpotVMField(name = "Thread::_allocated_bytes", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int threadAllocatedBytesOffset;
 
     @HotSpotVMFlag(name = "TLABWasteIncrement") @Stable public int tlabRefillWasteIncrement;
-    @Stable public int tlabAlignmentReserve;
+    @HotSpotVMValue(expression = "ThreadLocalAllocBuffer::alignment_reserve()") @Stable public int tlabAlignmentReserve;
 
     @HotSpotVMField(name = "ThreadLocalAllocBuffer::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferStartOffset;
     @HotSpotVMField(name = "ThreadLocalAllocBuffer::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferEndOffset;
@@ -1296,7 +1308,7 @@
     }
 
     @HotSpotVMFlag(name = "TLABStats") @Stable public boolean tlabStats;
-    @Stable public boolean inlineContiguousAllocationSupported;
+    @HotSpotVMValue(expression = " !CMSIncrementalMode && Universe::heap()->supports_inline_contig_alloc()") @Stable public boolean inlineContiguousAllocationSupported;
 
     /**
      * The DataLayout header size is the same as the cell size.
@@ -1352,8 +1364,6 @@
         return unsafe.getAddress(codeCacheHeap + codeHeapMemoryOffset + virtualSpaceHighBoundaryOffset);
     }
 
-    @Stable public long handleDeoptStub;
-
     @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub;
     @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub;
     @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_encryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingEncryptAESCryptStub;
@@ -1390,41 +1400,43 @@
     @HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy;
     @HotSpotVMField(name = "StubRoutines::_generic_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long genericArraycopy;
 
-    @Stable public long newInstanceAddress;
-    @Stable public long newArrayAddress;
-    @Stable public long newMultiArrayAddress;
-    @Stable public long dynamicNewArrayAddress;
-    @Stable public long dynamicNewInstanceAddress;
-    @Stable public long registerFinalizerAddress;
-    @Stable public long threadIsInterruptedAddress;
-    @Stable public long vmMessageAddress;
-    @Stable public long identityHashCodeAddress;
-    @Stable public long exceptionHandlerForPcAddress;
-    @Stable public long exceptionHandlerForReturnAddressAddress;
-    @Stable public long osrMigrationEndAddress;
-    @Stable public long monitorenterAddress;
-    @Stable public long monitorexitAddress;
-    @Stable public long createNullPointerExceptionAddress;
-    @Stable public long createOutOfBoundsExceptionAddress;
-    @Stable public long logPrimitiveAddress;
-    @Stable public long logObjectAddress;
-    @Stable public long logPrintfAddress;
-    @Stable public long vmErrorAddress;
-    @Stable public long writeBarrierPreAddress;
-    @Stable public long writeBarrierPostAddress;
-    @Stable public long validateObject;
-    @Stable public long javaTimeMillisAddress;
-    @Stable public long javaTimeNanosAddress;
-    @Stable public long arithmeticSinAddress;
-    @Stable public long arithmeticCosAddress;
-    @Stable public long arithmeticTanAddress;
-    @Stable public long loadAndClearExceptionAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::new_instance", get = HotSpotVMValue.Type.ADDRESS) @Stable public long newInstanceAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::new_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long newArrayAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::new_multi_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long newMultiArrayAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_array", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewArrayAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::dynamic_new_instance", get = HotSpotVMValue.Type.ADDRESS) @Stable public long dynamicNewInstanceAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::thread_is_interrupted", get = HotSpotVMValue.Type.ADDRESS) @Stable public long threadIsInterruptedAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::vm_message", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmMessageAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::identity_hash_code", get = HotSpotVMValue.Type.ADDRESS) @Stable public long identityHashCodeAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::exception_handler_for_pc", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForPcAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::monitorenter", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorenterAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::monitorexit", get = HotSpotVMValue.Type.ADDRESS) @Stable public long monitorexitAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::create_null_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long createNullPointerExceptionAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::create_out_of_bounds_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long createOutOfBoundsExceptionAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::log_primitive", get = HotSpotVMValue.Type.ADDRESS) @Stable public long logPrimitiveAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::log_object", get = HotSpotVMValue.Type.ADDRESS) @Stable public long logObjectAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::log_printf", get = HotSpotVMValue.Type.ADDRESS) @Stable public long logPrintfAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::vm_error", get = HotSpotVMValue.Type.ADDRESS) @Stable public long vmErrorAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::load_and_clear_exception", get = HotSpotVMValue.Type.ADDRESS) @Stable public long loadAndClearExceptionAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::write_barrier_pre", get = HotSpotVMValue.Type.ADDRESS) @Stable public long writeBarrierPreAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::write_barrier_post", get = HotSpotVMValue.Type.ADDRESS) @Stable public long writeBarrierPostAddress;
+    @HotSpotVMValue(expression = "GraalRuntime::validate_object", get = HotSpotVMValue.Type.ADDRESS) @Stable public long validateObject;
 
-    @Stable public int graalCountersSize;
+    @HotSpotVMValue(expression = "SharedRuntime::register_finalizer", get = HotSpotVMValue.Type.ADDRESS) @Stable public long registerFinalizerAddress;
+    @HotSpotVMValue(expression = "SharedRuntime::exception_handler_for_return_address", get = HotSpotVMValue.Type.ADDRESS) @Stable public long exceptionHandlerForReturnAddressAddress;
+    @HotSpotVMValue(expression = "SharedRuntime::OSR_migration_end", get = HotSpotVMValue.Type.ADDRESS) @Stable public long osrMigrationEndAddress;
 
-    @Stable public long deoptimizationFetchUnrollInfo;
-    @Stable public long deoptimizationUncommonTrap;
-    @Stable public long deoptimizationUnpackFrames;
+    @HotSpotVMValue(expression = "os::javaTimeMillis", get = HotSpotVMValue.Type.ADDRESS) @Stable public long javaTimeMillisAddress;
+    @HotSpotVMValue(expression = "os::javaTimeNanos", get = HotSpotVMValue.Type.ADDRESS) @Stable public long javaTimeNanosAddress;
+    @HotSpotVMValue(expression = "SharedRuntime::dsin", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticSinAddress;
+    @HotSpotVMValue(expression = "SharedRuntime::dcos", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticCosAddress;
+    @HotSpotVMValue(expression = "SharedRuntime::dtan", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticTanAddress;
+
+    @HotSpotVMValue(expression = "(jint) GraalCounterSize") @Stable public int graalCountersSize;
+
+    @HotSpotVMValue(expression = "Deoptimization::fetch_unroll_info", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationFetchUnrollInfo;
+    @HotSpotVMValue(expression = "Deoptimization::uncommon_trap", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUncommonTrap;
+    @HotSpotVMValue(expression = "Deoptimization::unpack_frames", get = HotSpotVMValue.Type.ADDRESS) @Stable public long deoptimizationUnpackFrames;
 
     @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone;
     @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConstant.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +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.hotspot;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMConstant {
-
-    String name();
-
-    /**
-     * List of architectures where this constant is required. Names are derived from
-     * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
-     * required on all architectures.
-     */
-    String[] archs() default {};
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMField.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMField {
-
-    enum Type {
-        OFFSET,
-        ADDRESS,
-        VALUE;
-    }
-
-    String name();
-
-    String type();
-
-    Type get();
-
-    /**
-     * List of architectures where this constant is required. Names are derived from
-     * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
-     * required on all architectures.
-     */
-    String[] archs() default {};
-
-    boolean optional() default false;
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMFlag {
-
-    String name();
-
-    /**
-     * List of architectures where this constant is required. Names are derived from
-     * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
-     * required on all architectures.
-     */
-    String[] archs() default {};
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMType.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +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.hotspot;
-
-import java.lang.annotation.*;
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface HotSpotVMType {
-
-    enum Type {
-        SIZE;
-    }
-
-    String name();
-
-    Type get();
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVmSymbols.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVmSymbols.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import sun.misc.*;
 
@@ -32,17 +32,17 @@
 public final class HotSpotVmSymbols {
 
     /**
-     * Returns the {@link HotSpotSymbol} in the {@code vmSymbols} table at position {@code index} as
-     * {@link String}.
-     * 
+     * Returns the symbol in the {@code vmSymbols} table at position {@code index} as {@link String}
+     * .
+     *
      * @param index position in the symbol table
      * @return the symbol at position id
      */
     public static String symbolAt(int index) {
-        HotSpotVMConfig config = runtime().getConfig();
+        HotSpotGraalRuntime runtime = runtime();
+        HotSpotVMConfig config = runtime.getConfig();
         assert config.vmSymbolsFirstSID <= index && index < config.vmSymbolsSIDLimit : "index " + index + " is out of bounds";
         assert config.symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken";
-        final long metaspaceSymbol = unsafe.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize);
-        return new HotSpotSymbol(metaspaceSymbol).asString();
+        return runtime.getCompilerToVM().getSymbol(unsafe.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize));
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri May 30 15:09:09 2014 +0200
@@ -35,13 +35,12 @@
 public interface CompilerToVM {
 
     /**
-     * Copies the original bytecode of a given method into a given byte array.
+     * Copies the original bytecode of a given method into a new byte array and returns it.
      *
      * @param metaspaceMethod the metaspace Method object
-     * @param code the array into which to copy the original bytecode
-     * @return the value of {@code code}
+     * @return a new byte array containing the original bytecode
      */
-    byte[] initializeBytecode(long metaspaceMethod, byte[] code);
+    byte[] getBytecode(long metaspaceMethod);
 
     int exceptionTableLength(long metaspaceMethod);
 
@@ -124,9 +123,9 @@
 
     int lookupNameAndTypeRefIndexInPool(long metaspaceConstantPool, int cpi);
 
-    long lookupNameRefInPool(long metaspaceConstantPool, int cpi);
+    String lookupNameRefInPool(long metaspaceConstantPool, int cpi);
 
-    long lookupSignatureRefInPool(long metaspaceConstantPool, int cpi);
+    String lookupSignatureRefInPool(long metaspaceConstantPool, int cpi);
 
     int lookupKlassRefIndexInPool(long metaspaceConstantPool, int cpi);
 
@@ -248,7 +247,7 @@
 
     void initializeConfiguration(HotSpotVMConfig config);
 
-    long resolveMethod(long metaspaceKlass, String name, String signature);
+    long resolveMethod(long metaspaceKlassExactReceiver, long metaspaceMethod, long metaspaceKlassCaller);
 
     long getClassInitializer(long metaspaceKlass);
 
@@ -334,6 +333,13 @@
     long getTimeStamp();
 
     /**
+     * Gets the value of a metaspace {@code Symbol} as a String.
+     * 
+     * @param metaspaceSymbol
+     */
+    String getSymbol(long metaspaceSymbol);
+
+    /**
      * Looks for the next Java stack frame with the given method.
      *
      * @param frame the starting point of the search, where {@code null} refers to the topmost frame
@@ -353,4 +359,6 @@
     void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
 
     void resolveInvokeDynamic(long metaspaceConstantPool, int index);
+
+    int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -43,7 +43,7 @@
     public native long getMetaspaceMethod(Class<?> holder, int slot);
 
     @Override
-    public native byte[] initializeBytecode(long metaspaceMethod, byte[] code);
+    public native byte[] getBytecode(long metaspaceMethod);
 
     @Override
     public native int exceptionTableLength(long metaspaceMethod);
@@ -71,10 +71,10 @@
     public native int lookupNameAndTypeRefIndexInPool(long metaspaceConstantPool, int cpi);
 
     @Override
-    public native long lookupNameRefInPool(long metaspaceConstantPool, int cpi);
+    public native String lookupNameRefInPool(long metaspaceConstantPool, int cpi);
 
     @Override
-    public native long lookupSignatureRefInPool(long metaspaceConstantPool, int cpi);
+    public native String lookupSignatureRefInPool(long metaspaceConstantPool, int cpi);
 
     @Override
     public native int lookupKlassRefIndexInPool(long metaspaceConstantPool, int cpi);
@@ -99,7 +99,7 @@
     public native void initializeConfiguration(HotSpotVMConfig config);
 
     @Override
-    public native long resolveMethod(long metaspaceKlass, String name, String signature);
+    public native long resolveMethod(long metaspaceKlassExactReceiver, long metaspaceMethod, long metaspaceKlassCaller);
 
     @Override
     public native boolean hasFinalizableSubclass(long metaspaceKlass);
@@ -181,5 +181,9 @@
 
     public native long getTimeStamp();
 
+    public native String getSymbol(long metaspaceSymbol);
+
     public native void resolveInvokeDynamic(long metaspaceConstantPool, int index);
+
+    public native int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Fri May 30 15:09:09 2014 +0200
@@ -30,18 +30,24 @@
  */
 public interface VMToCompiler {
 
-    /**
-     * Compiles a method to machine code. This method is called from the VM
-     * (VMToCompiler::compileMethod).
-     */
-    void compileMethod(long metaspaceMethod, int entryBCI, boolean blocking);
-
-    void shutdownCompiler() throws Exception;
+    void startRuntime();
 
     void startCompiler(boolean bootstrapEnabled) throws Throwable;
 
     void bootstrap() throws Throwable;
 
+    /**
+     * Compiles a method to machine code. This method is called from the VM
+     * (VMToCompiler::compileMethod).
+     *
+     * @param ctask the CompileTask pointer if this is a request from a HotSpot compiler thread
+     */
+    void compileMethod(long metaspaceMethod, int entryBCI, long ctask, boolean blocking);
+
+    void shutdownCompiler() throws Exception;
+
+    void shutdownRuntime() throws Throwable;
+
     void compileTheWorld() throws Throwable;
 
     PrintStream log();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.hotspot.CompileTheWorld.Options.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -40,6 +41,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.CompilationTask.Enqueueing;
 import com.oracle.graal.hotspot.CompileTheWorld.Config;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime.InitTimer;
 import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
@@ -91,7 +93,7 @@
      * is in the proper state.
      */
     static class Queue {
-        private ThreadPoolExecutor executor;
+        private final ThreadPoolExecutor executor;
 
         Queue(CompilerThreadFactory factory) {
             executor = new ThreadPoolExecutor(Threads.getValue(), Threads.getValue(), 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<Runnable>(), factory);
@@ -117,11 +119,19 @@
             executor.execute(task);
         }
 
+        /**
+         * @see ExecutorService#isShutdown()
+         */
+        public boolean isShutdown() {
+            return executor.isShutdown();
+        }
+
         public void shutdown() throws InterruptedException {
             assert CompilationTask.isWithinEnqueue();
-            executor.shutdown();
-            if (Debug.isEnabled() && Dump.getValue() != null) {
-                // Wait 2 seconds to flush out all graph dumps that may be of interest
+            executor.shutdownNow();
+            if (Debug.isEnabled() && (Dump.getValue() != null || areMetricsOrTimersEnabled())) {
+                // Wait up to 2 seconds to flush out all graph dumps and stop metrics/timers
+                // being updated.
                 executor.awaitTermination(2, TimeUnit.SECONDS);
             }
         }
@@ -136,15 +146,13 @@
 
     private PrintStream log = System.out;
 
-    private long compilerStartTime;
+    private long runtimeStartTime;
 
     public VMToCompilerImpl(HotSpotGraalRuntime runtime) {
         this.runtime = runtime;
     }
 
-    public void startCompiler(boolean bootstrapEnabled) throws Throwable {
-
-        bootstrapRunning = bootstrapEnabled;
+    public void startRuntime() {
 
         if (LogFile.getValue() != null) {
             try {
@@ -185,65 +193,83 @@
         assert VerifyOptionsPhase.checkOptions(hostProviders.getMetaAccess());
 
         // Complete initialization of backends
-        hostBackend.completeInitialization();
+        try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) {
+            hostBackend.completeInitialization();
+        }
         for (HotSpotBackend backend : runtime.getBackends().values()) {
             if (backend != hostBackend) {
-                backend.completeInitialization();
-            }
-        }
-
-        // Create compilation queue.
-        CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() {
-            public GraalDebugConfig getDebugConfig() {
-                return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null;
-            }
-        });
-        compileQueue = new Queue(factory);
-
-        // Create queue status printing thread.
-        if (PrintQueue.getValue()) {
-            Thread t = new Thread() {
-
-                @Override
-                public void run() {
-                    while (true) {
-                        TTY.println(compileQueue.toString());
-                        try {
-                            Thread.sleep(1000);
-                        } catch (InterruptedException e) {
-                        }
-                    }
+                try (InitTimer st = timer(backend.getTarget().arch.getName(), ".completeInitialization")) {
+                    backend.completeInitialization();
                 }
-            };
-            t.setDaemon(true);
-            t.start();
-        }
-
-        if (PrintCompRate.getValue() != 0) {
-            if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) {
-                throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach");
             }
-            Thread t = new Thread() {
-
-                @Override
-                public void run() {
-                    while (true) {
-                        runtime.getCompilerToVM().printCompilationStatistics(true, false);
-                        runtime.getCompilerToVM().resetCompilationStatistics();
-                        try {
-                            Thread.sleep(PrintCompRate.getValue());
-                        } catch (InterruptedException e) {
-                        }
-                    }
-                }
-            };
-            t.setDaemon(true);
-            t.start();
         }
 
         BenchmarkCounters.initialize(runtime.getCompilerToVM());
 
-        compilerStartTime = System.nanoTime();
+        runtimeStartTime = System.nanoTime();
+    }
+
+    public void startCompiler(boolean bootstrapEnabled) throws Throwable {
+        try (InitTimer timer = timer("startCompiler")) {
+            startCompiler0(bootstrapEnabled);
+        }
+    }
+
+    private void startCompiler0(boolean bootstrapEnabled) throws Throwable {
+
+        bootstrapRunning = bootstrapEnabled;
+
+        if (runtime.getConfig().useGraalCompilationQueue) {
+
+            // Create compilation queue.
+            CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() {
+                public GraalDebugConfig getDebugConfig() {
+                    return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null;
+                }
+            });
+            compileQueue = new Queue(factory);
+
+            // Create queue status printing thread.
+            if (PrintQueue.getValue()) {
+                Thread t = new Thread() {
+
+                    @Override
+                    public void run() {
+                        while (true) {
+                            TTY.println(compileQueue.toString());
+                            try {
+                                Thread.sleep(1000);
+                            } catch (InterruptedException e) {
+                            }
+                        }
+                    }
+                };
+                t.setDaemon(true);
+                t.start();
+            }
+
+            if (PrintCompRate.getValue() != 0) {
+                if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) {
+                    throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach");
+                }
+                Thread t = new Thread() {
+
+                    @Override
+                    public void run() {
+                        while (true) {
+                            runtime.getCompilerToVM().printCompilationStatistics(true, false);
+                            runtime.getCompilerToVM().resetCompilationStatistics();
+                            try {
+                                Thread.sleep(PrintCompRate.getValue());
+                            } catch (InterruptedException e) {
+                            }
+                        }
+                    }
+                };
+                t.setDaemon(true);
+                t.start();
+            }
+        }
     }
 
     /**
@@ -272,7 +298,7 @@
             TTY.flush();
         }
 
-        long startTime = System.currentTimeMillis();
+        long boostrapStartTime = System.currentTimeMillis();
 
         boolean firstRun = true;
         do {
@@ -308,12 +334,12 @@
                 // Are we out of time?
                 final int timedBootstrap = TimedBootstrap.getValue();
                 if (timedBootstrap != -1) {
-                    if ((System.currentTimeMillis() - startTime) > timedBootstrap) {
+                    if ((System.currentTimeMillis() - boostrapStartTime) > timedBootstrap) {
                         break;
                     }
                 }
             }
-        } while ((System.currentTimeMillis() - startTime) <= TimedBootstrap.getValue());
+        } while ((System.currentTimeMillis() - boostrapStartTime) <= TimedBootstrap.getValue());
 
         if (ResetDebugValuesAfterBootstrap.getValue()) {
             printDebugValues("bootstrap", true);
@@ -324,7 +350,7 @@
         bootstrapRunning = false;
 
         if (PrintBootstrap.getValue()) {
-            TTY.println(" in %d ms (compiled %d methods)", System.currentTimeMillis() - startTime, compileQueue.getCompletedTaskCount());
+            TTY.println(" in %d ms (compiled %d methods)", System.currentTimeMillis() - boostrapStartTime, compileQueue.getCompletedTaskCount());
         }
 
         System.gc();
@@ -345,29 +371,33 @@
 
     private void enqueue(Method m) throws Throwable {
         JavaMethod javaMethod = runtime.getHostProviders().getMetaAccess().lookupJavaMethod(m);
-        assert !Modifier.isAbstract(((HotSpotResolvedJavaMethod) javaMethod).getModifiers()) && !Modifier.isNative(((HotSpotResolvedJavaMethod) javaMethod).getModifiers()) : javaMethod;
-        compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, false);
+        assert !((HotSpotResolvedJavaMethod) javaMethod).isAbstract() && !((HotSpotResolvedJavaMethod) javaMethod).isNative() : javaMethod;
+        compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, 0L, false);
     }
 
     public void shutdownCompiler() throws Exception {
-        try (Enqueueing enqueueing = new Enqueueing()) {
-            // We have to use a privileged action here because shutting down the compiler might be
-            // called from user code which very likely contains unprivileged frames.
-            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
-                public Void run() throws Exception {
-                    if (compileQueue != null) {
-                        compileQueue.shutdown();
+        if (runtime.getConfig().useGraalCompilationQueue) {
+            try (Enqueueing enqueueing = new Enqueueing()) {
+                // We have to use a privileged action here because shutting down the compiler might
+                // be called from user code which very likely contains unprivileged frames.
+                AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws Exception {
+                        if (compileQueue != null) {
+                            compileQueue.shutdown();
+                        }
+                        return null;
                     }
-                    return null;
-                }
-            });
+                });
+            }
         }
+    }
 
+    public void shutdownRuntime() throws Exception {
         printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false);
         phaseTransition("final");
 
         SnippetCounter.printGroups(TTY.out().out());
-        BenchmarkCounters.shutdown(runtime.getCompilerToVM(), compilerStartTime);
+        BenchmarkCounters.shutdown(runtime.getCompilerToVM(), runtimeStartTime);
     }
 
     private void printDebugValues(String phase, boolean reset) throws GraalInternalError {
@@ -462,18 +492,6 @@
         printMap(new DebugValueScope(null, result), debugValues);
     }
 
-    static long collectTotal(DebugValue value) {
-        List<DebugValueMap> maps = DebugValueMap.getTopLevelMaps();
-        long total = 0;
-        for (int i = 0; i < maps.size(); i++) {
-            DebugValueMap map = maps.get(i);
-            int index = value.getIndex();
-            total += map.getCurrentValue(index);
-            total += collectTotal(map.getChildren(), index);
-        }
-        return total;
-    }
-
     private static long collectTotal(List<DebugValueMap> maps, int index) {
         long total = 0;
         for (int i = 0; i < maps.size(); i++) {
@@ -537,22 +555,34 @@
     }
 
     @Override
-    public void compileMethod(long metaspaceMethod, final int entryBCI, final boolean blocking) {
+    public void compileMethod(long metaspaceMethod, final int entryBCI, long ctask, final boolean blocking) {
         final HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
-        // We have to use a privileged action here because compilations are enqueued from user code
-        // which very likely contains unprivileged frames.
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-            public Void run() {
-                compileMethod(method, entryBCI, blocking);
-                return null;
-            }
-        });
+        if (ctask != 0L) {
+            // This is on a VM CompilerThread - no user frames exist
+            compileMethod(method, entryBCI, ctask, false);
+        } else {
+            // We have to use a privileged action here because compilations are
+            // enqueued from user code which very likely contains unprivileged frames.
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    compileMethod(method, entryBCI, 0L, blocking);
+                    return null;
+                }
+            });
+        }
     }
 
     /**
      * Compiles a method to machine code.
      */
-    void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, final boolean blocking) {
+    void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, long ctask, final boolean blocking) {
+        if (ctask != 0L) {
+            HotSpotBackend backend = runtime.getHostBackend();
+            CompilationTask task = new CompilationTask(null, backend, method, entryBCI, ctask, false);
+            task.runCompilation();
+            return;
+        }
+
         boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
         if (osrCompilation && bootstrapRunning) {
             // no OSR compilations during bootstrap - the compiler is just too slow at this point,
@@ -574,13 +604,14 @@
             if (method.tryToQueueForCompilation()) {
                 assert method.isQueuedForCompilation();
 
-                HotSpotBackend backend = runtime.getHostBackend();
-                CompilationTask task = new CompilationTask(backend, method, entryBCI, block);
-
                 try {
-                    compileQueue.execute(task);
-                    if (block) {
-                        task.block();
+                    if (!compileQueue.executor.isShutdown()) {
+                        HotSpotBackend backend = runtime.getHostBackend();
+                        CompilationTask task = new CompilationTask(compileQueue.executor, backend, method, entryBCI, ctask, block);
+                        compileQueue.execute(task);
+                        if (block) {
+                            task.block();
+                        }
                     }
                 } catch (RejectedExecutionException e) {
                     // The compile queue was already shut down.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Fri May 30 15:09:09 2014 +0200
@@ -31,6 +31,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -40,7 +41,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.nodes.*;
 
@@ -99,7 +99,6 @@
 
     private static final boolean DUMP_STATIC = false;
 
-    public static String excludedClassPrefix = null;
     public static boolean enabled = false;
 
     public static final ConcurrentHashMap<String, Integer> indexes = new ConcurrentHashMap<>();
@@ -108,14 +107,23 @@
     public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>();
 
     @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
-    public static int getIndex(DynamicCounterNode counter) {
+    private static int getIndex(DynamicCounterNode counter) {
         if (!enabled) {
             throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName());
         }
-        String name = counter.getName();
+        String name;
         String group = counter.getGroup();
-        name = counter.isWithContext() && counter.graph().method() != null ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name +
-                        "#" + group;
+        if (counter.isWithContext()) {
+            StructuredGraph graph = counter.graph();
+            name = counter.getName() + " @ " + graph.graphId() + ":" + (graph.method() == null ? "" : MetaUtil.format("%h.%n", graph.method()));
+            if (graph.name != null) {
+                name += " (" + graph.name + ")";
+            }
+            name += "#" + group;
+
+        } else {
+            name = counter.getName() + "#" + group;
+        }
         Integer index = indexes.get(name);
         if (index == null) {
             synchronized (BenchmarkCounters.class) {
@@ -135,7 +143,7 @@
         return index;
     }
 
-    public static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
+    private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
         if (!groups.isEmpty()) {
             out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======");
             for (String group : new TreeSet<>(groups)) {
@@ -152,7 +160,7 @@
         }
     }
 
-    public static synchronized void clear(long[] counters) {
+    private static synchronized void clear(long[] counters) {
         delta = counters;
     }
 
@@ -228,7 +236,7 @@
         return (counter * 200 + 1) / sum / 2;
     }
 
-    public abstract static class CallbackOutputStream extends OutputStream {
+    private abstract static class CallbackOutputStream extends OutputStream {
 
         protected final PrintStream delegate;
         private final byte[][] patterns;
@@ -281,25 +289,30 @@
         final class BenchmarkCountersOutputStream extends CallbackOutputStream {
 
             private long startTime;
+            private boolean running;
             private boolean waitingForEnd;
 
             private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) {
-                super(delegate, new String[]{start, end, "\n"});
+                super(delegate, new String[]{"\n", end, start});
             }
 
             @Override
             protected void patternFound(int index) {
                 switch (index) {
-                    case 0:
+                    case 2:
                         startTime = System.nanoTime();
                         BenchmarkCounters.clear(compilerToVM.collectCounters());
+                        running = true;
                         break;
                     case 1:
-                        waitingForEnd = true;
+                        if (running) {
+                            waitingForEnd = true;
+                        }
                         break;
-                    case 2:
+                    case 0:
                         if (waitingForEnd) {
                             waitingForEnd = false;
+                            running = false;
                             BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters(), 100);
                         }
                         break;
@@ -321,7 +334,6 @@
                     throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out");
                 }
             }
-            excludedClassPrefix = "Lcom/oracle/graal/";
             enabled = true;
         }
         if (Options.GenericDynamicCounters.getValue()) {
@@ -363,26 +375,24 @@
 
     public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) {
         StructuredGraph graph = counter.graph();
-        if (excludedClassPrefix == null || (counter.graph().method() != null && !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix))) {
 
-            ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
+        ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
 
-            int index = BenchmarkCounters.getIndex(counter);
-            if (index >= config.graalCountersSize) {
-                throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
-            }
-            ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset, graph);
-            ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
-            ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
-            ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
-            IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
-            WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
+        int index = BenchmarkCounters.getIndex(counter);
+        if (index >= config.graalCountersSize) {
+            throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
+        }
+        ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, wordKind, config.graalCountersThreadOffset, graph);
+        ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE));
+        ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
+        ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE));
+        IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
+        WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE));
 
-            graph.addBeforeFixed(counter, thread);
-            graph.addBeforeFixed(counter, readArray);
-            graph.addBeforeFixed(counter, read);
-            graph.addBeforeFixed(counter, write);
-        }
+        graph.addBeforeFixed(counter, thread);
+        graph.addBeforeFixed(counter, readArray);
+        graph.addBeforeFixed(counter, read);
+        graph.addBeforeFixed(counter, write);
         graph.removeFixed(counter);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EmptyEventProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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.events;
+
+import com.oracle.graal.compiler.common.*;
+
+/**
+ * An empty implementation for {@link EventProvider}. This implementation is used when no logging is
+ * requested.
+ */
+public final class EmptyEventProvider implements EventProvider {
+
+    public CompilationEvent newCompilationEvent() {
+        return new EmptyCompilationEvent();
+    }
+
+    class EmptyCompilationEvent implements CompilationEvent {
+        public void commit() {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public boolean shouldWrite() {
+            // Events of this class should never been written.
+            return false;
+        }
+
+        public void begin() {
+        }
+
+        public void end() {
+        }
+
+        public void setMethod(String method) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setCompileId(int compileId) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setCompileLevel(int compileLevel) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setSucceeded(boolean succeeded) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setIsOsr(boolean isOsr) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setCodeSize(int codeSize) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setInlinedBytes(int inlinedBytes) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public CompilerFailureEvent newCompilerFailureEvent() {
+        return new EmptyCompilerFailureEvent();
+    }
+
+    class EmptyCompilerFailureEvent implements CompilerFailureEvent {
+        public void commit() {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public boolean shouldWrite() {
+            // Events of this class should never been written.
+            return false;
+        }
+
+        public void setCompileId(int compileId) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setMessage(String message) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EventProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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.events;
+
+/**
+ * A provider that provides a specific implementation for events that can be logged in the compiler.
+ */
+public interface EventProvider {
+
+    /**
+     * An instant event is an event that is not considered to have taken any time.
+     */
+    interface InstantEvent {
+        /**
+         * Commits the event.
+         */
+        void commit();
+
+        /**
+         * Determines if this particular event instance would be committed to the data stream right
+         * now if application called {@link #commit()}. This in turn depends on whether the event is
+         * enabled and possible other factors.
+         *
+         * @return if this event would be committed on a call to {@link #commit()}.
+         */
+        boolean shouldWrite();
+    }
+
+    /**
+     * Timed events describe an operation that somehow consumes time.
+     */
+    interface TimedEvent extends InstantEvent {
+        /**
+         * Starts the timing for this event.
+         */
+        void begin();
+
+        /**
+         * Ends the timing period for this event.
+         */
+        void end();
+    }
+
+    /**
+     * Creates a new {@link CompilationEvent}.
+     *
+     * @return a compilation event
+     */
+    CompilationEvent newCompilationEvent();
+
+    /**
+     * A compilation event.
+     */
+    interface CompilationEvent extends TimedEvent {
+        void setMethod(String method);
+
+        void setCompileId(int compileId);
+
+        void setCompileLevel(int compileLevel);
+
+        void setSucceeded(boolean succeeded);
+
+        void setIsOsr(boolean isOsr);
+
+        void setCodeSize(int codeSize);
+
+        void setInlinedBytes(int inlinedBytes);
+    }
+
+    /**
+     * Creates a new {@link CompilerFailureEvent}.
+     *
+     * @return a compiler failure event
+     */
+    CompilerFailureEvent newCompilerFailureEvent();
+
+    /**
+     * A compiler failure event.
+     */
+    interface CompilerFailureEvent extends InstantEvent {
+        void setCompileId(int compileId);
+
+        void setMessage(String message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.meta;
+
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.debug.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * HotSpot implementation of {@link LoweringProvider}.
+ */
+public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider implements HotSpotLoweringProvider {
+
+    protected final HotSpotGraalRuntime runtime;
+    protected final ForeignCallsProvider foreignCalls;
+    protected final HotSpotRegistersProvider registers;
+
+    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
+    protected InstanceOfSnippets.Templates instanceofSnippets;
+    protected NewObjectSnippets.Templates newObjectSnippets;
+    protected MonitorSnippets.Templates monitorSnippets;
+    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
+    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
+    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
+
+    public DefaultHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, TargetDescription target) {
+        super(metaAccess, target);
+        this.runtime = runtime;
+        this.foreignCalls = foreignCalls;
+        this.registers = registers;
+    }
+
+    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
+        super.initialize(providers, providers.getSnippetReflection());
+
+        assert target == providers.getCodeCache().getTarget();
+        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
+        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
+        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
+        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
+        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
+        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
+        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
+        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        StructuredGraph graph = (StructuredGraph) n.graph();
+
+        if (n instanceof Invoke) {
+            lowerInvoke((Invoke) n, tool, graph);
+        } else if (n instanceof LoadMethodNode) {
+            lowerLoadMethodNode((LoadMethodNode) n);
+        } else if (n instanceof StoreHubNode) {
+            lowerStoreHubNode((StoreHubNode) n, graph);
+        } else if (n instanceof OSRStartNode) {
+            lowerOSRStartNode((OSRStartNode) n);
+        } else if (n instanceof DynamicCounterNode) {
+            lowerDynamicCounterNode((DynamicCounterNode) n);
+        } else if (n instanceof BytecodeExceptionNode) {
+            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
+        } else if (n instanceof CheckCastDynamicNode) {
+            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
+        } else if (n instanceof InstanceOfNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfNode) n, tool);
+            }
+        } else if (n instanceof InstanceOfDynamicNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
+            }
+        } else if (n instanceof NewInstanceNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewInstanceNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool);
+            }
+        } else if (n instanceof NewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewArrayNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool);
+            }
+        } else if (n instanceof MonitorEnterNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                monitorSnippets.lower((MonitorEnterNode) n, registers, tool);
+            }
+        } else if (n instanceof MonitorExitNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                monitorSnippets.lower((MonitorExitNode) n, tool);
+            }
+        } else if (n instanceof G1PreWriteBarrier) {
+            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1PostWriteBarrier) {
+            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ReferentFieldReadBarrier) {
+            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
+        } else if (n instanceof SerialWriteBarrier) {
+            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
+        } else if (n instanceof SerialArrayRangeWriteBarrier) {
+            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
+        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
+        } else if (n instanceof NewMultiArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+            }
+        } else if (n instanceof LoadExceptionObjectNode) {
+            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
+        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
+            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
+            // zero and the MIN_VALUE / -1 cases.
+        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode || n instanceof FloatRemNode) {
+            /* No lowering, we generate LIR directly for these nodes. */
+        } else {
+            super.lower(n, tool);
+        }
+    }
+
+    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
+        if (invoke.callTarget() instanceof MethodCallTargetNode) {
+            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+            NodeInputList<ValueNode> parameters = callTarget.arguments();
+            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
+            GuardingNode receiverNullCheck = null;
+            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isObjectNonNull(receiver)) {
+                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
+                invoke.setGuard(receiverNullCheck);
+            }
+            JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
+
+            LoweredCallTargetNode loweredCallTarget = null;
+            boolean isVirtualOrInterface = callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
+            if (InlineVTableStubs.getValue() && isVirtualOrInterface && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
+                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+                ResolvedJavaType receiverType = invoke.getReceiverType();
+                if (hsMethod.isInVirtualMethodTable(receiverType)) {
+                    Kind wordKind = runtime.getTarget().wordKind;
+                    ValueNode hub = createReadHub(graph, receiver, receiverNullCheck);
+
+                    ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod, receiverType);
+                    // We use LocationNode.ANY_LOCATION for the reads that access the
+                    // compiled code entry as HotSpot does not guarantee they are final
+                    // values.
+                    ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
+                                    StampFactory.forKind(wordKind), BarrierType.NONE));
+
+                    loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
+                                    CallingConvention.Type.JavaCall));
+
+                    graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+                    graph.addAfterFixed(metaspaceMethod, compiledEntry);
+                }
+            }
+
+            if (loweredCallTarget == null) {
+                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
+                                callTarget.invokeKind()));
+            }
+            callTarget.replaceAndDelete(loweredCallTarget);
+        }
+    }
+
+    @Override
+    protected Stamp loadStamp(Stamp stamp, Kind kind, boolean compressible) {
+        if (kind == Kind.Object && compressible && runtime.getConfig().useCompressedOops) {
+            return NarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getConfig().getOopEncoding());
+        }
+        return super.loadStamp(stamp, kind, compressible);
+    }
+
+    @Override
+    protected ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
+        if (kind == Kind.Object && compressible && runtime.getConfig().useCompressedOops) {
+            return CompressionNode.uncompress(value, runtime.getConfig().getOopEncoding());
+        }
+        return super.implicitLoadConvert(graph, kind, value, compressible);
+    }
+
+    @Override
+    protected ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField f) {
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f;
+        return ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph);
+    }
+
+    @Override
+    protected ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
+        if (kind == Kind.Object && compressible && runtime.getConfig().useCompressedOops) {
+            return CompressionNode.compress(value, runtime.getConfig().getOopEncoding());
+        }
+        return super.implicitStoreConvert(graph, kind, value, compressible);
+    }
+
+    @Override
+    protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor) {
+        Kind wordKind = runtime.getTarget().wordKind;
+        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph);
+        /*
+         * Anchor the read of the element klass to the cfg, because it is only valid when arrayClass
+         * is an object class, which might not be the case in other parts of the compiled method.
+         */
+        return graph.unique(new FloatingReadNode(arrayHub, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(anchor)));
+    }
+
+    @Override
+    protected void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
+        StructuredGraph graph = load.graph();
+        if (load.getGuardingCondition() == null && graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal() && addReadBarrier(load)) {
+            unsafeLoadSnippets.lower(load, tool);
+        } else {
+            super.lowerUnsafeLoadNode(load, tool);
+        }
+    }
+
+    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
+        StructuredGraph graph = loadMethodNode.graph();
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) loadMethodNode.getMethod();
+        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method, loadMethodNode.getReceiverType());
+        graph.replaceFixed(loadMethodNode, metaspaceMethod);
+    }
+
+    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
+        WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue());
+        graph.replaceFixed(storeHub, hub);
+    }
+
+    @Override
+    protected BarrierType fieldInitializationBarrier(Kind entryKind) {
+        return (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
+    }
+
+    @Override
+    protected BarrierType arrayInitializationBarrier(Kind entryKind) {
+        return (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
+    }
+
+    private void lowerOSRStartNode(OSRStartNode osrStart) {
+        StructuredGraph graph = osrStart.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            StartNode newStart = graph.add(new StartNode());
+            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
+            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
+            migrationEnd.setStateAfter(osrStart.stateAfter());
+
+            newStart.setNext(migrationEnd);
+            FixedNode next = osrStart.next();
+            osrStart.setNext(null);
+            migrationEnd.setNext(next);
+            graph.setStart(newStart);
+
+            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
+            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
+                int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind());
+                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
+                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1);
+                ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE));
+                osrLocal.replaceAndDelete(load);
+                graph.addBeforeFixed(migrationEnd, load);
+            }
+            osrStart.replaceAtUsages(newStart);
+            osrStart.safeDelete();
+        }
+    }
+
+    private void lowerDynamicCounterNode(DynamicCounterNode n) {
+        StructuredGraph graph = n.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
+        }
+    }
+
+    static final class Exceptions {
+        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
+        protected static final NullPointerException cachedNullPointerException;
+
+        static {
+            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
+            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
+            cachedNullPointerException = new NullPointerException();
+            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
+        }
+    }
+
+    public static final class RuntimeCalls {
+        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
+        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
+    }
+
+    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
+        StructuredGraph graph = node.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
+            if (OmitHotExceptionStacktrace.getValue()) {
+                Throwable exception;
+                if (node.getExceptionClass() == NullPointerException.class) {
+                    exception = Exceptions.cachedNullPointerException;
+                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+                    exception = Exceptions.cachedArrayIndexOutOfBoundsException;
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+                FloatingNode exceptionNode = ConstantNode.forConstant(HotSpotObjectConstant.forObject(exception), metaAccess, graph);
+                graph.replaceFixedWithFloating(node, exceptionNode);
+
+            } else {
+                ForeignCallDescriptor descriptor;
+                if (node.getExceptionClass() == NullPointerException.class) {
+                    descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
+                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+                    descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+
+                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
+                graph.replaceFixedWithFixed(node, foreignCallNode);
+            }
+        }
+    }
+
+    private static boolean addReadBarrier(UnsafeLoadNode load) {
+        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
+                        !StampTool.isObjectAlwaysNull(load.object())) {
+            ResolvedJavaType type = StampTool.typeOrNull(load.object());
+            if (type != null && !type.isArray()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, HotSpotResolvedJavaMethod method, ResolvedJavaType receiverType) {
+        return createReadVirtualMethod(graph, wordKind, hub, method.vtableEntryOffset(receiverType));
+    }
+
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, int vtableEntryOffset) {
+        assert vtableEntryOffset > 0;
+        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
+        // entry as HotSpot does not guarantee that this is a final value.
+        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE));
+        return metaspaceMethod;
+    }
+
+    @Override
+    protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard) {
+        Kind wordKind = target.wordKind;
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+
+        Stamp hubStamp;
+        if (config.useCompressedClassPointers) {
+            hubStamp = StampFactory.forInteger(32);
+        } else {
+            hubStamp = StampFactory.forKind(wordKind);
+        }
+
+        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(object, location, null, hubStamp, guard, BarrierType.NONE));
+        if (config.useCompressedClassPointers) {
+            return CompressionNode.uncompress(memoryRead, config.getKlassEncoding());
+        } else {
+            return memoryRead;
+        }
+    }
+
+    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+
+        ValueNode writeValue = value;
+        if (config.useCompressedClassPointers) {
+            writeValue = CompressionNode.compress(value, config.getKlassEncoding());
+        }
+
+        return graph.add(new WriteNode(object, writeValue, location, BarrierType.NONE));
+    }
+
+    @Override
+    protected BarrierType fieldLoadBarrierType(ResolvedJavaField f) {
+        HotSpotResolvedJavaField loadField = (HotSpotResolvedJavaField) f;
+        BarrierType barrierType = BarrierType.NONE;
+        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
+            barrierType = BarrierType.PRECISE;
+        }
+        return barrierType;
+    }
+
+    @Override
+    protected int fieldOffset(ResolvedJavaField f) {
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f;
+        return field.offset();
+    }
+
+    @Override
+    public int arrayScalingFactor(Kind kind) {
+        if (useCompressedOops() && kind == Kind.Object) {
+            return this.runtime.getTarget().getSizeInBytes(Kind.Int);
+        }
+        return super.arrayScalingFactor(kind);
+    }
+
+    @Override
+    protected int arrayBaseOffset(Kind kind) {
+        return HotSpotGraalRuntime.getArrayBaseOffset(kind);
+    }
+
+    @Override
+    protected int arrayLengthOffset() {
+        return config().arrayLengthOffset;
+    }
+
+    @Override
+    protected LocationIdentity initLocationIdentity() {
+        return INIT_LOCATION;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -206,12 +206,12 @@
         return installedCode;
     }
 
-    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) {
+    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) {
         if (compResult.getId() == -1) {
             compResult.setId(method.allocateCompileId(compResult.getEntryBCI()));
         }
         HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), true);
-        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult), installedCode, method.getSpeculationLog());
+        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult, ctask), installedCode, method.getSpeculationLog());
         return logOrDump(installedCode, compResult);
     }
 
@@ -236,7 +236,7 @@
     @Override
     public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) {
         HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method;
-        return installMethod(hotspotMethod, compResult);
+        return installMethod(hotspotMethod, compResult, 0L);
     }
 
     public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) {
@@ -286,4 +286,8 @@
     public String disassemble(ResolvedJavaMethod method) {
         return new BytecodeDisassembler().disassemble(method);
     }
+
+    public SpeculationLog createSpeculationLog() {
+        return new HotSpotSpeculationLog();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.meta;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+
+/**
+ * The compressed representation of the {@link Constant#NULL_OBJECT null constant}.
+ */
+public final class HotSpotCompressedNullConstant extends Constant implements HotSpotConstant {
+
+    private static final long serialVersionUID = 8906209595800783961L;
+
+    public static final Constant COMPRESSED_NULL = new HotSpotCompressedNullConstant();
+
+    private HotSpotCompressedNullConstant() {
+        super(NarrowOopStamp.NarrowOop);
+    }
+
+    @Override
+    public boolean isNull() {
+        return true;
+    }
+
+    @Override
+    public boolean isDefaultForKind() {
+        return true;
+    }
+
+    @Override
+    public Object asBoxedPrimitive() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public int asInt() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public boolean asBoolean() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public long asLong() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public float asFloat() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public double asDouble() {
+        throw new IllegalArgumentException();
+    }
+
+    @Override
+    public String toValueString() {
+        return "null";
+    }
+
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        assert o == this || !(o instanceof HotSpotCompressedNullConstant) : "null constant is a singleton";
+        return o == this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.meta;
+
+/**
+ * Marker interface for hotspot specific constants.
+ */
+public interface HotSpotConstant {
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.invoke.*;
@@ -256,9 +256,7 @@
      * @return name as {@link String}
      */
     private String getNameRefAt(int index) {
-        final long name = runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index);
-        HotSpotSymbol symbol = new HotSpotSymbol(name);
-        return symbol.asString();
+        return runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index);
     }
 
     /**
@@ -282,9 +280,7 @@
      * @return signature as {@link String}
      */
     private String getSignatureRefAt(int index) {
-        final long name = runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index);
-        HotSpotSymbol symbol = new HotSpotSymbol(name);
-        return symbol.asString();
+        return runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index);
     }
 
     /**
@@ -383,9 +379,7 @@
     @Override
     public String lookupUtf8(int cpi) {
         assertTag(cpi, JVM_CONSTANT.Utf8);
-        final long metaspaceSymbol = getEntryAt(cpi);
-        HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol);
-        return symbol.asString();
+        return runtime().getCompilerToVM().getSymbol(getEntryAt(cpi));
     }
 
     @Override
@@ -412,11 +406,12 @@
      * @param metaspacePointer either a metaspace Klass or a metaspace Symbol
      */
     private static JavaType getJavaType(final long metaspacePointer) {
-        HotSpotVMConfig config = runtime().getConfig();
+        HotSpotGraalRuntime runtime = runtime();
+        HotSpotVMConfig config = runtime.getConfig();
         if ((metaspacePointer & config.compilerToVMSymbolTag) != 0) {
             final long metaspaceSymbol = metaspacePointer & ~config.compilerToVMSymbolTag;
-            String name = new HotSpotSymbol(metaspaceSymbol).asString();
-            return HotSpotUnresolvedJavaType.create(name);
+            String name = runtime.getCompilerToVM().getSymbol(metaspaceSymbol);
+            return HotSpotUnresolvedJavaType.create("L" + name + ";");
         } else {
             assert (metaspacePointer & config.compilerToVMKlassTag) == 0;
             return HotSpotResolvedObjectType.fromMetaspaceKlass(metaspacePointer);
@@ -529,6 +524,9 @@
                 }
                 break;
             case InvokeDynamic:
+                if (!isInvokedynamicIndex(cpi)) {
+                    throw new IllegalArgumentException("InvokeDynamic entries must be accessed");
+                }
                 runtime().getCompilerToVM().resolveInvokeDynamic(metaspaceConstantPool, cpi);
                 break;
             default:
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
 import java.lang.reflect.*;
@@ -223,7 +223,7 @@
 
     @Override
     public ResolvedJavaType asJavaType(Constant constant) {
-        if (constant.getKind() == Kind.Object) {
+        if (constant instanceof HotSpotObjectConstant) {
             Object obj = HotSpotObjectConstant.asObject(constant);
             if (obj instanceof Class) {
                 return runtime.getHostProviders().getMetaAccess().lookupJavaType((Class<?>) obj);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -27,25 +27,19 @@
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
-import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
-import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
-import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
+import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
 import static com.oracle.graal.hotspot.replacements.ThreadSubstitutions.*;
 import static com.oracle.graal.hotspot.replacements.WriteBarrierSnippets.*;
-import static com.oracle.graal.hotspot.stubs.DeoptimizationStub.*;
 import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
 import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
-import static com.oracle.graal.hotspot.meta.HotSpotLoweringProvider.RuntimeCalls.*;
-import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
+import static com.oracle.graal.nodes.java.ForeignCallDescriptors.*;
 import static com.oracle.graal.replacements.Log.*;
 import static com.oracle.graal.replacements.MathSubstitutionsX86.*;
 
@@ -103,7 +97,6 @@
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
         TargetDescription target = providers.getCodeCache().getTarget();
 
-        registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub(), NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
 
         registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
@@ -119,7 +112,14 @@
         registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
+        /*
+         * We cannot use LEAF_SP here because on some architectures we have to align the stack
+         * manually before calling into the VM. See {@link
+         * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}.
+         */
         registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
 
         link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -22,961 +22,25 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
-import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.debug.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.replacements.*;
 
 /**
  * HotSpot implementation of {@link LoweringProvider}.
  */
-public class HotSpotLoweringProvider implements LoweringProvider {
-
-    protected final HotSpotGraalRuntime runtime;
-    protected final MetaAccessProvider metaAccess;
-    protected final ForeignCallsProvider foreignCalls;
-    protected final HotSpotRegistersProvider registers;
-
-    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
-    protected InstanceOfSnippets.Templates instanceofSnippets;
-    protected NewObjectSnippets.Templates newObjectSnippets;
-    protected MonitorSnippets.Templates monitorSnippets;
-    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
-    protected BoxingSnippets.Templates boxingSnippets;
-    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
-    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
-
-    public HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
-        this.runtime = runtime;
-        this.metaAccess = metaAccess;
-        this.foreignCalls = foreignCalls;
-        this.registers = registers;
-    }
-
-    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
-        TargetDescription target = providers.getCodeCache().getTarget();
-        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
-        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
-        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
-        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
-        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
-        boxingSnippets = new BoxingSnippets.Templates(providers, providers.getSnippetReflection(), target);
-        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
-        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
-        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
-    }
-
-    @Override
-    public void lower(Node n, LoweringTool tool) {
-        StructuredGraph graph = (StructuredGraph) n.graph();
-
-        if (n instanceof ArrayLengthNode) {
-            lowerArrayLengthNode((ArrayLengthNode) n, tool);
-        } else if (n instanceof Invoke) {
-            lowerInvoke((Invoke) n, tool, graph);
-        } else if (n instanceof LoadFieldNode) {
-            lowerLoadFieldNode((LoadFieldNode) n, tool);
-        } else if (n instanceof StoreFieldNode) {
-            lowerStoreFieldNode((StoreFieldNode) n, tool);
-        } else if (n instanceof CompareAndSwapNode) {
-            lowerCompareAndSwapNode((CompareAndSwapNode) n);
-        } else if (n instanceof LoadIndexedNode) {
-            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
-        } else if (n instanceof StoreIndexedNode) {
-            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
-        } else if (n instanceof UnsafeLoadNode) {
-            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
-        } else if (n instanceof UnsafeStoreNode) {
-            lowerUnsafeStoreNode((UnsafeStoreNode) n);
-        } else if (n instanceof JavaReadNode) {
-            lowerJavaReadNode((JavaReadNode) n);
-        } else if (n instanceof JavaWriteNode) {
-            lowerJavaWriteNode((JavaWriteNode) n);
-        } else if (n instanceof LoadHubNode) {
-            lowerLoadHubNode((LoadHubNode) n);
-        } else if (n instanceof LoadMethodNode) {
-            lowerLoadMethodNode((LoadMethodNode) n);
-        } else if (n instanceof StoreHubNode) {
-            lowerStoreHubNode((StoreHubNode) n, graph);
-        } else if (n instanceof CommitAllocationNode) {
-            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
-        } else if (n instanceof OSRStartNode) {
-            lowerOSRStartNode((OSRStartNode) n);
-        } else if (n instanceof DynamicCounterNode) {
-            lowerDynamicCounterNode((DynamicCounterNode) n);
-        } else if (n instanceof BytecodeExceptionNode) {
-            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
-        } else if (n instanceof CheckCastDynamicNode) {
-            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
-        } else if (n instanceof InstanceOfNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfNode) n, tool);
-            }
-        } else if (n instanceof InstanceOfDynamicNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
-            }
-        } else if (n instanceof NewInstanceNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
-            }
-        } else if (n instanceof DynamicNewInstanceNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool);
-            }
-        } else if (n instanceof NewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewArrayNode) n, registers, tool);
-            }
-        } else if (n instanceof DynamicNewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool);
-            }
-        } else if (n instanceof MonitorEnterNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                monitorSnippets.lower((MonitorEnterNode) n, registers, tool);
-            }
-        } else if (n instanceof MonitorExitNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                monitorSnippets.lower((MonitorExitNode) n, tool);
-            }
-        } else if (n instanceof G1PreWriteBarrier) {
-            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1PostWriteBarrier) {
-            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1ReferentFieldReadBarrier) {
-            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
-        } else if (n instanceof SerialWriteBarrier) {
-            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
-        } else if (n instanceof SerialArrayRangeWriteBarrier) {
-            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
-        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
-        } else if (n instanceof NewMultiArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
-            }
-        } else if (n instanceof LoadExceptionObjectNode) {
-            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
-        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
-            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
-            // zero and the MIN_VALUE / -1 cases.
-        } else if (n instanceof BoxNode) {
-            boxingSnippets.lower((BoxNode) n, tool);
-        } else if (n instanceof UnboxNode) {
-            boxingSnippets.lower((UnboxNode) n, tool);
-        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
-            /* No lowering, we generate LIR directly for these nodes. */
-        } else {
-            throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
-        }
-    }
-
-    private void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
-        StructuredGraph graph = arrayLengthNode.graph();
-        ValueNode array = arrayLengthNode.array();
-        ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, graph),
-                        StampFactory.positiveInt(), BarrierType.NONE, false));
-        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
-        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
-    }
-
-    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
-        if (invoke.callTarget() instanceof MethodCallTargetNode) {
-            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-            NodeInputList<ValueNode> parameters = callTarget.arguments();
-            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
-            GuardingNode receiverNullCheck = null;
-            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) {
-                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
-                invoke.setGuard(receiverNullCheck);
-            }
-            JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
-
-            LoweredCallTargetNode loweredCallTarget = null;
-            if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
-
-                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
-                if (!hsMethod.getDeclaringClass().isInterface()) {
-                    if (hsMethod.isInVirtualMethodTable()) {
-                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-                        assert vtableEntryOffset > 0;
-                        Kind wordKind = runtime.getTarget().wordKind;
-                        ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
-
-                        ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
-                        // We use LocationNode.ANY_LOCATION for the reads that access the
-                        // compiled code entry as HotSpot does not guarantee they are final
-                        // values.
-                        ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
-                                        StampFactory.forKind(wordKind), BarrierType.NONE, false));
-
-                        loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
-                                        CallingConvention.Type.JavaCall));
-
-                        graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
-                        graph.addAfterFixed(metaspaceMethod, compiledEntry);
-                    }
-                }
-            }
-
-            if (loweredCallTarget == null) {
-                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
-                                callTarget.invokeKind()));
-            }
-            callTarget.replaceAndDelete(loweredCallTarget);
-        }
-    }
-
-    private Stamp loadStamp(Stamp stamp, Kind kind) {
-        return loadStamp(stamp, kind, true);
-    }
-
-    private Stamp loadStamp(Stamp stamp, Kind kind, boolean compressible) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                return StampTool.narrowingConversion(stamp, 8);
-
-            case Char:
-            case Short:
-                return StampTool.narrowingConversion(stamp, 16);
-
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return new NarrowOopStamp((ObjectStamp) stamp, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return stamp;
-    }
-
-    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value) {
-        return implicitLoadConvert(graph, kind, value, true);
-    }
+public interface HotSpotLoweringProvider extends LoweringProvider {
 
-    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
-        switch (kind) {
-            case Byte:
-            case Short:
-                return graph.unique(new SignExtendNode(value, 32));
-
-            case Boolean:
-            case Char:
-                return graph.unique(new ZeroExtendNode(value, 32));
-
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return CompressionNode.uncompress(value, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return value;
-    }
-
-    private void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
-        StructuredGraph graph = loadField.graph();
-        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
-        ValueNode object = loadField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : loadField.object();
-        assert loadField.getKind() != Kind.Illegal;
-        BarrierType barrierType = getFieldLoadBarrierType(field);
-
-        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
-        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadStamp, barrierType, false));
-        ValueNode readValue = implicitLoadConvert(graph, field.getKind(), memoryRead);
-
-        loadField.replaceAtUsages(readValue);
-        graph.replaceFixed(loadField, memoryRead);
-
-        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
-
-        if (loadField.isVolatile()) {
-            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
-            graph.addBeforeFixed(memoryRead, preMembar);
-            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
-            graph.addAfterFixed(memoryRead, postMembar);
-        }
-    }
-
-    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value) {
-        return implicitStoreConvert(graph, kind, value, true);
-    }
-
-    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                return graph.unique(new NarrowNode(value, 8));
-            case Char:
-            case Short:
-                return graph.unique(new NarrowNode(value, 16));
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return CompressionNode.compress(value, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return value;
-    }
-
-    private void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
-        StructuredGraph graph = storeField.graph();
-        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
-        ValueNode object = storeField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : storeField.object();
-        BarrierType barrierType = getFieldStoreBarrierType(storeField);
-
-        ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
-        WriteNode memoryWrite = graph.add(new WriteNode(object, value, createFieldLocation(graph, field, false), barrierType, false));
-        memoryWrite.setStateAfter(storeField.stateAfter());
-        graph.replaceFixedWithFixed(storeField, memoryWrite);
-        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
-        FixedWithNextNode last = memoryWrite;
-        FixedWithNextNode first = memoryWrite;
-
-        if (storeField.isVolatile()) {
-            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
-            graph.addBeforeFixed(first, preMembar);
-            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
-            graph.addAfterFixed(last, postMembar);
-        }
-    }
-
-    private void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
-        StructuredGraph graph = cas.graph();
-        Kind valueKind = cas.getValueKind();
-        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), valueKind, cas.displacement(), cas.offset(), graph, 1);
-
-        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected(), true);
-        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue(), true);
-
-        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, expectedValue, newValue, getCompareAndSwapBarrierType(cas), false));
-        atomicNode.setStateAfter(cas.stateAfter());
-        graph.replaceFixedWithFixed(cas, atomicNode);
-    }
-
-    private void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
-        StructuredGraph graph = loadIndexed.graph();
-        Kind elementKind = loadIndexed.elementKind();
-        LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
-
-        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
-        ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadStamp, BarrierType.NONE, false));
-        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
-
-        memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
-
-        loadIndexed.replaceAtUsages(readValue);
-        graph.replaceFixed(loadIndexed, memoryRead);
-    }
+    void initialize(HotSpotProviders providers, HotSpotVMConfig config);
 
-    private void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
-        StructuredGraph graph = storeIndexed.graph();
-        GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
-        Kind elementKind = storeIndexed.elementKind();
-        LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
-
-        ValueNode value = storeIndexed.value();
-        ValueNode array = storeIndexed.array();
-
-        CheckCastNode checkcastNode = null;
-        CheckCastDynamicNode checkcastDynamicNode = null;
-        if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) {
-            // Store check!
-            ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
-            if (arrayType != null && ObjectStamp.isExactType(array)) {
-                ResolvedJavaType elementType = arrayType.getComponentType();
-                if (!MetaUtil.isJavaLangObject(elementType)) {
-                    checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
-                    graph.addBeforeFixed(storeIndexed, checkcastNode);
-                    value = checkcastNode;
-                }
-            } else {
-                Kind wordKind = runtime.getTarget().wordKind;
-                ValueNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
-                LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph);
-                /*
-                 * Anchor the read of the element klass to the cfg, because it is only valid when
-                 * arrayClass is an object class, which might not be the case in other parts of the
-                 * compiled method.
-                 */
-                FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
-                checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
-                graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
-                value = checkcastDynamicNode;
-            }
-        }
-        BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
-        WriteNode memoryWrite = graph.add(new WriteNode(array, implicitStoreConvert(graph, elementKind, value), arrayLocation, barrierType, false));
-        memoryWrite.setGuard(boundsCheck);
-        memoryWrite.setStateAfter(storeIndexed.stateAfter());
-        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
-
-        // Lower the associated checkcast node.
-        if (checkcastNode != null) {
-            checkcastNode.lower(tool);
-        } else if (checkcastDynamicNode != null) {
-            checkcastDynamicSnippets.lower(checkcastDynamicNode, tool);
-        }
-    }
-
-    private ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
-        boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-        Kind readKind = load.accessKind();
-        LocationNode location = createLocation(load);
-        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
-        ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, loadStamp, guard, BarrierType.NONE, false));
-        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
-        load.replaceAtUsages(readValue);
-        return memoryRead;
-    }
-
-    private void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
-        StructuredGraph graph = load.graph();
-        if (load.getGuardingCondition() != null) {
-            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
-            ReadNode memoryRead = createUnsafeRead(graph, load, valueAnchorNode);
-            graph.replaceFixedWithFixed(load, valueAnchorNode);
-            graph.addAfterFixed(valueAnchorNode, memoryRead);
-        } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
-            assert load.getKind() != Kind.Illegal;
-            if (addReadBarrier(load)) {
-                unsafeLoadSnippets.lower(load, tool);
-            } else {
-                ReadNode memoryRead = createUnsafeRead(graph, load, null);
-                // An unsafe read must not float outside its block otherwise
-                // it may float above an explicit null check on its object.
-                memoryRead.setGuard(BeginNode.prevBegin(load));
-                graph.replaceFixedWithFixed(load, memoryRead);
-            }
-        }
-    }
-
-    private void lowerUnsafeStoreNode(UnsafeStoreNode store) {
-        StructuredGraph graph = store.graph();
-        LocationNode location = createLocation(store);
-        ValueNode object = store.object();
-        BarrierType barrierType = getUnsafeStoreBarrierType(store);
-        boolean compressible = store.value().getKind() == Kind.Object;
-        Kind valueKind = store.accessKind();
-        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
-        WriteNode write = graph.add(new WriteNode(object, value, location, barrierType, false));
-        write.setStateAfter(store.stateAfter());
-        graph.replaceFixedWithFixed(store, write);
-    }
-
-    private void lowerJavaReadNode(JavaReadNode read) {
-        StructuredGraph graph = read.graph();
-
-        Kind valueKind = read.location().getValueKind();
-        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
-        ReadNode memoryRead = graph.add(new ReadNode(read.object(), read.location(), loadStamp, read.getBarrierType(), false));
-        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
-
-        memoryRead.setGuard(read.getGuard());
-
-        read.replaceAtUsages(readValue);
-        graph.replaceFixed(read, memoryRead);
-    }
-
-    private void lowerJavaWriteNode(JavaWriteNode write) {
-        StructuredGraph graph = write.graph();
-
-        Kind valueKind = write.location().getValueKind();
-        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
-
-        WriteNode memoryWrite = graph.add(new WriteNode(write.object(), value, write.location(), write.getBarrierType(), false, write.isInitialization()));
-        memoryWrite.setStateAfter(write.stateAfter());
-        graph.replaceFixedWithFixed(write, memoryWrite);
+    int arrayScalingFactor(Kind kind);
 
-        memoryWrite.setGuard(write.getGuard());
-    }
-
-    private void lowerLoadHubNode(LoadHubNode loadHub) {
-        StructuredGraph graph = loadHub.graph();
-        if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
-            Kind wordKind = runtime.getTarget().wordKind;
-            assert loadHub.getKind() == wordKind;
-            ValueNode object = loadHub.object();
-            GuardingNode guard = loadHub.getGuard();
-            ValueNode hub = createReadHub(graph, wordKind, object, guard);
-            graph.replaceFloating(loadHub, hub);
-        }
-    }
-
-    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
-        StructuredGraph graph = loadMethodNode.graph();
-        ResolvedJavaMethod method = loadMethodNode.getMethod();
-        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
-        graph.replaceFixed(loadMethodNode, metaspaceMethod);
-    }
-
-    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
-        WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue());
-        graph.replaceFixed(storeHub, hub);
-    }
-
-    private void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
-        StructuredGraph graph = commit.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
-            BitSet omittedValues = new BitSet();
-            int valuePos = 0;
-            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                int entryCount = virtual.entryCount();
-                FixedWithNextNode newObject;
-                if (virtual instanceof VirtualInstanceNode) {
-                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
-                } else {
-                    newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
-                }
-                graph.addBeforeFixed(commit, newObject);
-                allocations[objIndex] = newObject;
-                for (int i = 0; i < entryCount; i++) {
-                    ValueNode value = commit.getValues().get(valuePos);
-                    if (value instanceof VirtualObjectNode) {
-                        value = allocations[commit.getVirtualObjects().indexOf(value)];
-                    }
-                    if (value == null) {
-                        omittedValues.set(valuePos);
-                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                        // Constant.illegal is always the defaultForKind, so it is skipped
-                        Kind valueKind = value.getKind();
-                        Kind entryKind = virtual.entryKind(i);
-
-                        // Truffle requires some leniency in terms of what can be put where:
-                        Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
-                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
-                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
-                        ConstantLocationNode location;
-                        BarrierType barrierType;
-                        if (virtual instanceof VirtualInstanceNode) {
-                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
-                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
-                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
-                        } else {
-                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
-                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
-                        }
-                        WriteNode write = new WriteNode(newObject, implicitStoreConvert(graph, entryKind, value), location, barrierType, false);
-                        graph.addAfterFixed(newObject, graph.add(write));
-                    }
-                    valuePos++;
-
-                }
-            }
-            valuePos = 0;
-
-            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                int entryCount = virtual.entryCount();
-                ValueNode newObject = allocations[objIndex];
-                for (int i = 0; i < entryCount; i++) {
-                    if (omittedValues.get(valuePos)) {
-                        ValueNode value = commit.getValues().get(valuePos);
-                        assert value instanceof VirtualObjectNode;
-                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
-                            WriteNode write;
-                            if (virtual instanceof VirtualInstanceNode) {
-                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i),
-                                                true), BarrierType.IMPRECISE, false);
-                            } else {
-                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph),
-                                                true), BarrierType.PRECISE, false);
-                            }
-                            graph.addBeforeFixed(commit, graph.add(write));
-                        }
-                    }
-                    valuePos++;
-                }
-            }
-
-            finishAllocatedObjects(tool, commit, allocations);
-            graph.removeFixed(commit);
-        }
-    }
-
-    private void lowerOSRStartNode(OSRStartNode osrStart) {
-        StructuredGraph graph = osrStart.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-            StartNode newStart = graph.add(new StartNode());
-            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
-            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
-            migrationEnd.setStateAfter(osrStart.stateAfter());
-
-            newStart.setNext(migrationEnd);
-            FixedNode next = osrStart.next();
-            osrStart.setNext(null);
-            migrationEnd.setNext(next);
-            graph.setStart(newStart);
-
-            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
-            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
-            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
-                int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind());
-                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
-                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1);
-                ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
-                osrLocal.replaceAndDelete(load);
-                graph.addBeforeFixed(migrationEnd, load);
-            }
-            osrStart.replaceAtUsages(newStart);
-            osrStart.safeDelete();
-        }
-    }
-
-    private void lowerDynamicCounterNode(DynamicCounterNode n) {
-        StructuredGraph graph = n.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
-        }
-    }
-
-    static final class Exceptions {
-        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
-        protected static final NullPointerException cachedNullPointerException;
-
-        static {
-            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
-            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
-            cachedNullPointerException = new NullPointerException();
-            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
-        }
-    }
-
-    public static final class RuntimeCalls {
-        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
-        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
-    }
-
-    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
-        StructuredGraph graph = node.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
-            if (OmitHotExceptionStacktrace.getValue()) {
-                Throwable exception;
-                if (node.getExceptionClass() == NullPointerException.class) {
-                    exception = Exceptions.cachedNullPointerException;
-                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
-                    exception = Exceptions.cachedArrayIndexOutOfBoundsException;
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-                FloatingNode exceptionNode = ConstantNode.forConstant(HotSpotObjectConstant.forObject(exception), metaAccess, graph);
-                graph.replaceFixedWithFloating(node, exceptionNode);
-
-            } else {
-                ForeignCallDescriptor descriptor;
-                if (node.getExceptionClass() == NullPointerException.class) {
-                    descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
-                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
-                    descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-
-                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
-                graph.replaceFixedWithFixed(node, foreignCallNode);
-            }
-        }
-    }
-
-    protected static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
-        StructuredGraph graph = commit.graph();
-        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
-            allocations[objIndex] = anchor;
-            graph.addBeforeFixed(commit, anchor);
-        }
-        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
-                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
-                graph.addBeforeFixed(commit, enter);
-                enter.lower(tool);
-            }
-        }
-        for (Node usage : commit.usages().snapshot()) {
-            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
-            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
-            graph.replaceFloating(addObject, allocations[index]);
-        }
-    }
-
-    private static LocationNode createLocation(UnsafeAccessNode access) {
-        return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind());
-    }
-
-    private static LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind) {
-        ValueNode offset = offsetNode;
-        if (offset.isConstant()) {
-            long offsetValue = offset.asConstant().asLong();
-            return ConstantLocationNode.create(locationIdentity, accessKind, offsetValue, offset.graph());
-        }
+    IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization);
 
-        long displacement = 0;
-        int indexScaling = 1;
-        boolean signExtend = false;
-        if (offset instanceof SignExtendNode) {
-            SignExtendNode extend = (SignExtendNode) offset;
-            if (extend.getResultBits() == 64) {
-                signExtend = true;
-                offset = extend.getInput();
-            }
-        }
-        if (offset instanceof IntegerAddNode) {
-            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
-            if (integerAddNode.y() instanceof ConstantNode) {
-                displacement = integerAddNode.y().asConstant().asLong();
-                offset = integerAddNode.x();
-            }
-        }
-
-        if (offset instanceof LeftShiftNode) {
-            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
-            if (leftShiftNode.y() instanceof ConstantNode) {
-                long shift = leftShiftNode.y().asConstant().asLong();
-                if (shift >= 1 && shift <= 3) {
-                    if (shift == 1) {
-                        indexScaling = 2;
-                    } else if (shift == 2) {
-                        indexScaling = 4;
-                    } else {
-                        indexScaling = 8;
-                    }
-                    offset = leftShiftNode.x();
-                }
-            }
-        }
-        if (signExtend) {
-            // If we were using sign extended values before restore the sign extension.
-            offset = offset.graph().addOrUnique(new SignExtendNode(offset, 64));
-        }
-        return IndexedLocationNode.create(locationIdentity, accessKind, displacement, offset, offset.graph(), indexScaling);
-    }
-
-    private static boolean addReadBarrier(UnsafeLoadNode load) {
-        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
-                        !ObjectStamp.isObjectAlwaysNull(load.object())) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(load.object());
-            if (type != null && !type.isArray()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
-        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-        assert !hsMethod.getDeclaringClass().isInterface();
-        assert hsMethod.isInVirtualMethodTable();
-
-        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-        assert vtableEntryOffset > 0;
-        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
-        // entry as HotSpot does not guarantee that this is a final value.
-        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false));
-        return metaspaceMethod;
-    }
-
-    private ValueNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-
-        Stamp hubStamp;
-        if (config.useCompressedClassPointers) {
-            hubStamp = StampFactory.forInteger(32);
-        } else {
-            hubStamp = StampFactory.forKind(wordKind);
-        }
-
-        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(object, location, null, hubStamp, guard, BarrierType.NONE, false));
-        if (config.useCompressedClassPointers) {
-            return CompressionNode.uncompress(memoryRead, config.getKlassEncoding());
-        } else {
-            return memoryRead;
-        }
-    }
-
-    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-
-        ValueNode writeValue = value;
-        if (config.useCompressedClassPointers) {
-            writeValue = CompressionNode.compress(value, config.getKlassEncoding());
-        }
-
-        return graph.add(new WriteNode(object, writeValue, location, BarrierType.NONE, false));
-    }
-
-    private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
-            barrierType = BarrierType.PRECISE;
-        }
-        return barrierType;
-    }
-
-    private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
-        if (storeField.field().getKind() == Kind.Object) {
-            return BarrierType.IMPRECISE;
-        }
-        return BarrierType.NONE;
-    }
+    ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value);
 
-    private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
-        if (store.elementKind() == Kind.Object) {
-            return BarrierType.PRECISE;
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
-        if (store.value().getKind() == Kind.Object) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(store.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getCompareAndSwapBarrierType(CompareAndSwapNode cas) {
-        if (cas.expected().getKind() == Kind.Object) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(cas.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : field;
-        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
-    }
-
-    public int getScalingFactor(Kind kind) {
-        if (useCompressedOops() && kind == Kind.Object) {
-            return this.runtime.getTarget().getSizeInBytes(Kind.Int);
-        } else {
-            return this.runtime.getTarget().getSizeInBytes(kind);
-        }
-    }
-
-    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
-        int scale = getScalingFactor(elementKind);
-        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
-    }
-
-    @Override
-    public ValueNode reconstructArrayIndex(LocationNode location) {
-        Kind elementKind = location.getValueKind();
-        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
-
-        long base;
-        ValueNode index;
-        int scale = getScalingFactor(elementKind);
-
-        if (location instanceof ConstantLocationNode) {
-            base = ((ConstantLocationNode) location).getDisplacement();
-            index = null;
-        } else if (location instanceof IndexedLocationNode) {
-            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
-            assert indexedLocation.getIndexScaling() == scale;
-            base = indexedLocation.getDisplacement();
-            index = indexedLocation.getIndex();
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        base -= getArrayBaseOffset(elementKind);
-        assert base >= 0 && base % scale == 0;
-
-        base /= scale;
-        assert NumUtil.isInt(base);
-
-        StructuredGraph graph = location.graph();
-        if (index == null) {
-            return ConstantNode.forInt((int) base, graph);
-        } else {
-            if (base == 0) {
-                return index;
-            } else {
-                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
-            }
-        }
-    }
-
-    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
-        StructuredGraph g = n.graph();
-        ValueNode array = n.array();
-        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
-        if (arrayLength == null) {
-            Stamp stamp = StampFactory.positiveInt();
-            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
-            g.addBeforeFixed(n, readArrayLength);
-            readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
-            arrayLength = readArrayLength;
-        }
-
-        if (arrayLength.isConstant() && n.index().isConstant()) {
-            int l = arrayLength.asConstant().asInt();
-            int i = n.index().asConstant().asInt();
-            if (i >= 0 && i < l) {
-                // unneeded range check
-                return null;
-            }
-        }
-
-        return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
-    }
-
-    private static GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
-        if (ObjectStamp.isObjectNonNull(object)) {
-            return null;
-        }
-        return tool.createGuard(before, before.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
-    }
-
+    ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 
@@ -51,7 +51,7 @@
     }
 
     public ResolvedJavaType lookupJavaType(Constant constant) {
-        if (constant.getKind() != Kind.Object || constant.isNull()) {
+        if (constant.isNull() || !(constant instanceof HotSpotObjectConstant)) {
             return null;
         }
         Object o = HotSpotObjectConstant.asObject(constant);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 
-public final class HotSpotMetaspaceConstant extends PrimitiveConstant {
+public final class HotSpotMetaspaceConstant extends PrimitiveConstant implements HotSpotConstant {
 
     private static final long serialVersionUID = 1003463314013122983L;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static java.lang.String.*;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.meta;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.*;
+
+public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider {
+
+    /**
+     * Lazy initialization to break class initialization cycle. Field and method lookup is only
+     * possible after the {@link HotSpotGraalRuntime} is fully initialized.
+     */
+    static class LazyInitialization {
+        static final ResolvedJavaField methodHandleFormField;
+        static final ResolvedJavaField lambdaFormVmentryField;
+        static final ResolvedJavaMethod lambdaFormCompileToBytecodeMethod;
+        static final ResolvedJavaField memberNameVmtargetField;
+
+        /**
+         * Search for an instance field with the given name in a class.
+         *
+         * @param className name of the class to search in
+         * @param fieldName name of the field to be searched
+         * @return resolved java field
+         * @throws ClassNotFoundException
+         */
+        private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
+            Class<?> clazz = Class.forName(className);
+            ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
+            ResolvedJavaField[] fields = type.getInstanceFields(false);
+            for (ResolvedJavaField field : fields) {
+                if (field.getName().equals(fieldName)) {
+                    return field;
+                }
+            }
+            return null;
+        }
+
+        private static ResolvedJavaMethod findMethodInClass(String className, String methodName) throws ClassNotFoundException {
+            Class<?> clazz = Class.forName(className);
+            ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
+            ResolvedJavaMethod result = null;
+            for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
+                if (method.getName().equals(methodName)) {
+                    assert result == null : "more than one method found: " + className + "." + methodName;
+                    result = method;
+                }
+            }
+            assert result != null : "method not found: " + className + "." + methodName;
+            return result;
+        }
+
+        static {
+            try {
+                methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
+                lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
+                lambdaFormCompileToBytecodeMethod = findMethodInClass("java.lang.invoke.LambdaForm", "compileToBytecode");
+                memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
+            } catch (Throwable ex) {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Override
+    public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
+        int intrinsicId = ((HotSpotResolvedJavaMethod) method).intrinsicId();
+        if (intrinsicId != 0) {
+            HotSpotVMConfig config = runtime().getConfig();
+            if (intrinsicId == config.vmIntrinsicInvokeBasic) {
+                return IntrinsicMethod.INVOKE_BASIC;
+            } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
+                return IntrinsicMethod.LINK_TO_INTERFACE;
+            } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
+                return IntrinsicMethod.LINK_TO_SPECIAL;
+            } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
+                return IntrinsicMethod.LINK_TO_STATIC;
+            } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
+                return IntrinsicMethod.LINK_TO_VIRTUAL;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ResolvedJavaMethod resolveInvokeBasicTarget(Constant methodHandle, boolean forceBytecodeGeneration) {
+        if (methodHandle.isNull()) {
+            return null;
+        }
+
+        /* Load non-public field: LambdaForm MethodHandle.form */
+        Constant lambdaForm = LazyInitialization.methodHandleFormField.readValue(methodHandle);
+        if (lambdaForm.isNull()) {
+            return null;
+        }
+
+        Constant memberName;
+        if (forceBytecodeGeneration) {
+            /* Invoke non-public method: MemberName LambdaForm.compileToBytecode() */
+            memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new Constant[0]);
+        } else {
+            /* Load non-public field: MemberName LambdaForm.vmentry */
+            memberName = LazyInitialization.lambdaFormVmentryField.readValue(lambdaForm);
+        }
+        return getTargetMethod(memberName);
+    }
+
+    @Override
+    public ResolvedJavaMethod resolveLinkToTarget(Constant memberName) {
+        return getTargetMethod(memberName);
+    }
+
+    /**
+     * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName.
+     */
+    private static ResolvedJavaMethod getTargetMethod(Constant memberName) {
+        if (memberName.isNull()) {
+            return null;
+        }
+
+        /* Load injected field: JVM_Method* MemberName.vmtarget */
+        Constant vmtarget = LazyInitialization.memberNameVmtargetField.readValue(memberName);
+        /* Create a method from the vmtarget method pointer. */
+        return HotSpotResolvedJavaMethod.fromMetaspace(vmtarget.asLong());
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,6 @@
 
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 
@@ -38,7 +36,7 @@
  * instance to be anything but weak. This is due to the fact that HotSpot does not treat nmethods as
  * strong GC roots.
  */
-public final class HotSpotNmethod extends HotSpotInstalledCode {
+public class HotSpotNmethod extends HotSpotInstalledCode {
 
     /**
      * This (indirect) Method* reference is safe since class redefinition preserves all methods
@@ -84,10 +82,10 @@
     }
 
     protected boolean checkThreeObjectArgs() {
-        assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3;
+        assert method.getSignature().getParameterCount(!method.isStatic()) == 3;
         assert method.getSignature().getParameterKind(0) == Kind.Object;
         assert method.getSignature().getParameterKind(1) == Kind.Object;
-        assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object;
+        assert !method.isStatic() || method.getSignature().getParameterKind(2) == Kind.Object;
         return true;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Fri May 30 15:09:09 2014 +0200
@@ -23,12 +23,13 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 
 /**
  * Represents a constant non-{@code null} object reference, within the compiler and across the
  * compiler/runtime interface.
  */
-public final class HotSpotObjectConstant extends Constant {
+public final class HotSpotObjectConstant extends Constant implements HotSpotConstant {
 
     private static final long serialVersionUID = 3592151693708093496L;
 
@@ -36,7 +37,7 @@
         if (object == null) {
             return Constant.NULL_OBJECT;
         } else {
-            return new HotSpotObjectConstant(object);
+            return new HotSpotObjectConstant(object, false);
         }
     }
 
@@ -59,21 +60,41 @@
     public static Object asBoxedValue(Constant constant) {
         if (constant.isNull()) {
             return null;
-        } else if (constant.getKind() == Kind.Object) {
+        } else if (constant instanceof HotSpotObjectConstant) {
             return ((HotSpotObjectConstant) constant).object;
         } else {
             return constant.asBoxedPrimitive();
         }
     }
 
+    public static boolean isCompressed(Constant constant) {
+        if (constant.isNull()) {
+            return HotSpotCompressedNullConstant.NULL_OBJECT.equals(constant);
+        } else {
+            return ((HotSpotObjectConstant) constant).compressed;
+        }
+    }
+
     private final Object object;
+    private final boolean compressed;
 
-    private HotSpotObjectConstant(Object object) {
-        super(Kind.Object);
+    private HotSpotObjectConstant(Object object, boolean compressed) {
+        super(compressed ? NarrowOopStamp.NarrowOop : Kind.Object);
         this.object = object;
+        this.compressed = compressed;
         assert object != null;
     }
 
+    public Constant compress() {
+        assert !compressed;
+        return new HotSpotObjectConstant(object, true);
+    }
+
+    public Constant uncompress() {
+        assert compressed;
+        return new HotSpotObjectConstant(object, false);
+    }
+
     @Override
     public boolean isNull() {
         return false;
@@ -135,6 +156,6 @@
 
     @Override
     public String toString() {
-        return getKind().getJavaName() + "[" + Kind.Object.format(object) + "]";
+        return (compressed ? "NarrowOop" : getKind().getJavaName()) + "[" + Kind.Object.format(object) + "]";
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Fri May 30 15:09:09 2014 +0200
@@ -38,15 +38,17 @@
     private final SuitesProvider suites;
     private final HotSpotRegistersProvider registers;
     private final SnippetReflectionProvider snippetReflection;
+    private final HotSpotMethodHandleAccessProvider methodHandleAccess;
 
     public HotSpotProviders(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls,
                     LoweringProvider lowerer, Replacements replacements, HotSpotDisassemblerProvider disassembler, SuitesProvider suites, HotSpotRegistersProvider registers,
-                    SnippetReflectionProvider snippetReflection) {
+                    SnippetReflectionProvider snippetReflection, HotSpotMethodHandleAccessProvider methodHandleAccess) {
         super(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements);
         this.disassembler = disassembler;
         this.suites = suites;
         this.registers = registers;
         this.snippetReflection = snippetReflection;
+        this.methodHandleAccess = methodHandleAccess;
     }
 
     @Override
@@ -79,4 +81,8 @@
     public SnippetReflectionProvider getSnippetReflection() {
         return snippetReflection;
     }
+
+    public HotSpotMethodHandleAccessProvider getMethodHandleAccess() {
+        return methodHandleAccess;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,9 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-import static java.lang.reflect.Modifier.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -200,8 +199,8 @@
         assert !ImmutableCode.getValue() || isCalledForSnippets() : receiver;
 
         if (receiver == null) {
-            assert isStatic(modifiers);
-            if (Modifier.isFinal(getModifiers())) {
+            assert isStatic();
+            if (isFinal()) {
                 if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable()) {
                     return readValue(receiver);
                 }
@@ -211,29 +210,35 @@
              * for non-static final fields, we must assume that they are only initialized if they
              * have a non-default value.
              */
-            assert !isStatic(modifiers);
+            assert !isStatic();
             Object object = HotSpotObjectConstant.asObject(receiver);
 
             // Canonicalization may attempt to process an unsafe read before
             // processing a guard (e.g. a null check or a type check) for this read
             // so we need to check the object being read
-            if (object != null && isInObject(object)) {
-                if (Modifier.isFinal(getModifiers())) {
-                    Constant value = readValue(receiver);
-                    if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
-                        return value;
+            if (object != null) {
+                if (isFinal()) {
+                    if (isInObject(object)) {
+                        Constant value = readValue(receiver);
+                        if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
+                            return value;
+                        }
                     }
                 } else if (isStable()) {
-                    Constant value = readValue(receiver);
-                    if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
-                        return value;
+                    if (isInObject(object)) {
+                        Constant value = readValue(receiver);
+                        if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
+                            return value;
+                        }
                     }
                 } else {
                     Class<?> clazz = object.getClass();
                     if (StableOptionValue.class.isAssignableFrom(clazz)) {
-                        assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this;
-                        StableOptionValue<?> option = (StableOptionValue<?>) object;
-                        return HotSpotObjectConstant.forObject(option.getValue());
+                        if (isInObject(object)) {
+                            assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this;
+                            StableOptionValue<?> option = (StableOptionValue<?>) object;
+                            return HotSpotObjectConstant.forObject(option.getValue());
+                        }
                     }
                 }
             }
@@ -248,7 +253,7 @@
      *         {@code object}'s class
      */
     public boolean isInObject(Object object) {
-        if (isStatic(modifiers)) {
+        if (isStatic()) {
             return false;
         }
         return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectType.fromClass(object.getClass()));
@@ -257,13 +262,13 @@
     @Override
     public Constant readValue(Constant receiver) {
         if (receiver == null) {
-            assert isStatic(modifiers);
+            assert isStatic();
             if (holder.isInitialized()) {
                 return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), HotSpotObjectConstant.forObject(holder.mirror()), offset);
             }
             return null;
         } else {
-            assert !isStatic(modifiers);
+            assert !isStatic();
             assert receiver.isNonNull() && isInObject(HotSpotObjectConstant.asObject(receiver));
             return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), receiver, offset);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Fri May 30 15:09:09 2014 +0200
@@ -22,17 +22,18 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.GraalInternalError.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.debug.*;
@@ -55,7 +56,7 @@
     private final HotSpotSignature signature;
     private HotSpotMethodData methodData;
     private byte[] code;
-    private SpeculationLog speculationLog;
+    private Member toJavaCache;
 
     /**
      * Gets the holder of a HotSpot metaspace method native object.
@@ -186,8 +187,7 @@
 
     @Override
     public boolean canBeStaticallyBound() {
-        int modifiers = getModifiers();
-        return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(holder.getModifiers())) && !Modifier.isAbstract(modifiers);
+        return (isFinal() || isPrivate() || isStatic() || holder.isFinal()) && !isAbstract();
     }
 
     @Override
@@ -196,7 +196,7 @@
             return null;
         }
         if (code == null && holder.isLinked()) {
-            code = runtime().getCompilerToVM().initializeBytecode(metaspaceMethod, new byte[getCodeSize()]);
+            code = runtime().getCompilerToVM().getBytecode(metaspaceMethod);
             assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length;
         }
         return code;
@@ -314,18 +314,17 @@
 
     @Override
     public boolean isClassInitializer() {
-        return "<clinit>".equals(name) && Modifier.isStatic(getModifiers());
+        return "<clinit>".equals(name) && isStatic();
     }
 
     @Override
     public boolean isConstructor() {
-        return "<init>".equals(name) && !Modifier.isStatic(getModifiers());
+        return "<init>".equals(name) && !isStatic();
     }
 
     @Override
     public int getMaxLocals() {
-        int modifiers = getModifiers();
-        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+        if (isAbstract() || isNative()) {
             return 0;
         }
         HotSpotVMConfig config = runtime().getConfig();
@@ -334,8 +333,7 @@
 
     @Override
     public int getMaxStackSize() {
-        int modifiers = getModifiers();
-        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+        if (isAbstract() || isNative()) {
             return 0;
         }
         HotSpotVMConfig config = runtime().getConfig();
@@ -508,16 +506,26 @@
     }
 
     private Method toJava() {
+        if (toJavaCache != null) {
+            return (Method) toJavaCache;
+        }
         try {
-            return holder.mirror().getDeclaredMethod(name, signatureToTypes());
+            Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes());
+            toJavaCache = result;
+            return result;
         } catch (NoSuchMethodException e) {
             return null;
         }
     }
 
     private Constructor<?> toJavaConstructor() {
+        if (toJavaCache != null) {
+            return (Constructor<?>) toJavaCache;
+        }
         try {
-            return holder.mirror().getDeclaredConstructor(signatureToTypes());
+            Constructor<?> result = holder.mirror().getDeclaredConstructor(signatureToTypes());
+            toJavaCache = result;
+            return result;
         } catch (NoSuchMethodException e) {
             return null;
         }
@@ -592,22 +600,34 @@
 
     /**
      * Returns the offset of this method into the v-table. The method must have a v-table entry as
-     * indicated by {@link #isInVirtualMethodTable()}, otherwise an exception is thrown.
+     * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is
+     * thrown.
      *
      * @return the offset of this method into the v-table
      */
-    public int vtableEntryOffset() {
-        if (!isInVirtualMethodTable() || !holder.isInitialized()) {
-            throw new GraalInternalError("%s does not have a vtable entry", this);
-        }
+    public int vtableEntryOffset(ResolvedJavaType resolved) {
+        guarantee(isInVirtualMethodTable(resolved), "%s does not have a vtable entry", this);
         HotSpotVMConfig config = runtime().getConfig();
-        final int vtableIndex = getVtableIndex();
+        final int vtableIndex = getVtableIndex(resolved);
         return config.instanceKlassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
     }
 
     @Override
-    public boolean isInVirtualMethodTable() {
-        return getVtableIndex() >= 0;
+    public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
+        return getVtableIndex(resolved) >= 0;
+    }
+
+    private int getVtableIndex(ResolvedJavaType resolved) {
+        if (!holder.isLinked()) {
+            return runtime().getConfig().invalidVtableIndex;
+        }
+        if (holder.isInterface()) {
+            if (resolved.isArray() || resolved.isInterface()) {
+                return runtime().getConfig().invalidVtableIndex;
+            }
+            return getVtableIndexForInterface(resolved);
+        }
+        return getVtableIndex();
     }
 
     /**
@@ -616,18 +636,45 @@
      * @return virtual table index
      */
     private int getVtableIndex() {
-        assert !Modifier.isInterface(holder.getModifiers());
+        assert !holder.isInterface();
         HotSpotVMConfig config = runtime().getConfig();
         int result = unsafe.getInt(metaspaceMethod + config.methodVtableIndexOffset);
         assert result >= config.nonvirtualVtableIndex : "must be linked";
         return result;
     }
 
+    private int getVtableIndexForInterface(ResolvedJavaType resolved) {
+        HotSpotResolvedObjectType hotspotType = (HotSpotResolvedObjectType) resolved;
+        return runtime().getCompilerToVM().getVtableIndexForInterface(hotspotType.getMetaspaceKlass(), getMetaspaceMethod());
+    }
+
+    /**
+     * The {@link SpeculationLog} for methods compiled by Graal hang off this per-declaring-type
+     * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is
+     * never moves and b) we never read from it.
+     * <p>
+     * One implication is that we will preserve {@link SpeculationLog}s for methods that have been
+     * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot
+     * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods
+     * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal).
+     */
+    private static final ClassValue<Map<Long, SpeculationLog>> SpeculationLogs = new ClassValue<Map<Long, SpeculationLog>>() {
+        @Override
+        protected Map<Long, SpeculationLog> computeValue(java.lang.Class<?> type) {
+            return new HashMap<>(4);
+        }
+    };
+
     public SpeculationLog getSpeculationLog() {
-        if (speculationLog == null) {
-            speculationLog = new HotSpotSpeculationLog();
+        Map<Long, SpeculationLog> map = SpeculationLogs.get(holder.mirror());
+        synchronized (map) {
+            SpeculationLog log = map.get(this.metaspaceMethod);
+            if (log == null) {
+                log = new HotSpotSpeculationLog();
+                map.put(metaspaceMethod, log);
+            }
+            return log;
         }
-        return speculationLog;
     }
 
     public int intrinsicId() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Fri May 30 15:09:09 2014 +0200
@@ -23,9 +23,8 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static java.lang.reflect.Modifier.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
@@ -109,7 +108,7 @@
     /**
      * Gets the metaspace Klass for this type.
      */
-    private long metaspaceKlass() {
+    public long getMetaspaceKlass() {
         return HotSpotGraalRuntime.unsafeReadWord(javaClass, runtime().getConfig().klassOffset);
     }
 
@@ -120,7 +119,7 @@
 
     public int getAccessFlags() {
         HotSpotVMConfig config = runtime().getConfig();
-        return unsafe.getInt(metaspaceKlass() + config.klassAccessFlagsOffset);
+        return unsafe.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset);
     }
 
     @Override
@@ -141,9 +140,9 @@
     public ResolvedJavaType findUniqueConcreteSubtype() {
         HotSpotVMConfig config = runtime().getConfig();
         if (isArray()) {
-            return isFinal(getElementalType(this).getModifiers()) ? this : null;
+            return getElementalType(this).isFinal() ? this : null;
         } else if (isInterface()) {
-            final long implementorMetaspaceKlass = runtime().getCompilerToVM().getKlassImplementor(metaspaceKlass());
+            final long implementorMetaspaceKlass = runtime().getCompilerToVM().getKlassImplementor(getMetaspaceKlass());
 
             // No implementor.
             if (implementorMetaspaceKlass == 0) {
@@ -157,20 +156,20 @@
              * than one implementors (see: InstanceKlass::add_implementor). The isInterface check
              * takes care of this fact since this class is an interface.
              */
-            if (isAbstract(type.getModifiers()) || type.isInterface() || !type.isLeafClass()) {
+            if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) {
                 return null;
             }
             return type;
         } else {
             HotSpotResolvedObjectType type = this;
-            while (isAbstract(type.getModifiers())) {
+            while (type.isAbstract()) {
                 long subklass = type.getSubklass();
                 if (subklass == 0 || unsafeReadWord(subklass + config.nextSiblingOffset) != 0) {
                     return null;
                 }
                 type = (HotSpotResolvedObjectType) fromMetaspaceKlass(subklass);
             }
-            if (isAbstract(type.getModifiers()) || type.isInterface() || !type.isLeafClass()) {
+            if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) {
                 return null;
             }
             return type;
@@ -194,7 +193,7 @@
      * @return value of the subklass field as metaspace klass pointer
      */
     private long getSubklass() {
-        return unsafeReadWord(metaspaceKlass() + runtime().getConfig().subklassOffset);
+        return unsafeReadWord(getMetaspaceKlass() + runtime().getConfig().subklassOffset);
     }
 
     @Override
@@ -255,7 +254,7 @@
         if (isArray()) {
             return getComponentType().asExactType() != null ? this : null;
         }
-        return isFinal(getModifiers()) ? this : null;
+        return isFinal() ? this : null;
     }
 
     @Override
@@ -273,7 +272,7 @@
     @Override
     public boolean hasFinalizableSubclass() {
         assert !isArray();
-        return runtime().getCompilerToVM().hasFinalizableSubclass(metaspaceKlass());
+        return runtime().getCompilerToVM().hasFinalizableSubclass(getMetaspaceKlass());
     }
 
     @Override
@@ -311,7 +310,7 @@
      * @return state field value of this type
      */
     private int getState() {
-        return unsafe.getByte(metaspaceKlass() + runtime().getConfig().klassStateOffset) & 0xFF;
+        return unsafe.getByte(getMetaspaceKlass() + runtime().getConfig().klassStateOffset) & 0xFF;
     }
 
     @Override
@@ -356,18 +355,22 @@
     }
 
     @Override
-    public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
-        assert method instanceof HotSpotMethod;
-        if (!isAbstract(method.getModifiers()) && method.getDeclaringClass().equals(this)) {
+    public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
+        assert !callerType.isArray();
+        if (!method.isAbstract() && method.getDeclaringClass().equals(this) && method.isPublic()) {
             return method;
         }
-
-        final long resolvedMetaspaceMethod = runtime().getCompilerToVM().resolveMethod(metaspaceKlass(), method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
+        if (!method.getDeclaringClass().isAssignableFrom(this)) {
+            return null;
+        }
+        HotSpotResolvedJavaMethod hotSpotMethod = (HotSpotResolvedJavaMethod) method;
+        HotSpotResolvedObjectType hotSpotCallerType = (HotSpotResolvedObjectType) callerType;
+        final long resolvedMetaspaceMethod = runtime().getCompilerToVM().resolveMethod(getMetaspaceKlass(), hotSpotMethod.getMetaspaceMethod(), hotSpotCallerType.getMetaspaceKlass());
         if (resolvedMetaspaceMethod == 0) {
             return null;
         }
         HotSpotResolvedJavaMethod resolvedMethod = HotSpotResolvedJavaMethod.fromMetaspace(resolvedMetaspaceMethod);
-        if (isAbstract(resolvedMethod.getModifiers())) {
+        if (resolvedMethod.isAbstract()) {
             return null;
         }
         return resolvedMethod;
@@ -375,7 +378,7 @@
 
     public ConstantPool constantPool() {
         if (constantPool == null) {
-            final long metaspaceConstantPool = unsafe.getAddress(metaspaceKlass() + runtime().getConfig().instanceKlassConstantsOffset);
+            final long metaspaceConstantPool = unsafe.getAddress(getMetaspaceKlass() + runtime().getConfig().instanceKlassConstantsOffset);
             constantPool = new HotSpotConstantPool(metaspaceConstantPool);
         }
         return constantPool;
@@ -391,7 +394,7 @@
         assert !isInterface();
 
         HotSpotVMConfig config = runtime().getConfig();
-        final int layoutHelper = unsafe.getInt(metaspaceKlass() + config.klassLayoutHelperOffset);
+        final int layoutHelper = unsafe.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset);
         assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance";
 
         // See: Klass::layout_helper_size_in_bytes
@@ -477,7 +480,7 @@
         public FieldInfo(int index) {
             HotSpotVMConfig config = runtime().getConfig();
             // Get Klass::_fields
-            final long metaspaceFields = unsafe.getAddress(metaspaceKlass() + config.instanceKlassFieldsOffset);
+            final long metaspaceFields = unsafe.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset);
             assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code";
             metaspaceData = metaspaceFields + config.arrayU2DataOffset + config.fieldInfoFieldSlots * Short.BYTES * index;
         }
@@ -604,6 +607,29 @@
         return instanceFields;
     }
 
+    @Override
+    public ResolvedJavaField[] getStaticFields() {
+        if (isArray()) {
+            return new HotSpotResolvedJavaField[0];
+        } else {
+            final int fieldCount = getFieldCount();
+            ArrayList<HotSpotResolvedJavaField> fieldsArray = new ArrayList<>(fieldCount);
+
+            for (int i = 0; i < fieldCount; i++) {
+                FieldInfo field = new FieldInfo(i);
+
+                // We are only interested in static fields.
+                if (field.isStatic()) {
+                    HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags());
+                    fieldsArray.add(resolvedJavaField);
+                }
+            }
+
+            fieldsArray.sort(new OffsetComparator());
+            return fieldsArray.toArray(new HotSpotResolvedJavaField[fieldsArray.size()]);
+        }
+    }
+
     /**
      * Returns the actual field count of this class's internal {@code InstanceKlass::_fields} array
      * by walking the array and discounting the generic signature slots at the end of the array.
@@ -613,7 +639,7 @@
      */
     private int getFieldCount() {
         HotSpotVMConfig config = runtime().getConfig();
-        final long metaspaceFields = unsafe.getAddress(metaspaceKlass() + config.instanceKlassFieldsOffset);
+        final long metaspaceFields = unsafe.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset);
         int metaspaceFieldsLength = unsafe.getInt(metaspaceFields + config.arrayU1LengthOffset);
         int fieldCount = 0;
 
@@ -635,7 +661,7 @@
     @Override
     public String getSourceFileName() {
         HotSpotVMConfig config = runtime().getConfig();
-        final int sourceFileNameIndex = unsafe.getChar(metaspaceKlass() + config.klassSourceFileNameIndexOffset);
+        final int sourceFileNameIndex = unsafe.getChar(getMetaspaceKlass() + config.klassSourceFileNameIndexOffset);
         if (sourceFileNameIndex == 0) {
             return null;
         }
@@ -656,7 +682,7 @@
      * Gets the metaspace Klass boxed in a {@link Constant}.
      */
     public Constant klass() {
-        return HotSpotMetaspaceConstant.forMetaspaceObject(runtime().getTarget().wordKind, metaspaceKlass(), this);
+        return HotSpotMetaspaceConstant.forMetaspaceObject(runtime().getTarget().wordKind, getMetaspaceKlass(), this);
     }
 
     public boolean isPrimaryType() {
@@ -665,7 +691,7 @@
 
     public int superCheckOffset() {
         HotSpotVMConfig config = runtime().getConfig();
-        return unsafe.getInt(metaspaceKlass() + config.superCheckOffsetOffset);
+        return unsafe.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset);
     }
 
     public long prototypeMarkWord() {
@@ -673,7 +699,7 @@
         if (isArray()) {
             return config.arrayPrototypeMarkWord();
         } else {
-            return unsafeReadWord(metaspaceKlass() + config.prototypeMarkWordOffset);
+            return unsafeReadWord(getMetaspaceKlass() + config.prototypeMarkWordOffset);
         }
     }
 
@@ -733,7 +759,7 @@
     }
 
     public ResolvedJavaMethod getClassInitializer() {
-        final long metaspaceMethod = runtime().getCompilerToVM().getClassInitializer(metaspaceKlass());
+        final long metaspaceMethod = runtime().getCompilerToVM().getClassInitializer(getMetaspaceKlass());
         if (metaspaceMethod != 0L) {
             return createMethod(metaspaceMethod);
         }
@@ -747,12 +773,6 @@
 
     @Override
     public String toString() {
-        String simpleName;
-        if (isArray() || isInterface()) {
-            simpleName = getName();
-        } else {
-            simpleName = getName().substring(1, getName().length() - 1);
-        }
-        return "HotSpotType<" + simpleName + ", resolved>";
+        return "HotSpotType<" + getName() + ", resolved>";
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Fri May 30 15:09:09 2014 +0200
@@ -39,7 +39,7 @@
 
     /**
      * Gets the Graal mirror for a {@link Kind}.
-     * 
+     *
      * @return the {@link HotSpotResolvedObjectType} corresponding to {@code kind}
      */
     public static ResolvedJavaType fromKind(Kind kind) {
@@ -49,12 +49,12 @@
 
     /**
      * Creates the Graal mirror for a primitive {@link Kind}.
-     * 
+     *
      * <p>
      * <b>NOTE</b>: Creating an instance of this class does not install the mirror for the
      * {@link Class} type. Use {@link #fromKind(Kind)} or {@link #fromClass(Class)} instead.
      * </p>
-     * 
+     *
      * @param kind the Kind to create the mirror for
      */
     public HotSpotResolvedPrimitiveType(Kind kind) {
@@ -163,7 +163,7 @@
     }
 
     @Override
-    public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
+    public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
         return null;
     }
 
@@ -188,6 +188,11 @@
     }
 
     @Override
+    public ResolvedJavaField[] getStaticFields() {
+        return new ResolvedJavaField[0];
+    }
+
+    @Override
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.phases.*;
@@ -58,7 +58,7 @@
 
         if (ImmutableCode.getValue()) {
             // lowering introduces class constants, therefore it must be after lowering
-            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(runtime.getConfig().classMirrorOffset));
+            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(runtime.getConfig().classMirrorOffset, runtime.getConfig().getOopEncoding()));
             if (VerifyPhases.getValue()) {
                 ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase());
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java	Fri May 30 15:09:09 2014 +0200
@@ -32,56 +32,28 @@
 public class HotSpotUnresolvedJavaType extends HotSpotJavaType {
 
     private static final long serialVersionUID = -2320936267633521314L;
-    public final String simpleName;
-    public final int dimensions;
 
-    public HotSpotUnresolvedJavaType(String name, String simpleName, int dimensions) {
+    public HotSpotUnresolvedJavaType(String name) {
         super(name);
-        assert dimensions >= 0;
-        this.simpleName = simpleName;
-        this.dimensions = dimensions;
     }
 
     /**
      * Creates an unresolved type for a valid {@link JavaType#getName() type name}.
      */
     public static HotSpotUnresolvedJavaType create(String name) {
-        int dims = 0;
-        int startIndex = 0;
-        while (name.charAt(startIndex) == '[') {
-            startIndex++;
-            dims++;
-        }
-
-        // Decode name if necessary.
-        if (name.charAt(name.length() - 1) == ';') {
-            assert name.charAt(startIndex) == 'L';
-            return new HotSpotUnresolvedJavaType(name, name.substring(startIndex + 1, name.length() - 1), dims);
-        } else {
-            return new HotSpotUnresolvedJavaType(HotSpotUnresolvedJavaType.getFullName(name, dims), name, dims);
-        }
-    }
-
-    public static String getFullName(String name, int dimensions) {
-        StringBuilder str = new StringBuilder(name.length() + dimensions + 2);
-        for (int i = 0; i < dimensions; i++) {
-            str.append('[');
-        }
-        str.append('L').append(name).append(';');
-        return str.toString();
+        assert name.charAt(name.length() - 1) == ';' : name;
+        return new HotSpotUnresolvedJavaType(name);
     }
 
     @Override
     public JavaType getComponentType() {
-        assert dimensions > 0 : "no array class" + getName();
-        String name = getFullName(getName(), dimensions - 1);
-        return new HotSpotUnresolvedJavaType(name, simpleName, dimensions - 1);
+        assert getName().charAt(0) == '[' : "no array class" + getName();
+        return new HotSpotUnresolvedJavaType(getName().substring(1));
     }
 
     @Override
     public JavaType getArrayClass() {
-        String name = getFullName(getName(), dimensions + 1);
-        return new HotSpotUnresolvedJavaType(name, simpleName, dimensions + 1);
+        return new HotSpotUnresolvedJavaType('[' + getName());
     }
 
     @Override
@@ -91,7 +63,7 @@
 
     @Override
     public int hashCode() {
-        return simpleName.hashCode();
+        return getName().hashCode();
     }
 
     @Override
@@ -103,12 +75,12 @@
             return false;
         }
         HotSpotUnresolvedJavaType that = (HotSpotUnresolvedJavaType) obj;
-        return this.simpleName.equals(that.simpleName) && this.dimensions == that.dimensions;
+        return this.getName().equals(that.getName());
     }
 
     @Override
     public String toString() {
-        return "HotSpotType<" + simpleName + ", unresolved>";
+        return "HotSpotType<" + getName() + ", unresolved>";
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.nfi;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.nfi.NativeCallStubGraphBuilder.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -33,7 +33,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.word.phases.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,18 +26,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.compiler.common.type.*;
 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 LIRGenResLowerable {
+public final class AllocaNode extends FixedWithNextNode implements LIRLowerable {
 
     /**
      * The number of slots in block.
@@ -58,8 +56,8 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
-        StackSlot array = res.getFrameMap().allocateStackSlots(slots, objects, null);
+    public void generate(NodeLIRBuilderTool gen) {
+        StackSlot array = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(slots, objects, null);
         Value result = gen.getLIRGeneratorTool().emitAddress(array);
         gen.setResult(this, result);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,12 +24,11 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +38,7 @@
  * check on the object.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
+public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single {
 
     private int lockDepth;
 
@@ -59,7 +58,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         assert lockDepth != -1;
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         StackSlot slot = hsGen.getLockSlot(lockDepth);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,6 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -32,7 +30,7 @@
 /**
  * Converts a compile-time constant Java string into a C string installed with the generated code.
  */
-public final class CStringNode extends FloatingNode implements LIRGenLowerable {
+public final class CStringNode extends FloatingNode implements LIRLowerable {
 
     private final String string;
 
@@ -41,7 +39,7 @@
         this.string = string;
     }
 
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         gen.setResult(this, emitCString(gen, string));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Fri May 30 15:09:09 2014 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -39,7 +40,7 @@
  * Compress or uncompress an oop or metaspace pointer.
  */
 @NodeInfo(nameTemplate = "{p#op/s}")
-public final class CompressionNode extends FloatingNode implements LIRLowerable, Canonicalizable {
+public final class CompressionNode extends ConvertNode implements LIRLowerable, Canonicalizable {
 
     private enum CompressionOp {
         Compress,
@@ -49,13 +50,10 @@
     private final CompressionOp op;
     private final CompressEncoding encoding;
 
-    @Input private ValueNode input;
-
     private CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
-        super(mkStamp(op, input.stamp(), encoding));
+        super(mkStamp(op, input.stamp(), encoding), input);
         this.op = op;
         this.encoding = encoding;
-        this.input = input;
     }
 
     public static CompressionNode compress(ValueNode input, CompressEncoding encoding) {
@@ -66,12 +64,67 @@
         return input.graph().unique(new CompressionNode(CompressionOp.Uncompress, input, encoding));
     }
 
+    private static Constant compress(Constant c, CompressEncoding encoding) {
+        if (Constant.NULL_OBJECT.equals(c)) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) c).compress();
+        } else if (c instanceof HotSpotMetaspaceConstant) {
+            assert c.getKind() == Kind.Long;
+            return HotSpotMetaspaceConstant.forMetaspaceObject(Kind.Int, encoding.compress(c.asLong()), HotSpotMetaspaceConstant.getMetaspaceObject(c));
+        } else {
+            throw GraalInternalError.shouldNotReachHere("invalid constant input for compress op: " + c);
+        }
+    }
+
+    private static Constant uncompress(Constant c, CompressEncoding encoding) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return Constant.NULL_OBJECT;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) c).uncompress();
+        } else if (c instanceof HotSpotMetaspaceConstant) {
+            assert c.getKind() == Kind.Int;
+            return HotSpotMetaspaceConstant.forMetaspaceObject(Kind.Long, encoding.uncompress(c.asInt()), HotSpotMetaspaceConstant.getMetaspaceObject(c));
+        } else {
+            throw GraalInternalError.shouldNotReachHere("invalid constant input for uncompress op: " + c);
+        }
+    }
+
+    @Override
+    public Constant convert(Constant c) {
+        switch (op) {
+            case Compress:
+                return compress(c, encoding);
+            case Uncompress:
+                return uncompress(c, encoding);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Constant reverse(Constant c) {
+        switch (op) {
+            case Compress:
+                return uncompress(c, encoding);
+            case Uncompress:
+                return compress(c, encoding);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        return true;
+    }
+
     private static Stamp mkStamp(CompressionOp op, Stamp input, CompressEncoding encoding) {
         switch (op) {
             case Compress:
                 if (input instanceof ObjectStamp) {
                     // compressed oop
-                    return new NarrowOopStamp((ObjectStamp) input, encoding);
+                    return NarrowOopStamp.compressed((ObjectStamp) input, encoding);
                 } else if (input instanceof IntegerStamp) {
                     // compressed metaspace pointer
                     assert PrimitiveStamp.getBits(input) == 64;
@@ -90,15 +143,21 @@
                 }
                 break;
         }
-        throw GraalInternalError.shouldNotReachHere();
+        throw GraalInternalError.shouldNotReachHere(String.format("Unexpected input stamp %s", input));
+    }
+
+    public CompressEncoding getEncoding() {
+        return encoding;
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (input instanceof CompressionNode) {
-            CompressionNode other = (CompressionNode) input;
+        if (getInput().isConstant()) {
+            return ConstantNode.forConstant(stamp(), evalConst(getInput().asConstant()), tool.getMetaAccess(), graph());
+        } else if (getInput() instanceof CompressionNode) {
+            CompressionNode other = (CompressionNode) getInput();
             if (op != other.op && encoding.equals(other.encoding)) {
-                return other.input;
+                return other.getInput();
             }
         }
         return this;
@@ -108,8 +167,8 @@
     public void generate(NodeLIRBuilderTool gen) {
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         boolean nonNull;
-        if (input.stamp() instanceof ObjectStamp) {
-            nonNull = ObjectStamp.isObjectNonNull(input.stamp());
+        if (getInput().stamp() instanceof ObjectStamp) {
+            nonNull = StampTool.isObjectNonNull(getInput().stamp());
         } else {
             // metaspace pointers are never null
             nonNull = true;
@@ -118,10 +177,10 @@
         Value result;
         switch (op) {
             case Compress:
-                result = hsGen.emitCompress(gen.operand(input), encoding, nonNull);
+                result = hsGen.emitCompress(gen.operand(getInput()), encoding, nonNull);
                 break;
             case Uncompress:
-                result = hsGen.emitUncompress(gen.operand(input), encoding, nonNull);
+                result = hsGen.emitUncompress(gen.operand(getInput()), encoding, nonNull);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,11 +27,10 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.word.*;
+
+/**
+ * A call to the runtime code {@code Deoptimization::fetch_unroll_info}.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+
+    @Input private SaveAllRegistersNode registerSaver;
+    private final ForeignCallsProvider foreignCalls;
+
+    public DeoptimizationFetchUnrollInfoCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver) {
+        super(StampFactory.forKind(Kind.fromJavaClass(FETCH_UNROLL_INFO.getResultType())));
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+        this.foreignCalls = foreignCalls;
+    }
+
+    @Override
+    public LocationIdentity[] getLocationIdentities() {
+        return foreignCalls.getKilledLocations(FETCH_UNROLL_INFO);
+    }
+
+    public SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizationFetchUnrollInfoCall(getSaveRegistersOp());
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word fetchUnrollInfo(long registerSaver);
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return null;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Removes the current frame and tail calls the uncommon trap routine.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Fri May 30 15:09:09 2014 +0200
@@ -28,8 +28,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -38,7 +37,7 @@
  * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray
  * instruction.
  */
-public final class DimensionsNode extends FixedWithNextNode implements LIRGenResLowerable {
+public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable {
 
     private final int rank;
 
@@ -48,12 +47,13 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
         int size = rank * 4;
-        int wordSize = gen.getLIRGeneratorTool().target().wordSize;
+        int wordSize = lirGen.target().wordSize;
         int slots = roundUp(size, wordSize) / wordSize;
-        StackSlot array = res.getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
-        Value result = gen.getLIRGeneratorTool().emitAddress(array);
+        StackSlot array = lirGen.getResult().getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
+        Value result = lirGen.emitAddress(array);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,13 +23,12 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +38,7 @@
  * expected value or the compared against value instead of a boolean.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint.Single {
+public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
@@ -79,7 +78,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ((HotSpotNodeLIRBuilder) gen).visitDirectCompareAndSwap(this);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,28 +23,34 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Emits code to enter a low-level stack frame specifically to call out to the C++ method
- * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
  */
 public class EnterUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input private ValueNode framePc;
     @Input private ValueNode senderSp;
     @Input private ValueNode senderFp;
+    @Input private SaveAllRegistersNode registerSaver;
 
-    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp) {
+    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp, ValueNode registerSaver) {
         super(StampFactory.forVoid());
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.senderFp = senderFp;
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
@@ -52,9 +58,9 @@
         Value operandValue = gen.operand(framePc);
         Value senderSpValue = gen.operand(senderSp);
         Value senderFpValue = gen.operand(senderFp);
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue, getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp);
+    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp, long registerSaver);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,9 +23,9 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Intrinsification for getting the address of an object. The code path(s) between a call to
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Emits code to leave (pop) the current low-level stack frame. This operation also removes the
@@ -33,15 +34,22 @@
  */
 public class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
-    public LeaveCurrentStackFrameNode() {
+    @Input private SaveAllRegistersNode registerSaver;
+
+    public LeaveCurrentStackFrameNode(ValueNode registerSaver) {
         super(StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame();
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame(getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void leaveCurrentStackFrame();
+    public static native void leaveCurrentStackFrame(long registerSaver);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,27 +22,34 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Emits code to leave a low-level stack frame specifically to call out to the C++ method
- * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
  */
 public class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
-    public LeaveUnpackFramesStackFrameNode() {
+    @Input private SaveAllRegistersNode registerSaver;
+
+    public LeaveUnpackFramesStackFrameNode(ValueNode registerSaver) {
         super(StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame();
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame(getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void leaveUnpackFramesStackFrame();
+    public static native void leaveUnpackFramesStackFrame(long registerSaver);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -35,16 +33,16 @@
 /**
  * Node that is used to maintain a stack based counter of how many locks are currently held.
  */
-public final class MonitorCounterNode extends FloatingNode implements LIRGenResLowerable {
+public final class MonitorCounterNode extends FloatingNode implements LIRLowerable {
 
     private MonitorCounterNode() {
         super(null);
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
         assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
-        StackSlot counter = res.getFrameMap().allocateStackSlots(1, new BitSet(0), null);
+        StackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(1, new BitSet(0), null);
         Value result = gen.getLIRGeneratorTool().emitAddress(counter);
         gen.setResult(this, result);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Fri May 30 15:09:09 2014 +0200
@@ -22,30 +22,27 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.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.type.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
  * A call to the {@link NewArrayStub}.
  */
-public class NewArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
+public class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable {
 
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
     @Input private ValueNode hub;
     @Input private ValueNode length;
 
-    public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class);
-
     public NewArrayStubCall(ValueNode hub, ValueNode length) {
         super(defaultStamp);
         this.hub = hub;
@@ -62,9 +59,9 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY);
-        Variable result = gen.getLIRGenerator().emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length));
+        Variable result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -29,7 +31,6 @@
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -41,8 +42,6 @@
 
     @Input private ValueNode hub;
 
-    public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class);
-
     public NewInstanceStubCall(ValueNode hub) {
         super(defaultStamp);
         this.hub = hub;
@@ -60,7 +59,7 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_INSTANCE);
-        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(hub));
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -29,7 +31,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -43,8 +44,6 @@
     @Input private ValueNode dims;
     private final int rank;
 
-    public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class);
-
     public NewMultiArrayStubCall(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode hub, int rank, ValueNode dims) {
         super(foreignCalls, NEW_MULTI_ARRAY, defaultStamp);
         this.hub = hub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,14 +23,13 @@
 
 package com.oracle.graal.hotspot.nodes;
 
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
-public class PrefetchAllocateNode extends FixedWithNextNode implements LIRGenLowerable {
+public class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input private ValueNode distance;
     @Input private ValueNode address;
@@ -42,7 +41,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ((HotSpotNodeLIRBuilder) gen).emitPrefetchAllocate(address, distance);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PushInterpreterFrameNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PushInterpreterFrameNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Saves all allocatable registers.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Value, InputType.Anchor, InputType.Guard})
 public final class SnippetAnchorNode extends FixedWithNextNode implements Simplifiable, GuardingNode {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Association, InputType.Value})
 public final class SnippetLocationProxyNode extends FloatingNode implements Canonicalizable {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,11 +24,11 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Node for a {@linkplain ForeignCallDescriptor foreign} call from within a stub.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,25 +24,23 @@
 
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Performs a tail call to the specified target compiled method, with the parameter taken from the
  * supplied FrameState.
  */
-public class TailcallNode extends FixedWithNextNode implements LIRGenResLowerable {
+public class TailcallNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input(InputType.State) private FrameState frameState;
     @Input private ValueNode target;
@@ -59,20 +57,21 @@
         this.frameState = frameState;
     }
 
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
         HotSpotVMConfig config = runtime().getConfig();
+        LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
         ResolvedJavaMethod method = frameState.method();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
 
         JavaType[] signature = MetaUtil.signatureToTypes(method.getSignature(), isStatic ? null : method.getDeclaringClass());
-        CallingConvention cc = res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.getLIRGeneratorTool().target(), false);
+        CallingConvention cc = lirGen.getResult().getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, lirGen.target(), false);
         List<ValueNode> parameters = new ArrayList<>();
         for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += HIRFrameStateBuilder.stackSlots(frameState.localAt(slot).getKind())) {
             parameters.add(frameState.localAt(slot));
         }
         Value[] args = gen.visitInvokeArguments(cc, parameters);
-        Value address = gen.getLIRGeneratorTool().emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
-        Value entry = gen.getLIRGeneratorTool().emitLoad(Kind.Long, address, null);
+        Value address = lirGen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
+        Value entry = lirGen.emitLoad(Kind.Long, address, null);
         HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
         hsgen.emitTailcall(args, entry);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,15 +22,17 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -42,7 +44,6 @@
     @Input private ValueNode trapRequest;
     @Input private SaveAllRegistersNode registerSaver;
     private final ForeignCallsProvider foreignCalls;
-    public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class);
 
     public UncommonTrapCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode trapRequest) {
         super(StampFactory.forKind(Kind.fromJavaClass(UNCOMMON_TRAP.getResultType())));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,13 +23,14 @@
 package com.oracle.graal.hotspot.nodes;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.nodes.CStringNode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
 
 /**
@@ -40,7 +41,6 @@
 
     private final String format;
     @Input private ValueNode value;
-    public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
 
     public VMErrorNode(String format, ValueNode value) {
         super(StampFactory.forVoid());
@@ -67,7 +67,7 @@
         Value whereArg = emitCString(gen, whereString);
         Value formatArg = emitCString(gen, format);
 
-        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VMErrorNode.VM_ERROR);
+        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VM_ERROR);
         gen.getLIRGeneratorTool().emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable {
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/NarrowOopStamp.java	Fri May 30 15:09:09 2014 +0200
@@ -26,9 +26,8 @@
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
-import com.oracle.graal.nodes.type.*;
 
-public class NarrowOopStamp extends ObjectStamp {
+public class NarrowOopStamp extends AbstractObjectStamp {
 
     public static final PlatformKind NarrowOop = new PlatformKind() {
 
@@ -44,15 +43,20 @@
 
     private final CompressEncoding encoding;
 
-    public NarrowOopStamp(ObjectStamp stamp, CompressEncoding encoding) {
-        this(stamp.type(), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), encoding);
-    }
-
     public NarrowOopStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
         super(type, exactType, nonNull, alwaysNull);
         this.encoding = encoding;
     }
 
+    @Override
+    protected AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        return new NarrowOopStamp(type, exactType, nonNull, alwaysNull, encoding);
+    }
+
+    public static Stamp compressed(AbstractObjectStamp stamp, CompressEncoding encoding) {
+        return new NarrowOopStamp(stamp.type(), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), encoding);
+    }
+
     public Stamp uncompressed() {
         return new ObjectStamp(type(), isExactType(), nonNull(), alwaysNull());
     }
@@ -62,22 +66,7 @@
     }
 
     @Override
-    public Stamp unrestricted() {
-        return new NarrowOopStamp((ObjectStamp) super.unrestricted(), encoding);
-    }
-
-    @Override
-    public Stamp illegal() {
-        return new NarrowOopStamp((ObjectStamp) super.illegal(), encoding);
-    }
-
-    @Override
-    public Kind getStackKind() {
-        return Kind.Object;
-    }
-
-    @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
+    public PlatformKind getPlatformKind(PlatformKindTool tool) {
         return NarrowOop;
     }
 
@@ -85,33 +74,11 @@
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append('n');
-        str.append(super.toString());
+        appendString(str);
         return str.toString();
     }
 
     @Override
-    public Stamp meet(Stamp otherStamp) {
-        if (this == otherStamp) {
-            return this;
-        }
-        if (!isCompatible(otherStamp)) {
-            return StampFactory.illegal();
-        }
-        return new NarrowOopStamp((ObjectStamp) super.meet(otherStamp), encoding);
-    }
-
-    @Override
-    public Stamp join(Stamp otherStamp) {
-        if (this == otherStamp) {
-            return this;
-        }
-        if (!isCompatible(otherStamp)) {
-            return StampFactory.illegal(Kind.Illegal);
-        }
-        return new NarrowOopStamp((ObjectStamp) super.join(otherStamp), encoding);
-    }
-
-    @Override
     public boolean isCompatible(Stamp other) {
         if (this == other) {
             return true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -46,7 +46,7 @@
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
         for (ConstantNode node : getConstantNodes(graph)) {
             if (node.recordsUsages() || !node.gatherUsages(graph).isEmpty()) {
-                if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node)) {
+                if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node)) {
                     throw new VerificationError("illegal object constant: " + node);
                 }
             }
@@ -66,7 +66,14 @@
         if (!isObject(node)) {
             return false;
         }
-        return "Ljava/lang/invoke/DirectMethodHandle;".equals(ObjectStamp.typeOrNull(node).getName());
+        return "Ljava/lang/invoke/DirectMethodHandle;".equals(StampTool.typeOrNull(node).getName());
+    }
+
+    private static boolean isBoundMethodHandle(ConstantNode node) {
+        if (!isObject(node)) {
+            return false;
+        }
+        return StampTool.typeOrNull(node).getName().startsWith("Ljava/lang/invoke/BoundMethodHandle");
     }
 
     @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want")
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,10 +27,11 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.HotSpotVMConfig.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -40,22 +41,24 @@
  * directly. Instead the {@link Class} reference should be obtained from the {@code Klass} object.
  * The reason for this is, that in Class Data Sharing (CDS) a {@code Klass} object is mapped to a
  * fixed address in memory, but the {@code javaMirror} is not (which lives in the Java heap).
- * 
+ *
  * Lowering can introduce new {@link ConstantNode}s containing a {@link Class} reference, thus this
  * phase must be applied after {@link LoweringPhase}.
- * 
+ *
  * @see AheadOfTimeVerificationPhase
  */
 public class LoadJavaMirrorWithKlassPhase extends BasePhase<PhaseContext> {
 
     private final int classMirrorOffset;
+    private final CompressEncoding oopEncoding;
 
-    public LoadJavaMirrorWithKlassPhase(int classMirrorOffset) {
+    public LoadJavaMirrorWithKlassPhase(int classMirrorOffset, CompressEncoding oopEncoding) {
         this.classMirrorOffset = classMirrorOffset;
+        this.oopEncoding = oopEncoding;
     }
 
-    private FloatingReadNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, Constant constant) {
-        if (constant.getKind() == Kind.Object && HotSpotObjectConstant.asObject(constant) instanceof Class<?>) {
+    private ValueNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, Constant constant) {
+        if (constant instanceof HotSpotObjectConstant && HotSpotObjectConstant.asObject(constant) instanceof Class<?>) {
             MetaAccessProvider metaAccess = context.getMetaAccess();
             ResolvedJavaType type = metaAccess.lookupJavaType((Class<?>) HotSpotObjectConstant.asObject(constant));
             assert type instanceof HotSpotResolvedObjectType;
@@ -66,7 +69,12 @@
             Stamp stamp = StampFactory.exactNonNull(metaAccess.lookupJavaType(Class.class));
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, Kind.Object, classMirrorOffset, graph);
             FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp));
-            return freadNode;
+
+            if (HotSpotObjectConstant.isCompressed(constant)) {
+                return CompressionNode.compress(freadNode, oopEncoding);
+            } else {
+                return freadNode;
+            }
         }
         return null;
     }
@@ -75,7 +83,7 @@
     protected void run(StructuredGraph graph, PhaseContext context) {
         for (ConstantNode node : getConstantNodes(graph)) {
             Constant constant = node.asConstant();
-            FloatingReadNode freadNode = getClassConstantReplacement(graph, context, constant);
+            ValueNode freadNode = getClassConstantReplacement(graph, context, constant);
             if (freadNode != null) {
                 node.replace(graph, freadNode);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -45,6 +45,9 @@
                 addReadNodeBarriers((ReadNode) n, graph);
             } else if (n instanceof WriteNode) {
                 addWriteNodeBarriers((WriteNode) n, graph);
+            } else if (n instanceof LoweredAtomicReadAndWriteNode) {
+                LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n;
+                addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph);
             } else if (n instanceof LoweredCompareAndSwapNode) {
                 addCASBarriers((LoweredCompareAndSwapNode) n, graph);
             } else if (n instanceof ArrayRangeWriteNode) {
@@ -75,12 +78,12 @@
     }
 
     protected void addG1PostWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
-        final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value);
+        final boolean alwaysNull = StampTool.isObjectAlwaysNull(value);
         graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(object, value, location, precise, alwaysNull)));
     }
 
     protected void addSerialPostWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
-        final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value);
+        final boolean alwaysNull = StampTool.isObjectAlwaysNull(value);
         final LocationNode loc = (precise ? location : null);
         graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(object, loc, precise, alwaysNull)));
     }
@@ -110,6 +113,33 @@
         }
     }
 
+    private void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode, StructuredGraph graph) {
+        BarrierType barrierType = loweredAtomicReadAndWriteNode.getBarrierType();
+        if (barrierType == BarrierType.PRECISE) {
+            if (useG1GC()) {
+                addG1PreWriteBarrier(loweredAtomicReadAndWriteNode, loweredAtomicReadAndWriteNode.object(), null, loweredAtomicReadAndWriteNode.location(), true,
+                                loweredAtomicReadAndWriteNode.getNullCheck(), graph);
+                addG1PostWriteBarrier(loweredAtomicReadAndWriteNode, loweredAtomicReadAndWriteNode.object(), loweredAtomicReadAndWriteNode.getNewValue(), loweredAtomicReadAndWriteNode.location(),
+                                true, graph);
+            } else {
+                addSerialPostWriteBarrier(loweredAtomicReadAndWriteNode, loweredAtomicReadAndWriteNode.object(), loweredAtomicReadAndWriteNode.getNewValue(), loweredAtomicReadAndWriteNode.location(),
+                                true, graph);
+            }
+        } else if (barrierType == BarrierType.IMPRECISE) {
+            if (useG1GC()) {
+                addG1PreWriteBarrier(loweredAtomicReadAndWriteNode, loweredAtomicReadAndWriteNode.object(), null, loweredAtomicReadAndWriteNode.location(), true,
+                                loweredAtomicReadAndWriteNode.getNullCheck(), graph);
+                addG1PostWriteBarrier(loweredAtomicReadAndWriteNode, loweredAtomicReadAndWriteNode.object(), loweredAtomicReadAndWriteNode.getNewValue(), loweredAtomicReadAndWriteNode.location(),
+                                false, graph);
+            } else {
+                addSerialPostWriteBarrier(loweredAtomicReadAndWriteNode, loweredAtomicReadAndWriteNode.object(), loweredAtomicReadAndWriteNode.getNewValue(), loweredAtomicReadAndWriteNode.location(),
+                                false, graph);
+            }
+        } else {
+            assert barrierType == BarrierType.NONE;
+        }
+    }
+
     private void addCASBarriers(LoweredCompareAndSwapNode node, StructuredGraph graph) {
         BarrierType barrierType = node.getBarrierType();
         if (barrierType == BarrierType.PRECISE) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,13 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
@@ -94,9 +94,6 @@
         }
     }
 
-    public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Word.class);
-    public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Word.class);
-
     @NodeIntrinsic(ForeignCallNode.class)
     public static native void encryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +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.hotspot.replacements;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-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.replacements.nodes.*;
-
-/**
- * Common base class for method handle invoke nodes.
- */
-public abstract class AbstractMethodHandleNode extends MacroNode implements Canonicalizable {
-
-    private static final ResolvedJavaField methodHandleFormField;
-    private static final ResolvedJavaField lambdaFormVmentryField;
-    private static final ResolvedJavaField memberNameClazzField;
-    private static final ResolvedJavaField memberNameVmtargetField;
-
-    // Replacement method data
-    private ResolvedJavaMethod replacementTargetMethod;
-    private JavaType replacementReturnType;
-    @Input private final NodeInputList<ValueNode> replacementArguments;
-
-    /**
-     * Search for an instance field with the given name in a class.
-     * 
-     * @param className name of the class to search in
-     * @param fieldName name of the field to be searched
-     * @return resolved java field
-     * @throws ClassNotFoundException
-     */
-    private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
-        Class<?> clazz = Class.forName(className);
-        ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
-        ResolvedJavaField[] fields = type.getInstanceFields(false);
-        for (ResolvedJavaField field : fields) {
-            if (field.getName().equals(fieldName)) {
-                return field;
-            }
-        }
-        return null;
-    }
-
-    static {
-        try {
-            methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
-            lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
-            memberNameClazzField = findFieldInClass("java.lang.invoke.MemberName", "clazz");
-            memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
-        } catch (ClassNotFoundException | SecurityException ex) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public AbstractMethodHandleNode(Invoke invoke) {
-        super(invoke);
-
-        // See if we need to save some replacement method data.
-        CallTargetNode callTarget = invoke.callTarget();
-        if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
-            SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
-            replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
-            replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
-            replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
-        } else {
-            // NodeInputList can't be null.
-            replacementArguments = new NodeInputList<>(this);
-        }
-    }
-
-    /**
-     * Get the receiver of a MethodHandle.invokeBasic call.
-     * 
-     * @return the receiver argument node
-     */
-    private ValueNode getReceiver() {
-        return arguments.first();
-    }
-
-    /**
-     * Get the MemberName argument of a MethodHandle.linkTo* call.
-     * 
-     * @return the MemberName argument node (which is the last argument)
-     */
-    private ValueNode getMemberName() {
-        return arguments.last();
-    }
-
-    /**
-     * Used from {@link MethodHandleInvokeBasicNode} to get the target {@link InvokeNode} if the
-     * method handle receiver is constant.
-     * 
-     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
-     */
-    protected InvokeNode getInvokeBasicTarget() {
-        ValueNode methodHandleNode = getReceiver();
-        if (methodHandleNode.isConstant() && !methodHandleNode.isNullConstant()) {
-            // Get the data we need from MethodHandle.LambdaForm.MemberName
-            Constant methodHandle = methodHandleNode.asConstant();
-            Constant lambdaForm = methodHandleFormField.readValue(methodHandle);
-            Constant memberName = lambdaFormVmentryField.readValue(lambdaForm);
-            return getTargetInvokeNode(memberName);
-        }
-        return null;
-    }
-
-    /**
-     * Used from {@link MethodHandleLinkToStaticNode}, {@link MethodHandleLinkToSpecialNode},
-     * {@link MethodHandleLinkToVirtualNode}, and {@link MethodHandleLinkToInterfaceNode} to get the
-     * target {@link InvokeNode} if the member name argument is constant.
-     * 
-     * @return invoke node for the member name target
-     */
-    protected InvokeNode getLinkToTarget() {
-        ValueNode memberNameNode = getMemberName();
-        if (memberNameNode.isConstant() && !memberNameNode.isNullConstant()) {
-            Constant memberName = memberNameNode.asConstant();
-            return getTargetInvokeNode(memberName);
-        }
-        return null;
-    }
-
-    /**
-     * Helper function to get the {@link InvokeNode} for the vmtarget of a
-     * java.lang.invoke.MemberName.
-     * 
-     * @param memberName constant member name node
-     * @return invoke node for the member name target
-     */
-    private InvokeNode getTargetInvokeNode(Constant memberName) {
-        // Get the data we need from MemberName
-        Constant clazz = memberNameClazzField.readValue(memberName);
-        Constant vmtarget = memberNameVmtargetField.readValue(memberName);
-
-        // Create a method from the vmtarget pointer
-        Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(clazz);
-        HotSpotResolvedObjectType holderClass = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c);
-        HotSpotResolvedJavaMethod targetMethod = HotSpotResolvedJavaMethod.fromMetaspace(vmtarget.asLong());
-
-        // In lambda forms we erase signature types to avoid resolving issues
-        // involving class loaders. When we optimize a method handle invoke
-        // to a direct call we must cast the receiver and arguments to its
-        // actual types.
-        HotSpotSignature signature = targetMethod.getSignature();
-        final boolean isStatic = Modifier.isStatic(targetMethod.getModifiers());
-        final int receiverSkip = isStatic ? 0 : 1;
-
-        // Cast receiver to its type.
-        if (!isStatic) {
-            JavaType receiverType = holderClass;
-            maybeCastArgument(0, receiverType);
-        }
-
-        // Cast reference arguments to its type.
-        for (int index = 0; index < signature.getParameterCount(false); index++) {
-            JavaType parameterType = signature.getParameterType(index, holderClass);
-            maybeCastArgument(receiverSkip + index, parameterType);
-        }
-
-        // Try to get the most accurate receiver type
-        if (this instanceof MethodHandleLinkToVirtualNode || this instanceof MethodHandleLinkToInterfaceNode) {
-            ResolvedJavaType receiverType = ObjectStamp.typeOrNull(getReceiver().stamp());
-            if (receiverType != null) {
-                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
-                if (concreteMethod != null) {
-                    return createTargetInvokeNode(concreteMethod);
-                }
-            }
-        }
-
-        if (targetMethod.canBeStaticallyBound()) {
-            return createTargetInvokeNode(targetMethod);
-        }
-
-        ResolvedJavaMethod concreteMethod = targetMethod.uniqueConcreteMethod();
-        if (concreteMethod != null) {
-            return createTargetInvokeNode(concreteMethod);
-        }
-
-        return null;
-    }
-
-    /**
-     * Inserts a node to cast the argument at index to the given type if the given type is more
-     * concrete than the argument type.
-     * 
-     * @param index of the argument to be cast
-     * @param type the type the argument should be cast to
-     */
-    private void maybeCastArgument(int index, JavaType type) {
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType targetType = (ResolvedJavaType) type;
-            if (!targetType.isPrimitive()) {
-                ValueNode argument = arguments.get(index);
-                ResolvedJavaType argumentType = ObjectStamp.typeOrNull(argument.stamp());
-                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
-                    PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
-                    arguments.set(index, piNode);
-                }
-            }
-        }
-    }
-
-    /**
-     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
-     * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
-     * 
-     * @param targetMethod the method the be called
-     * @return invoke node for the member name target
-     */
-    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
-        InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special;
-        JavaType returnType = targetMethod.getSignature().getReturnType(null);
-
-        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
-        // needs to be popped.
-        ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
-        ValueNode[] targetArguments;
-        if (this instanceof MethodHandleInvokeBasicNode) {
-            targetArguments = originalArguments;
-        } else {
-            assert this instanceof MethodHandleLinkToStaticNode || this instanceof MethodHandleLinkToSpecialNode || this instanceof MethodHandleLinkToVirtualNode ||
-                            this instanceof MethodHandleLinkToInterfaceNode : this;
-            targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
-        }
-
-        // If there is already replacement information, use that instead.
-        MethodCallTargetNode callTarget;
-        if (replacementTargetMethod == null) {
-            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
-        } else {
-            ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
-            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
-        }
-        graph().add(callTarget);
-
-        // The call target can have a different return type than the invoker,
-        // e.g. the target returns an Object but the invoker void. In this case
-        // we need to use the stamp of the invoker. Note: always using the
-        // invoker's stamp would be wrong because it's a less concrete type
-        // (usually java.lang.Object).
-        InvokeNode invoke;
-        if (stamp() == StampFactory.forVoid()) {
-            invoke = new InvokeNode(callTarget, getBci(), stamp());
-        } else {
-            invoke = new InvokeNode(callTarget, getBci());
-        }
-        graph().add(invoke);
-        invoke.setStateAfter(stateAfter());
-        return invoke;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,6 +27,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -34,8 +36,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.phases.*;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.runtime.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.loop.phases.*;
@@ -33,7 +34,6 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.nodes.*;
@@ -69,8 +69,8 @@
     }
 
     private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
-        ResolvedJavaType srcType = ObjectStamp.typeOrNull(getSource().stamp());
-        ResolvedJavaType destType = ObjectStamp.typeOrNull(getDestination().stamp());
+        ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp());
+        ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp());
 
         if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
             return null;
@@ -143,13 +143,13 @@
      * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays.
      */
     private boolean isExact() {
-        ResolvedJavaType srcType = ObjectStamp.typeOrNull(getSource().stamp());
+        ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp());
         if (srcType.getComponentType().getKind().isPrimitive() || getSource() == getDestination()) {
             return true;
         }
 
-        ResolvedJavaType destType = ObjectStamp.typeOrNull(getDestination().stamp());
-        if (ObjectStamp.isExactType(getDestination().stamp())) {
+        ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp());
+        if (StampTool.isExactType(getDestination().stamp())) {
             if (destType != null && destType.isAssignableFrom(srcType)) {
                 return true;
             }
@@ -171,10 +171,10 @@
                     if (state.getState() == EscapeState.Virtual) {
                         type = state.getVirtualObject().type();
                     } else {
-                        type = ObjectStamp.typeOrNull(state.getMaterializedValue());
+                        type = StampTool.typeOrNull(state.getMaterializedValue());
                     }
                 } else {
-                    type = ObjectStamp.typeOrNull(entry);
+                    type = StampTool.typeOrNull(entry);
                 }
                 if (type == null || !destComponentType.isAssignableFrom(type)) {
                     return false;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.GuardingPiNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.lang.reflect.*;
 import java.util.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -34,10 +34,10 @@
 public class CallSiteSubstitutions implements ReplacementsProvider {
 
     @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
-        replacements.registerSubstitutions(ConstantCallSiteSubstitutions.class);
-        replacements.registerSubstitutions(MutableCallSiteSubstitutions.class);
-        replacements.registerSubstitutions(VolatileCallSiteSubstitutions.class);
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
+        replacements.registerSubstitutions(ConstantCallSite.class, ConstantCallSiteSubstitutions.class);
+        replacements.registerSubstitutions(MutableCallSite.class, MutableCallSiteSubstitutions.class);
+        replacements.registerSubstitutions(VolatileCallSite.class, VolatileCallSiteSubstitutions.class);
     }
 
     @ClassSubstitution(ConstantCallSite.class)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -31,6 +31,7 @@
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -38,7 +39,6 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,13 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.nodes.*;
@@ -109,9 +109,6 @@
         }
     }
 
-    public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
-    public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class);
-
     @NodeIntrinsic(ForeignCallNode.class)
     public static native void encryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key, Word r, int inLength);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompositeValueClassSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompositeValueClassSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeClassSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeClassSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -22,28 +22,50 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import java.lang.reflect.*;
+import java.util.zip.*;
+
+import sun.misc.*;
+import sun.reflect.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 
 @ServiceProvider(ReplacementsProvider.class)
 public class HotSpotSubstitutions implements ReplacementsProvider {
 
+    static class NamedType implements Type {
+        private final String name;
+
+        public NamedType(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
     @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
-        replacements.registerSubstitutions(ObjectSubstitutions.class);
-        replacements.registerSubstitutions(SystemSubstitutions.class);
-        replacements.registerSubstitutions(ThreadSubstitutions.class);
-        replacements.registerSubstitutions(UnsafeSubstitutions.class);
-        replacements.registerSubstitutions(ClassSubstitutions.class);
-        replacements.registerSubstitutions(AESCryptSubstitutions.class);
-        replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class);
-        replacements.registerSubstitutions(CRC32Substitutions.class);
-        replacements.registerSubstitutions(ReflectionSubstitutions.class);
-        replacements.registerSubstitutions(HotSpotNodeClassSubstitutions.class);
-        replacements.registerSubstitutions(HotSpotNodeSubstitutions.class);
-        replacements.registerSubstitutions(CompositeValueClassSubstitutions.class);
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
+        replacements.registerSubstitutions(Object.class, ObjectSubstitutions.class);
+        replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
+        replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
+        replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class);
+        replacements.registerSubstitutions(Class.class, ClassSubstitutions.class);
+        replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class);
+        replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
+        replacements.registerSubstitutions(NodeClass.class, HotSpotNodeClassSubstitutions.class);
+        replacements.registerSubstitutions(Node.class, HotSpotNodeSubstitutions.class);
+        replacements.registerSubstitutions(CompositeValueClass.class, CompositeValueClassSubstitutions.class);
+        replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class);
+        replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.Hints;
@@ -40,7 +41,6 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -28,12 +28,12 @@
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
@@ -44,6 +44,12 @@
 
 /**
  * Snippet for loading the exception object at the start of an exception dispatcher.
+ * <p>
+ * The frame state upon entry to an exception handler is such that it is a
+ * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
+ * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
+ * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
+ * find the exception object to be rethrown.
  */
 public class LoadExceptionObjectSnippets implements Snippets {
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .invokeBasic(Object...)}.
- */
-public class MethodHandleInvokeBasicNode extends AbstractMethodHandleNode {
-
-    public MethodHandleInvokeBasicNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getInvokeBasicTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToInterface(Object...)}.
- */
-public class MethodHandleLinkToInterfaceNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToInterfaceNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToSpecial(Object...)}.
- */
-public class MethodHandleLinkToSpecialNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToSpecialNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToStatic(Object...)}.
- */
-public class MethodHandleLinkToStaticNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToStaticNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToVirtual(Object...)}.
- */
-public class MethodHandleLinkToVirtualNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToVirtualNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,292 @@
+/*
+ * 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.replacements;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import java.lang.invoke.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.api.replacements.MethodHandleAccessProvider.IntrinsicMethod;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.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.replacements.nodes.*;
+
+/**
+ * Node for invocation methods defined on the class {@link MethodHandle}.
+ */
+public class MethodHandleNode extends MacroNode implements Canonicalizable {
+
+    /** The method that this node is representing. */
+    private final IntrinsicMethod intrinsicMethod;
+
+    // Replacement method data
+    private ResolvedJavaMethod replacementTargetMethod;
+    private JavaType replacementReturnType;
+    @Input private final NodeInputList<ValueNode> replacementArguments;
+
+    public MethodHandleNode(Invoke invoke) {
+        super(invoke);
+
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        intrinsicMethod = lookupMethodHandleIntrinsic(callTarget.targetMethod());
+        assert intrinsicMethod != null;
+
+        // See if we need to save some replacement method data.
+        if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
+            SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
+            replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
+            replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
+            replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
+        } else {
+            // NodeInputList can't be null.
+            replacementArguments = new NodeInputList<>(this);
+        }
+    }
+
+    /**
+     * Returns the method handle method intrinsic identifier for the provided method, or
+     * {@code null} if the method is not a method that can be handled by this class.
+     */
+    public static IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
+        return methodHandleAccess().lookupMethodHandleIntrinsic(method);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        InvokeNode invoke;
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                invoke = getInvokeBasicTarget();
+                break;
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                invoke = getLinkToTarget();
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        if (invoke != null) {
+            return invoke;
+        }
+        return this;
+    }
+
+    /**
+     * Get the receiver of a MethodHandle.invokeBasic call.
+     *
+     * @return the receiver argument node
+     */
+    private ValueNode getReceiver() {
+        return arguments.first();
+    }
+
+    /**
+     * Get the MemberName argument of a MethodHandle.linkTo* call.
+     *
+     * @return the MemberName argument node (which is the last argument)
+     */
+    private ValueNode getMemberName() {
+        return arguments.last();
+    }
+
+    /**
+     * Returns the {@link MethodHandleAccessProvider} that provides introspection of internal
+     * {@link MethodHandle} data.
+     */
+    private static MethodHandleAccessProvider methodHandleAccess() {
+        return runtime().getHostProviders().getMethodHandleAccess();
+    }
+
+    /**
+     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
+     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
+     *
+     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
+     */
+    protected InvokeNode getInvokeBasicTarget() {
+        ValueNode methodHandleNode = getReceiver();
+        if (methodHandleNode.isConstant()) {
+            return getTargetInvokeNode(methodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asConstant(), false));
+        }
+        return null;
+    }
+
+    /**
+     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
+     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
+     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
+     * the member name argument is constant.
+     *
+     * @return invoke node for the member name target
+     */
+    protected InvokeNode getLinkToTarget() {
+        ValueNode memberNameNode = getMemberName();
+        if (memberNameNode.isConstant()) {
+            return getTargetInvokeNode(methodHandleAccess().resolveLinkToTarget(memberNameNode.asConstant()));
+        }
+        return null;
+    }
+
+    /**
+     * Helper function to get the {@link InvokeNode} for the targetMethod of a
+     * java.lang.invoke.MemberName.
+     *
+     * @param targetMethod the target, already loaded from the member name node
+     * @return invoke node for the member name target
+     */
+    private InvokeNode getTargetInvokeNode(ResolvedJavaMethod targetMethod) {
+        if (targetMethod == null) {
+            return null;
+        }
+
+        // In lambda forms we erase signature types to avoid resolving issues
+        // involving class loaders. When we optimize a method handle invoke
+        // to a direct call we must cast the receiver and arguments to its
+        // actual types.
+        Signature signature = targetMethod.getSignature();
+        final boolean isStatic = targetMethod.isStatic();
+        final int receiverSkip = isStatic ? 0 : 1;
+
+        // Cast receiver to its type.
+        if (!isStatic) {
+            JavaType receiverType = targetMethod.getDeclaringClass();
+            maybeCastArgument(0, receiverType);
+        }
+
+        // Cast reference arguments to its type.
+        for (int index = 0; index < signature.getParameterCount(false); index++) {
+            JavaType parameterType = signature.getParameterType(index, targetMethod.getDeclaringClass());
+            maybeCastArgument(receiverSkip + index, parameterType);
+        }
+
+        // Try to get the most accurate receiver type
+        if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+            ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
+            if (receiverType != null) {
+                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
+                if (concreteMethod != null) {
+                    return createTargetInvokeNode(concreteMethod);
+                }
+            }
+        }
+
+        if (targetMethod.canBeStaticallyBound()) {
+            return createTargetInvokeNode(targetMethod);
+        }
+
+        ResolvedJavaMethod concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod);
+        if (concreteMethod != null) {
+            return createTargetInvokeNode(concreteMethod);
+        }
+
+        return null;
+    }
+
+    /**
+     * Inserts a node to cast the argument at index to the given type if the given type is more
+     * concrete than the argument type.
+     *
+     * @param index of the argument to be cast
+     * @param type the type the argument should be cast to
+     */
+    private void maybeCastArgument(int index, JavaType type) {
+        if (type instanceof ResolvedJavaType) {
+            ResolvedJavaType targetType = (ResolvedJavaType) type;
+            if (!targetType.isPrimitive()) {
+                ValueNode argument = arguments.get(index);
+                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
+                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
+                    PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
+                    arguments.set(index, piNode);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
+     * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
+     *
+     * @param targetMethod the method the be called
+     * @return invoke node for the member name target
+     */
+    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
+        InvokeKind invokeKind = targetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        JavaType returnType = targetMethod.getSignature().getReturnType(null);
+
+        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
+        // needs to be popped.
+        ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
+        ValueNode[] targetArguments;
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                targetArguments = originalArguments;
+                break;
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+
+        // If there is already replacement information, use that instead.
+        MethodCallTargetNode callTarget;
+        if (replacementTargetMethod == null) {
+            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
+        } else {
+            ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
+            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
+        }
+        graph().add(callTarget);
+
+        // The call target can have a different return type than the invoker,
+        // e.g. the target returns an Object but the invoker void. In this case
+        // we need to use the stamp of the invoker. Note: always using the
+        // invoker's stamp would be wrong because it's a less concrete type
+        // (usually java.lang.Object).
+        InvokeNode invoke;
+        if (stamp() == StampFactory.forVoid()) {
+            invoke = new InvokeNode(callTarget, getBci(), stamp());
+        } else {
+            invoke = new InvokeNode(callTarget, getBci());
+        }
+        graph().add(invoke);
+        invoke.setStateAfter(stateAfter());
+        return invoke;
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -47,7 +47,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
 import com.oracle.graal.replacements.Snippet.Fold;
@@ -180,7 +180,7 @@
                         // owns the bias and we need to revoke that bias. The revocation will occur
                         // in the interpreter runtime.
                         traceObject(trace, "+lock{stub:revoke}", object, true);
-                        monitorenterStub(MONITORENTER, object, lock);
+                        monitorenterStubC(MONITORENTER, object, lock);
                         return;
                     } else {
                         // At this point we know the epoch has expired, meaning that the
@@ -200,7 +200,7 @@
                         // succeeded in biasing it toward itself and we need to revoke that
                         // bias. The revocation will occur in the runtime in the slow case.
                         traceObject(trace, "+lock{stub:epoch-expired}", object, true);
-                        monitorenterStub(MONITORENTER, object, lock);
+                        monitorenterStubC(MONITORENTER, object, lock);
                         return;
                     }
                 } else {
@@ -257,7 +257,7 @@
             if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) {
                 // Most likely not a recursive lock, go into a slow runtime call
                 traceObject(trace, "+lock{stub:failed-cas}", object, true);
-                monitorenterStub(MONITORENTER, object, lock);
+                monitorenterStubC(MONITORENTER, object, lock);
                 return;
             } else {
                 // Recursively locked => write 0 to the lock slot
@@ -283,7 +283,7 @@
         // cannot float about the null check above
         final Word lock = beginLockScope(lockDepth);
         traceObject(trace, "+lock{stub}", object, true);
-        monitorenterStub(MONITORENTER, object, lock);
+        monitorenterStubC(MONITORENTER, object, lock);
     }
 
     @Snippet
@@ -324,7 +324,7 @@
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
                 traceObject(trace, "-lock{stub}", object, false);
-                monitorexitStub(MONITOREXIT, object, lock);
+                monitorexitStubC(MONITOREXIT, object, lock);
             } else {
                 traceObject(trace, "-lock{cas}", object, false);
             }
@@ -341,7 +341,7 @@
         verifyOop(object);
         traceObject(trace, "-lock{stub}", object, false);
         final Word lock = CurrentLockNode.currentLock(lockDepth);
-        monitorexitStub(MONITOREXIT, object, lock);
+        monitorexitStubC(MONITOREXIT, object, lock);
         endLockScope();
         decCounter();
     }
@@ -457,7 +457,7 @@
         }
 
         static boolean isTracingEnabledForType(ValueNode object) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(object.stamp());
+            ResolvedJavaType type = StampTool.typeOrNull(object.stamp());
             if (TRACE_TYPE_FILTER == null) {
                 return false;
             } else {
@@ -511,7 +511,7 @@
                         callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnType));
                         invoke = graph.add(new InvokeNode(callTarget, 0));
                         List<ValueNode> stack = Collections.emptyList();
-                        FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], new MonitorIdNode[0], false, false);
+                        FrameState stateAfter = new FrameState(graph.method(), BytecodeFrame.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], new MonitorIdNode[0], false, false);
                         invoke.setStateAfter(graph.add(stateAfter));
                         graph.addBeforeFixed(ret, invoke);
 
@@ -531,9 +531,9 @@
     public static final ForeignCallDescriptor MONITOREXIT = new ForeignCallDescriptor("monitorexit", void.class, Object.class, Word.class);
 
     @NodeIntrinsic(ForeignCallNode.class)
-    private static native void monitorenterStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
+    private static native void monitorenterStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
 
     @NodeIntrinsic(ForeignCallNode.class)
-    private static native void monitorexitStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
+    private static native void monitorexitStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -24,17 +24,18 @@
 
 import static com.oracle.graal.api.code.UnsignedMath.*;
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 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.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 import static com.oracle.graal.replacements.nodes.ExplodeLoopNode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
@@ -46,7 +47,6 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -179,15 +179,11 @@
     @Snippet
     public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
                     @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) {
-        if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
-            // This handles both negative array sizes and very large array sizes
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
-        }
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext);
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
     }
 
     private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, @ConstantParameter Register threadRegister,
-                    @ConstantParameter boolean maybeUnroll, String typeContext) {
+                    @ConstantParameter boolean maybeUnroll, String typeContext, boolean skipNegativeCheck) {
         Object result;
         int alignment = wordSize();
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
@@ -195,7 +191,7 @@
         Word top = readTlabTop(thread);
         Word end = readTlabEnd(thread);
         Word newTop = top.add(allocationSize);
-        if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+        if ((skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
             writeTlabTop(thread, newTop);
             emitPrefetchAllocate(newTop, true);
             newarray_loopInit.inc();
@@ -246,7 +242,7 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
 
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type");
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true);
     }
 
     /**
@@ -420,7 +416,7 @@
             ConstantNode hub = ConstantNode.forConstant(arrayType.klass(), providers.getMetaAccess(), graph);
             final int headerSize = HotSpotGraalRuntime.getArrayBaseOffset(elementKind);
             HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
-            int log2ElementSize = CodeUtil.log2(lowerer.getScalingFactor(elementKind));
+            int log2ElementSize = CodeUtil.log2(lowerer.arrayScalingFactor(elementKind));
 
             Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("hub", hub);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Fri May 30 15:09:09 2014 +0200
@@ -60,7 +60,7 @@
             return null;
         }
 
-        ResolvedJavaType type = ObjectStamp.typeOrNull(getObject());
+        ResolvedJavaType type = StampTool.typeOrNull(getObject());
         if (type != null) {
             if (type.isArray()) {
                 Method method = ObjectCloneSnippets.arrayCloneMethods.get(type.getComponentType().getKind());
@@ -106,7 +106,7 @@
     /*
      * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
      * exact type) and if it is a cloneable type.
-     * 
+     *
      * If yes, then the exact type is returned, otherwise it returns null.
      */
     private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectGetClassNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectGetClassNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -68,13 +67,10 @@
         if (usages().isEmpty()) {
             return null;
         } else {
-            Stamp stamp = getObject().stamp();
-            if (stamp instanceof ObjectStamp) {
-                ObjectStamp objectStamp = (ObjectStamp) stamp;
-                if (objectStamp.isLegal() && objectStamp.isExactType()) {
-                    Constant clazz = objectStamp.type().getEncoding(Representation.JavaClass);
-                    return ConstantNode.forConstant(clazz, tool.getMetaAccess(), graph());
-                }
+            if (StampTool.isExactType(getObject())) {
+                ResolvedJavaType type = StampTool.typeOrNull(getObject());
+                Constant clazz = type.getEncoding(Representation.JavaClass);
+                return ConstantNode.forConstant(clazz, tool.getMetaAccess(), graph());
             }
             return this;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.meta.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,11 +25,11 @@
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
@@ -39,7 +40,6 @@
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -35,7 +36,8 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.word.*;
 
 /**
@@ -45,37 +47,42 @@
  *
  * The steps taken by this frame are as follows:
  *
- * - push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all potentially
- * live registers (at a pollpoint many registers can be live).
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
  *
- * - call the C routine: Deoptimization::fetch_unroll_info (this function returns information about
- * the number and size of interpreter frames which are equivalent to the frame which is being
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
  * deoptimized)
  *
- * - deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
  * be captured in the vframeArray as needed.
  *
- * - deallocate the deoptimization frame
+ * <li>deallocate the deoptimization frame
  *
- * - in a loop using the information returned in the previous step push new interpreter frames (take
- * care to propagate the return values through each new frame pushed)
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
  *
- * - create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
  *
- * - call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
  * interpreter frame which was just created)
  *
- * - deallocate the dummy unpack_frame
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
  *
- * - ensure that all the return values are correctly set and then do a return to the interpreter
- * entry point
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
  */
 public class DeoptimizationStub extends SnippetStub {
 
     private final TargetDescription target;
 
     public DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super(DeoptimizationStub.class, "deoptimizationHandler", providers, target, linkage);
         this.target = target;
     }
 
@@ -97,46 +104,30 @@
     }
 
     /**
-     * Uncommon trap.
-     *
-     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
-     * routine captures the return values and returns a structure which describes the current frame
-     * size and the sizes of all replacement frames. The current frame is compiled code and may
-     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
-     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
-     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
-     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
-     * was patched.
-     *
-     * <p>
-     * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
-     * because we change the current stack layout and so the code is very sensitive to register
-     * allocation.</b>
+     * Deoptimization handler for normal deoptimization
+     * {@link HotSpotVMConfig#deoptimizationUnpackDeopt}.
      */
     @Snippet
-    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+    private static void deoptimizationHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
         final Word thread = registerAsWord(threadRegister);
-        long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
 
-        final int actionAndReason = readPendingDeoptimization(thread);
-        writePendingDeoptimization(thread, -1);
-
-        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason);
+        final Word unrollBlock = fetchUnrollInfo(registerSaver);
 
         // Pop all the frames we must move/replace.
         //
         // Frame picture (youngest to oldest)
-        // 1: self-frame (no frame link)
-        // 2: deoptimizing frame (no frame link)
+        // 1: self-frame
+        // 2: deoptimizing frame
         // 3: caller of deoptimizing frame (could be compiled/interpreted).
 
         // Pop self-frame.
-        LeaveCurrentStackFrameNode.leaveCurrentStackFrame();
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver);
 
         // Load the initial info we should save (e.g. frame pointer).
         final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
 
-        // Pop deoptimized frame
+        // Pop deoptimized frame.
         final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset());
         LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
 
@@ -144,13 +135,15 @@
          * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
          * total size of the interpreter frames plus shadow page size. Bang one page at a time
          * because large sizes can bang beyond yellow and red zones.
+         *
+         * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
          */
         final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
         final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages();
         Word stackPointer = readRegister(stackPointerRegister);
 
         for (int i = 1; i < bangPages; i++) {
-            stackPointer.writeInt(-(i * pageSize()), i);
+            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0);
         }
 
         // Load number of interpreter frames.
@@ -191,13 +184,13 @@
          * unknown alignment we need to align it here before calling C++ code.
          */
         final Word senderFp = initialInfo;
-        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp);
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver);
 
-        // Pass uncommon trap mode to unpack frames.
-        final int mode = deoptimizationUnpackUncommonTrap();
+        // Pass unpack deopt mode to unpack frames.
+        final int mode = deoptimizationUnpackDeopt();
         unpackFrames(UNPACK_FRAMES, thread, mode);
 
-        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame();
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver);
     }
 
     /**
@@ -221,6 +214,19 @@
         return config().useStackBanging ? config().stackShadowPages : 0;
     }
 
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    private static int stackBias() {
+        return config().stackBias;
+    }
+
     @Fold
     private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
         return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
@@ -266,12 +272,6 @@
         return config().deoptimizationUnpackUncommonTrap;
     }
 
-    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = descriptorFor(DeoptimizationStub.class, "fetchUnrollInfo");
-    public static final ForeignCallDescriptor UNPACK_FRAMES = descriptorFor(DeoptimizationStub.class, "unpackFrames");
-
-    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
-    public static native Word fetchUnrollInfo(@ConstantNodeParameter ForeignCallDescriptor fetchUnrollInfo, Word thread);
-
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Fri May 30 15:09:09 2014 +0200
@@ -50,7 +50,7 @@
 public class ExceptionHandlerStub extends SnippetStub {
 
     public ExceptionHandlerStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("exceptionHandler", providers, target, linkage);
     }
 
     /**
@@ -142,7 +142,7 @@
         return enabled || cAssertionsEnabled();
     }
 
-    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc");
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class);
 
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Fri May 30 15:09:09 2014 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Fri May 30 15:09:09 2014 +0200
@@ -53,7 +53,7 @@
 public class NewArrayStub extends SnippetStub {
 
     public NewArrayStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("newArray", providers, target, linkage);
     }
 
     @Override
@@ -97,7 +97,7 @@
 
         // check that array length is small enough for fast path.
         Word thread = registerAsWord(threadRegister);
-        if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
+        if (length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
             Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging());
             if (memory.notEqual(0)) {
                 if (logging()) {
@@ -115,7 +115,7 @@
         return verifyObject(getAndClearObjectResult(thread));
     }
 
-    public static final ForeignCallDescriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC");
+    public static final ForeignCallDescriptor NEW_ARRAY_C = newDescriptor(NewArrayStub.class, "newArrayC", void.class, Word.class, Word.class, int.class);
 
     @NodeIntrinsic(StubForeignCallNode.class)
     public static native void newArrayC(@ConstantNodeParameter ForeignCallDescriptor newArrayC, Word thread, Word hub, int length);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
@@ -54,22 +53,16 @@
 public class NewInstanceStub extends SnippetStub {
 
     public NewInstanceStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("newInstance", providers, target, linkage);
     }
 
     @Override
     protected Arguments makeArguments(SnippetInfo stub) {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
 
-        // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we
-        // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since
-        // the int[] class will never be unloaded.
-        Constant intArrayHub = intArrayType.klass();
-        intArrayHub = Constant.forIntegerKind(runtime().getTarget().wordKind, intArrayHub.asLong());
-
         Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS, LoweringTool.StandardLoweringStage.HIGH_TIER);
         args.add("hub", null);
-        args.addConst("intArrayHub", intArrayHub);
+        args.addConst("intArrayHub", intArrayType.klass());
         args.addConst("threadRegister", providers.getRegisters().getThreadRegister());
         return args;
     }
@@ -258,7 +251,7 @@
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
 
-    public static final ForeignCallDescriptor NEW_INSTANCE_C = descriptorFor(NewInstanceStub.class, "newInstanceC");
+    public static final ForeignCallDescriptor NEW_INSTANCE_C = newDescriptor(NewInstanceStub.class, "newInstanceC", void.class, Word.class, Word.class);
 
     @NodeIntrinsic(StubForeignCallNode.class)
     public static native void newInstanceC(@ConstantNodeParameter ForeignCallDescriptor newInstanceC, Word thread, Word hub);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Fri May 30 15:09:09 2014 +0200
@@ -44,9 +44,9 @@
 
     static class Template extends AbstractTemplates {
 
-        Template(HotSpotProviders providers, TargetDescription target, Class<? extends Snippets> declaringClass) {
+        Template(HotSpotProviders providers, TargetDescription target, Class<? extends Snippets> declaringClass, String snippetMethodName) {
             super(providers, providers.getSnippetReflection(), target);
-            this.info = snippet(declaringClass, null);
+            this.info = snippet(declaringClass, snippetMethodName);
         }
 
         /**
@@ -65,11 +65,26 @@
     /**
      * Creates a new snippet stub.
      *
+     * @param snippetMethodName name of the single {@link Snippet} annotated method in the class of
+     *            this object
      * @param linkage linkage details for a call to the stub
      */
-    public SnippetStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+    public SnippetStub(String snippetMethodName, HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        this(null, snippetMethodName, providers, target, linkage);
+    }
+
+    /**
+     * Creates a new snippet stub.
+     *
+     * @param snippetDeclaringClass this class in which the {@link Snippet} annotated method is
+     *            declared. If {@code null}, this the class of this object is used.
+     * @param snippetMethodName name of the single {@link Snippet} annotated method in
+     *            {@code snippetDeclaringClass}
+     * @param linkage linkage details for a call to the stub
+     */
+    public SnippetStub(Class<? extends Snippets> snippetDeclaringClass, String snippetMethodName, HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, linkage);
-        this.snippet = new Template(providers, target, getClass());
+        this.snippet = new Template(providers, target, snippetDeclaringClass == null ? getClass() : snippetDeclaringClass, snippetMethodName);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,8 @@
 package com.oracle.graal.hotspot.stubs;
 
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.CStringNode.*;
@@ -48,14 +47,20 @@
  */
 public class StubUtil {
 
-    public static final ForeignCallDescriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC");
+    public static final ForeignCallDescriptor VM_MESSAGE_C = newDescriptor(StubUtil.class, "vmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class);
+
+    public static ForeignCallDescriptor newDescriptor(Class<?> stubClass, String name, Class<?> resultType, Class<?>... argumentTypes) {
+        ForeignCallDescriptor d = new ForeignCallDescriptor(name, resultType, argumentTypes);
+        assert descriptorFor(stubClass, name).equals(d) : descriptorFor(stubClass, name) + " != " + d;
+        return d;
+    }
 
     /**
      * Looks for a {@link StubForeignCallNode} node intrinsic named {@code name} in
      * {@code stubClass} and returns a {@link ForeignCallDescriptor} based on its signature and the
      * value of {@code hasSideEffect}.
      */
-    public static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) {
+    private static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) {
         Method found = null;
         for (Method method : stubClass.getDeclaredMethods()) {
             if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) {
@@ -78,7 +83,7 @@
             if (isObjectResult) {
                 getAndClearObjectResult(thread);
             }
-            DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+            DeoptimizeCallerNode.deopt(DeoptimizationAction.None, RuntimeConstraint);
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.stubs.StubUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Uncommon trap stub.
+ *
+ * This is the entry point for code which is returning to a de-optimized frame.
+ *
+ * The steps taken by this frame are as follows:
+ *
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
+ *
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
+ * deoptimized)
+ *
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * be captured in the vframeArray as needed.
+ *
+ * <li>deallocate the deoptimization frame
+ *
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
+ *
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ *
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * interpreter frame which was just created)
+ *
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
+ *
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
+ */
+public class UncommonTrapStub extends SnippetStub {
+
+    private final TargetDescription target;
+
+    public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(UncommonTrapStub.class, "uncommonTrapHandler", providers, target, linkage);
+        this.target = target;
+    }
+
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        switch (index) {
+            case 0:
+                return providers.getRegisters().getThreadRegister();
+            case 1:
+                return providers.getRegisters().getStackPointerRegister();
+            default:
+                throw GraalInternalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
+        }
+    }
+
+    /**
+     * Uncommon trap handler.
+     *
+     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
+     * routine captures the return values and returns a structure which describes the current frame
+     * size and the sizes of all replacement frames. The current frame is compiled code and may
+     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
+     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
+     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
+     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
+     * was patched.
+     */
+    @Snippet
+    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+        final Word thread = registerAsWord(threadRegister);
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+
+        final int actionAndReason = readPendingDeoptimization(thread);
+        writePendingDeoptimization(thread, -1);
+
+        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason);
+
+        // Pop all the frames we must move/replace.
+        //
+        // Frame picture (youngest to oldest)
+        // 1: self-frame
+        // 2: deoptimizing frame
+        // 3: caller of deoptimizing frame (could be compiled/interpreted).
+
+        // Pop self-frame.
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver);
+
+        // Load the initial info we should save (e.g. frame pointer).
+        final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
+
+        // Pop deoptimized frame.
+        final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset());
+        LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
+
+        /*
+         * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
+         * total size of the interpreter frames plus shadow page size. Bang one page at a time
+         * because large sizes can bang beyond yellow and red zones.
+         * 
+         * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
+         */
+        final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
+        final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages();
+        Word stackPointer = readRegister(stackPointerRegister);
+
+        for (int i = 1; i < bangPages; i++) {
+            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0);
+        }
+
+        // Load number of interpreter frames.
+        final int numberOfFrames = unrollBlock.readInt(deoptimizationUnrollBlockNumberOfFramesOffset());
+
+        // Load address of array of frame sizes.
+        final Word frameSizes = unrollBlock.readWord(deoptimizationUnrollBlockFrameSizesOffset());
+
+        // Load address of array of frame PCs.
+        final Word framePcs = unrollBlock.readWord(deoptimizationUnrollBlockFramePcsOffset());
+
+        /*
+         * Get the current stack pointer (sender's original SP) before adjustment so that we can
+         * save it in the skeletal interpreter frame.
+         */
+        Word senderSp = readRegister(stackPointerRegister);
+
+        // Adjust old interpreter frame to make space for new frame's extra Java locals.
+        final int callerAdjustment = unrollBlock.readInt(deoptimizationUnrollBlockCallerAdjustmentOffset());
+        writeRegister(stackPointerRegister, readRegister(stackPointerRegister).subtract(callerAdjustment));
+
+        for (int i = 0; i < numberOfFrames; i++) {
+            final Word frameSize = frameSizes.readWord(i * wordSize());
+            final Word framePc = framePcs.readWord(i * wordSize());
+
+            // Push an interpreter frame onto the stack.
+            PushInterpreterFrameNode.pushInterpreterFrame(frameSize, framePc, senderSp, initialInfo);
+
+            // Get the current stack pointer (sender SP) and pass it to next frame.
+            senderSp = readRegister(stackPointerRegister);
+        }
+
+        // Get final return address.
+        final Word framePc = framePcs.readWord(numberOfFrames * wordSize());
+
+        /*
+         * Enter a frame to call out to unpack frames. Since we changed the stack pointer to an
+         * unknown alignment we need to align it here before calling C++ code.
+         */
+        final Word senderFp = initialInfo;
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver);
+
+        // Pass uncommon trap mode to unpack frames.
+        final int mode = deoptimizationUnpackUncommonTrap();
+        unpackFrames(UNPACK_FRAMES, thread, mode);
+
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver);
+    }
+
+    /**
+     * Reads the value of the passed register as a Word.
+     */
+    private static Word readRegister(Register register) {
+        return registerAsWord(register, false, false);
+    }
+
+    /**
+     * Writes the value of the passed register.
+     *
+     * @param value value the register should be set to
+     */
+    private static void writeRegister(Register register, Word value) {
+        writeRegisterAsWord(register, value);
+    }
+
+    @Fold
+    private static int stackShadowPages() {
+        return config().useStackBanging ? config().stackShadowPages : 0;
+    }
+
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    private static int stackBias() {
+        return config().stackBias;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+        return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+        return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+        return config().deoptimizationUnrollBlockNumberOfFramesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFramePcsOffset() {
+        return config().deoptimizationUnrollBlockFramePcsOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+        return config().deoptimizationUnrollBlockInitialInfoOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackDeopt() {
+        return config().deoptimizationUnpackDeopt;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackUncommonTrap() {
+        return config().deoptimizationUnpackUncommonTrap;
+    }
+
+    public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(UncommonTrapStub.class, "unpackFrames", int.class, Word.class, int.class);
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Fri May 30 15:09:09 2014 +0200
@@ -47,7 +47,7 @@
 public class UnwindExceptionToCallerStub extends SnippetStub {
 
     public UnwindExceptionToCallerStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("unwindExceptionToCaller", providers, target, linkage);
     }
 
     /**
@@ -110,7 +110,8 @@
         return enabled || cAssertionsEnabled();
     }
 
-    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress");
+    public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class,
+                    Word.class);
 
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Fri May 30 15:09:09 2014 +0200
@@ -35,7 +35,7 @@
 public class VerifyOopStub extends SnippetStub {
 
     public VerifyOopStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(providers, target, linkage);
+        super("verifyOop", providers, target, linkage);
     }
 
     @Snippet
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/META-INF/services/javax.annotation.processing.Processor	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,1 @@
+com.oracle.graal.hotspotvmconfig.HotSpotVMConfigProcessor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConfigProcessor.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,417 @@
+/*
+ * 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.hotspotvmconfig;
+
+import java.io.*;
+import java.lang.annotation.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.*;
+
+import com.oracle.graal.compiler.common.*;
+
+@SupportedAnnotationTypes({"com.oracle.graal.hotspotvmconfig.HotSpotVMConstant", "com.oracle.graal.hotspotvmconfig.HotSpotVMFlag", "com.oracle.graal.hotspotvmconfig.HotSpotVMField",
+                "com.oracle.graal.hotspotvmconfig.HotSpotVMType", "com.oracle.graal.hotspotvmconfig.HotSpotVMValue"})
+public class HotSpotVMConfigProcessor extends AbstractProcessor {
+
+    public HotSpotVMConfigProcessor() {
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    /**
+     * Set to true to enable logging to a local file during annotation processing. There's no normal
+     * channel for any debug messages and debugging annotation processors requires some special
+     * setup.
+     */
+    private static final boolean DEBUG = true;
+
+    private static final String LOGFILE = new File(System.getProperty("java.io.tmpdir"), "hotspotvmconfigprocessor.log").getPath();
+
+    private static PrintWriter log;
+
+    /**
+     * Logging facility for the debugging the annotation processor.
+     */
+
+    private static synchronized PrintWriter getLog() {
+        if (log == null) {
+            try {
+                log = new PrintWriter(new FileWriter(LOGFILE, true));
+            } catch (IOException e) {
+                // Do nothing
+            }
+        }
+        return log;
+    }
+
+    private static synchronized void logMessage(String format, Object... args) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            bw.printf(format, args);
+            bw.flush();
+        }
+    }
+
+    private static synchronized void logException(Throwable t) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            t.printStackTrace(bw);
+            bw.flush();
+        }
+    }
+
+    /**
+     * Bugs in an annotation processor can cause silent failure so try to report any exception
+     * throws as errors.
+     */
+    private void reportExceptionThrow(Element element, Throwable t) {
+        if (element != null) {
+            logMessage("throw for %s:\n", element);
+        }
+        logException(t);
+        processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 8)), element);
+    }
+
+    //@formatter:off
+    String[] prologue = new String[]{
+        "// The normal wrappers CommandLineFlags::boolAt and CommandLineFlags::intxAt skip constant flags",
+        "static bool boolAt(char* name, bool* value) {",
+        "  Flag* result = Flag::find_flag(name, strlen(name), true, true);",
+        "  if (result == NULL) return false;",
+        "  if (!result->is_bool()) return false;",
+        "  *value = result->get_bool();",
+        "  return true;",
+        "}",
+        "",
+        "static bool intxAt(char* name, intx* value) {",
+        "  Flag* result = Flag::find_flag(name, strlen(name), true, true);",
+        "  if (result == NULL) return false;",
+        "  if (!result->is_intx()) return false;",
+        "  *value = result->get_intx();",
+        "  return true;",
+        "}",
+        "",
+        "#define set_boolean(name, value) vmconfig_oop->bool_field_put(fs.offset(), value)",
+        "#define set_int(name, value) vmconfig_oop->int_field_put(fs.offset(), (int)value)",
+        "#define set_long(name, value) vmconfig_oop->long_field_put(fs.offset(), value)",
+        "#define set_address(name, value) do { set_long(name, (jlong) value); } while (0)",
+        "",
+        "#define set_optional_boolean_flag(varName, flagName) do { bool flagValue; if (boolAt((char*) flagName, &flagValue)) { set_boolean(varName, flagValue); } } while (0)",
+        "#define set_optional_int_flag(varName, flagName) do { intx flagValue; if (intxAt((char*) flagName, &flagValue)) { set_int(varName, flagValue); } } while (0)",
+        "#define set_optional_long_flag(varName, flagName) do { intx flagValue; if (intxAt((char*) flagName, &flagValue)) { set_long(varName, flagValue); } } while (0)",
+        "",
+        "void VMStructs::initHotSpotVMConfig(oop vmconfig_oop) {",
+        "  InstanceKlass* vmconfig_klass = InstanceKlass::cast(vmconfig_oop->klass());",
+        "",
+        "  for (JavaFieldStream fs(vmconfig_klass); !fs.done(); fs.next()) {",
+    };
+    //@formatter:on
+
+    String outputName = "HotSpotVMConfig.inline.hpp";
+    String outputDirectory = "hotspot";
+
+    private void createFiles(Map<String, VMConfigField> annotations, Element element) {
+
+        Filer filer = processingEnv.getFiler();
+        try (PrintWriter out = createSourceFile(outputDirectory, outputName, filer, element)) {
+
+            for (String line : prologue) {
+                out.println(line);
+            }
+
+            out.println();
+
+            Set<String> fieldTypes = new HashSet<>();
+            for (VMConfigField key : annotations.values()) {
+                fieldTypes.add(key.getType());
+            }
+            // For each type of field, generate a switch on the length of the symbol and then do a
+            // direct compare. In general this reduces each operation to 2 tests plus a string
+            // compare. Being more perfect than that is probably not worth it.
+            for (String type : fieldTypes) {
+                String sigtype = type.equals("boolean") ? "bool" : type;
+                out.println("    if (fs.signature() == vmSymbols::" + sigtype + "_signature()) {");
+                Set<Integer> lengths = new HashSet<>();
+                for (Entry<String, VMConfigField> entry : annotations.entrySet()) {
+                    if (entry.getValue().getType().equals(type)) {
+                        lengths.add(entry.getKey().length());
+                    }
+                }
+                out.println("      switch (fs.name()->utf8_length()) {");
+                for (int len : lengths) {
+                    out.println("        case " + len + ":");
+                    for (Entry<String, VMConfigField> entry : annotations.entrySet()) {
+                        if (entry.getValue().getType().equals(type) && entry.getKey().length() == len) {
+                            out.println("          if (fs.name()->equals(\"" + entry.getKey() + "\")) {");
+                            entry.getValue().emit(out);
+                            out.println("            continue;");
+                            out.println("          }");
+                        }
+                    }
+                    out.println("          continue;");
+                }
+                out.println("      } // switch");
+                out.println("      continue;");
+                out.println("    } // if");
+            }
+            out.println("  } // for");
+            out.println("}");
+        }
+    }
+
+    protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+        try {
+            // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle
+            FileObject sourceFile = filer.createResource(StandardLocation.SOURCE_OUTPUT, pkg, relativeName, originatingElements);
+            logMessage("%s\n", sourceFile);
+            return new PrintWriter(sourceFile.openWriter()) {
+
+                @Override
+                public void println() {
+                    print("\n");
+                }
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    class VMConfigField {
+        final VariableElement field;
+        final Annotation annotation;
+
+        public VMConfigField(VariableElement field, Annotation value) {
+            super();
+            this.field = field;
+            this.annotation = value;
+        }
+
+        public String getType() {
+            return field.asType().toString();
+        }
+
+        private String archDefine(String arch) {
+            switch (arch) {
+                case "amd64":
+                    return "defined(AMD64)";
+                case "sparcv9":
+                    return "(defined(SPARC) && defined(_LP64))";
+                case "sparc":
+                    return "defined(SPARC)";
+                default:
+                    throw new GraalInternalError("unexpected arch: " + arch);
+            }
+        }
+
+        private String archDefines(String[] archs) {
+            if (archs.length == 0) {
+                return null;
+            }
+            if (archs.length == 1) {
+                return archDefine(archs[0]);
+            }
+            String[] defs = new String[archs.length];
+            int i = 0;
+            for (String arch : archs) {
+                defs[i++] = archDefine(arch);
+            }
+            return String.join(" ||", defs);
+        }
+
+        public void emit(PrintWriter out) {
+            if (annotation instanceof HotSpotVMField) {
+                emitField(out, (HotSpotVMField) annotation);
+            } else if (annotation instanceof HotSpotVMType) {
+                emitType(out, (HotSpotVMType) annotation);
+            } else if (annotation instanceof HotSpotVMFlag) {
+                emitFlag(out, (HotSpotVMFlag) annotation);
+            } else if (annotation instanceof HotSpotVMConstant) {
+                emitConstant(out, (HotSpotVMConstant) annotation);
+            } else if (annotation instanceof HotSpotVMValue) {
+                emitValue(out, (HotSpotVMValue) annotation);
+            } else {
+                throw new InternalError(annotation.toString());
+            }
+
+        }
+
+        private void emitField(PrintWriter out, HotSpotVMField value) {
+            String type = field.asType().toString();
+            String define = archDefines(value.archs());
+            if (define != null) {
+                out.printf("#if %s\n", define);
+            }
+
+            String name = value.name();
+            int i = name.lastIndexOf("::");
+            switch (value.get()) {
+                case OFFSET:
+                    out.printf("            set_%s(\"%s\", offset_of(%s, %s));\n", type, field.getSimpleName(), name.substring(0, i), name.substring(i + 2));
+                    break;
+                case ADDRESS:
+                    out.printf("            set_address(\"%s\", &%s);\n", field.getSimpleName(), name);
+                    break;
+                case VALUE:
+                    out.printf("            set_%s(\"%s\", (%s) (intptr_t) %s);\n", type, field.getSimpleName(), type, name);
+                    break;
+            }
+            if (define != null) {
+                out.printf("#endif\n");
+            }
+        }
+
+        private void emitType(PrintWriter out, HotSpotVMType value) {
+            String type = field.asType().toString();
+            out.printf("            set_%s(\"%s\", sizeof(%s));\n", type, field.getSimpleName(), value.name());
+        }
+
+        private void emitValue(PrintWriter out, HotSpotVMValue value) {
+            String type = field.asType().toString();
+            int length = value.defines().length;
+            if (length != 0) {
+                out.printf("#if ");
+                for (int i = 0; i < length; i++) {
+                    out.printf("defined(%s)", value.defines()[i]);
+                    if (i + 1 < length) {
+                        out.printf(" || ");
+                    }
+                }
+                out.println();
+            }
+            if (value.get() == HotSpotVMValue.Type.ADDRESS) {
+                out.printf("            set_address(\"%s\", %s);\n", field.getSimpleName(), value.expression());
+            } else {
+                out.printf("            set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.expression());
+            }
+            if (length != 0) {
+                out.println("#endif");
+            }
+        }
+
+        private void emitConstant(PrintWriter out, HotSpotVMConstant value) {
+            String define = archDefines(value.archs());
+            if (define != null) {
+                out.printf("#if %s\n", define);
+            }
+            String type = field.asType().toString();
+            out.printf("            set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.name());
+            if (define != null) {
+                out.printf("#endif\n");
+            }
+        }
+
+        private void emitFlag(PrintWriter out, HotSpotVMFlag value) {
+            String type = field.asType().toString();
+
+            String define = archDefines(value.archs());
+            if (define != null) {
+                out.printf("#if %s\n", define);
+            }
+            if (value.optional()) {
+                out.printf("            set_optional_%s_flag(\"%s\",  \"%s\");\n", type, field.getSimpleName(), value.name());
+            } else {
+                out.printf("            set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.name());
+            }
+            if (define != null) {
+                out.printf("#endif\n");
+            }
+        }
+
+    }
+
+    private void collectAnnotations(RoundEnvironment roundEnv, Map<String, VMConfigField> annotationMap, Class<? extends Annotation> annotationClass) {
+        for (Element element : roundEnv.getElementsAnnotatedWith(annotationClass)) {
+            Annotation constant = element.getAnnotation(annotationClass);
+            if (element.getKind() != ElementKind.FIELD) {
+                errorMessage(element, "%s annotations may only be on fields", annotationClass.getSimpleName());
+            }
+            if (annotationClass == HotSpotVMValue.class) {
+                HotSpotVMValue value = (HotSpotVMValue) constant;
+                if (value.get() == HotSpotVMValue.Type.ADDRESS && !element.asType().toString().equals("long")) {
+                    errorMessage(element, "HotSpotVMValue with get == ADDRESS must be of type long, but found %s", element.asType());
+                }
+            }
+            if (currentTypeElement == null) {
+                currentTypeElement = element.getEnclosingElement();
+            } else {
+                if (!currentTypeElement.equals(element.getEnclosingElement())) {
+                    errorMessage(element, "Multiple types encountered.  Only HotSpotVMConfig is supported");
+                }
+            }
+            annotationMap.put(element.getSimpleName().toString(), new VMConfigField((VariableElement) element, constant));
+        }
+    }
+
+    private void errorMessage(Element element, String format, Object... args) {
+        processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element);
+    }
+
+    Element currentTypeElement = null;
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+        logMessage("Starting round %s %s\n", roundEnv, annotations);
+        try {
+
+            currentTypeElement = null;
+
+            // First collect all the annotations.
+            Map<String, VMConfigField> annotationMap = new HashMap<>();
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMConstant.class);
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMFlag.class);
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMField.class);
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMType.class);
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMValue.class);
+
+            if (annotationMap.isEmpty()) {
+                return true;
+            }
+
+            logMessage("type element %s\n", currentTypeElement);
+            createFiles(annotationMap, currentTypeElement);
+
+        } catch (Throwable t) {
+            reportExceptionThrow(null, t);
+        }
+
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConstant.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Refers to a C++ constant in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMConstant {
+
+    /**
+     * Returns the name of the constant.
+     *
+     * @return name of constant
+     */
+    String name();
+
+    /**
+     * List of architectures where this constant is required. Names are derived from
+     * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
+     * required on all architectures.
+     */
+    @SuppressWarnings("javadoc")
+    String[] archs() default {};
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMField.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,85 @@
+/*
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Refers to a C++ field in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMField {
+
+    /**
+     * Types of information this annotation can return.
+     */
+    enum Type {
+        /**
+         * Returns the offset of this field within the type. Only valid for instance fields.
+         */
+        OFFSET,
+
+        /**
+         * Returns the absolute address of this field. Only valid for static fields.
+         */
+        ADDRESS,
+
+        /**
+         * Returns the value of this field. Only valid for static fields.
+         */
+        VALUE;
+    }
+
+    /**
+     * Specifies what type of information to return.
+     *
+     * @see Type
+     */
+    Type get();
+
+    /**
+     * Returns the type name containing this field.
+     *
+     * @return name of containing type
+     */
+    String type();
+
+    /**
+     * Returns the name of this field.
+     *
+     * @return name of field
+     */
+    String name();
+
+    /**
+     * List of architectures where this constant is required. Names are derived from
+     * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
+     * required on all architectures.
+     */
+    @SuppressWarnings("javadoc")
+    String[] archs() default {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMFlag.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,53 @@
+/*
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Refers to a C++ flag in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMFlag {
+
+    /**
+     * Returns the name of this flag.
+     *
+     * @return name of flag.
+     */
+    String name();
+
+    /**
+     * List of architectures where this constant is required. Names are derived from
+     * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is
+     * required on all architectures.
+     */
+    @SuppressWarnings("javadoc")
+    String[] archs() default {};
+
+    boolean optional() default false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMType.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,57 @@
+/*
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.*;
+
+/**
+ * Refers to a C++ type in the VM.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMType {
+
+    /**
+     * Types of information this annotation can return.
+     */
+    enum Type {
+        /**
+         * Returns the size of the type (C++ {@code sizeof()}).
+         */
+        SIZE;
+    }
+
+    /**
+     * Specifies what type of information to return.
+     *
+     * @see Type
+     */
+    Type get();
+
+    /**
+     * Returns the name of the type.
+     *
+     * @return name of type
+     */
+    String name();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMValue.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.hotspotvmconfig;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HotSpotVMValue {
+
+    /**
+     * A C++ expression to be evaluated and assigned to the field.
+     */
+    String expression();
+
+    enum Type {
+        /**
+         * A C++ address which might require extra casts to be safely assigned to a Java field.
+         */
+        ADDRESS,
+
+        /**
+         * A simple value which can be assigned to a regular Java field.
+         */
+        VALUE
+    }
+
+    Type get() default Type.VALUE;
+
+    /**
+     * List of preprocessor symbols that should guard initialization of this value.
+     */
+    String[] defines() default {};
+
+}
--- a/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java	Fri May 30 15:09:09 2014 +0200
@@ -136,7 +136,6 @@
     public static final Register threadRegister = d20;
     public static final Register actionAndReasonReg = s32;
     public static final Register codeBufferOffsetReg = s33;
-    public static final Register dregOopMapReg = s39;
 
     // @formatter:off
     public static final Register[] cRegisters = {
@@ -160,9 +159,12 @@
 
     public static final Register[] allRegisters = {
         c0, c1, c2, c3, c4, c5, c6, c7, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15,
+        s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30, s31,
         d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13,
         d14, d15, q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11,
-        q12, q13, q14, q15, threadRegister
+        q12, q13, q14, q15,
+        s32, s33, s34, s35, s36, s37, s38, s39,
+        d16, d17, d18, d19, threadRegister
     };
 
     // @formatter:on
@@ -175,10 +177,16 @@
         return -(((StackSlot) reg).getRawOffset());
     }
 
-    public static String mapStackSlot(Value reg) {
-        StackSlot s = (StackSlot) reg;
-        long offset = -s.getRawOffset();
-        return "[%spillseg]" + "[" + offset + "]";
+    /**
+     * The mapping to stack slots is always relative to the beginning of the spillseg.
+     * {@link #getStackOffset(Value)} returns the positive version of the originally negative
+     * offset. Then we back up from that by {@code argSize} in bytes. This ensures that slots of
+     * different size do not overlap, even though we have converted from negative to positive
+     * offsets.
+     */
+    public static int getStackOffsetStart(Value reg, int argSize) {
+        int argSizeInBytes = argSize / 8;
+        return getStackOffset(reg) - argSizeInBytes;
     }
 
     public static String mapRegister(Value arg) {
--- a/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/Decompiler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/Decompiler.java	Fri May 30 15:09:09 2014 +0200
@@ -68,8 +68,8 @@
             cfgBlocks.add(b);
         }
 
-        for (int i = 0; i < getCfg().getBlocks().length - 1; i++) {
-            if (cfg.getBlocks()[i].getId() >= cfg.getBlocks()[i + 1].getId()) {
+        for (int i = 0; i < getCfg().getBlocks().size() - 1; i++) {
+            if (cfg.getBlocks().get(i).getId() >= cfg.getBlocks().get(i + 1).getId()) {
                 throw new AssertionError();
             }
         }
--- a/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java	Fri May 30 15:09:09 2014 +0200
@@ -50,18 +50,18 @@
                 Loop<Block> loop = firstBlock.getLoop();
 
                 for (int i = 0; i < cfgBlocks.size(); i++) {
-                    if (loop.blocks.contains(cfgBlocks.get(i)) && cfgBlocks.get(i) != firstBlock) {
+                    if (loop.getBlocks().contains(cfgBlocks.get(i)) && cfgBlocks.get(i) != firstBlock) {
                         loopBlock.addBodyBlock(cfgBlocks.get(i));
                     }
                 }
 
                 // Asserting:
                 for (Block b : loopBlock.getBody()) {
-                    if (!loop.blocks.contains(b)) {
+                    if (!loop.getBlocks().contains(b)) {
                         throw new AssertionError();
                     }
                 }
-                for (Block b : loop.blocks) {
+                for (Block b : loop.getBlocks()) {
                     if (b != firstBlock && !loopBlock.getBody().contains(b)) {
                         throw new AssertionError();
                     }
--- a/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerLoopBlock.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerLoopBlock.java	Fri May 30 15:09:09 2014 +0200
@@ -82,7 +82,7 @@
 
     @Override
     public int getSuccessorCount() {
-        return block.getLoop().exits.size();
+        return block.getLoop().getExits().size();
     }
 
     @Override
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Fri May 30 15:09:09 2014 +0200
@@ -25,8 +25,6 @@
 
 import static com.oracle.graal.api.code.TypeCheckHints.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -39,7 +37,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
@@ -327,7 +324,7 @@
     private void genArithmeticOp(Kind result, int opcode) {
         T y = frameState.pop(result);
         T x = frameState.pop(result);
-        boolean isStrictFP = isStrict(method.getModifiers());
+        boolean isStrictFP = method.isStrict();
         T v;
         switch (opcode) {
             case IADD:
@@ -586,7 +583,7 @@
         }
     }
 
-    protected abstract T genCheckCast(ResolvedJavaType type, T object, JavaTypeProfile profileForTypeCheck, boolean b);
+    protected abstract T createCheckCast(ResolvedJavaType type, T object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck);
 
     private void genCheckCast() {
         int cpi = getStream().readCPI();
@@ -594,14 +591,14 @@
         T object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
             JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type);
-            T checkCastNode = append(genCheckCast((ResolvedJavaType) type, object, profileForTypeCheck, false));
+            T checkCastNode = append(createCheckCast((ResolvedJavaType) type, object, profileForTypeCheck, false));
             frameState.apush(checkCastNode);
         } else {
             handleUnresolvedCheckCast(type, object);
         }
     }
 
-    protected abstract T genInstanceOf(ResolvedJavaType type, T object, JavaTypeProfile profileForTypeCheck);
+    protected abstract T createInstanceOf(ResolvedJavaType type, T object, JavaTypeProfile profileForTypeCheck);
 
     protected abstract T genConditional(T x);
 
@@ -611,7 +608,7 @@
         T object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
             ResolvedJavaType resolvedType = (ResolvedJavaType) type;
-            T instanceOfNode = genInstanceOf((ResolvedJavaType) type, object, getProfileForTypeCheck(resolvedType));
+            T instanceOfNode = createInstanceOf((ResolvedJavaType) type, object, getProfileForTypeCheck(resolvedType));
             frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
         } else {
             handleUnresolvedInstanceOf(type, object);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -69,6 +69,12 @@
     public abstract boolean isCompatibleWith(S other);
 
     public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
+        /*
+         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
+         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
+         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
+         * Kind.Illegal, because the conflicting branch might not have been parsed.
+         */
         if (liveness == null) {
             return;
         }
@@ -118,6 +124,13 @@
     }
 
     /**
+     * @return the current lock depth
+     */
+    public int lockDepth() {
+        return lockedObjects.length;
+    }
+
+    /**
      * Gets the value in the local variables at the specified index, without any sanity checking.
      *
      * @param i the index into the locals
@@ -138,6 +151,20 @@
     }
 
     /**
+     * Gets the value in the lock at the specified index, without any sanity checking.
+     *
+     * @param i the index into the lock
+     * @return the instruction that produced the value for the specified lock
+     */
+    public T lockAt(int i) {
+        return lockedObjects[i];
+    }
+
+    public void storeLock(int i, T lock) {
+        lockedObjects[i] = lock;
+    }
+
+    /**
      * Loads the local variable at the specified index, checking that the returned value is non-null
      * and that two-stack values are properly handled.
      *
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.java;
 
 import static com.oracle.graal.bytecode.Bytecodes.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
@@ -154,6 +154,10 @@
             return loop;
         }
 
+        public void setLoop(Loop<BciBlock> loop) {
+            this.loop = loop;
+        }
+
         public int getLoopDepth() {
             return Long.bitCount(loops);
         }
@@ -177,6 +181,71 @@
         public BciBlock getPredecessor(int index) {
             return predecessors.get(index);
         }
+
+        /**
+         * Get the loop id of the inner most loop.
+         *
+         * @return the loop id of the most inner loop or -1 if not part of any loop
+         */
+        public int getLoopId() {
+            long l = loops;
+            if (l == 0) {
+                return -1;
+            }
+            int pos = 0;
+            for (int lMask = 1; (l & lMask) == 0; lMask = lMask << 1) {
+                pos++;
+            }
+            return pos;
+        }
+
+        /**
+         * Iterate over loop ids.
+         */
+        public Iterable<Integer> loopIdIterable() {
+            return new Iterable<Integer>() {
+                public Iterator<Integer> iterator() {
+                    return idIterator(loops);
+                }
+            };
+        }
+
+        /**
+         * Iterate over exit ids.
+         */
+        public Iterable<Integer> exitIdIterable() {
+            return new Iterable<Integer>() {
+                public Iterator<Integer> iterator() {
+                    return idIterator(exits);
+                }
+            };
+        }
+
+        private static Iterator<Integer> idIterator(long field) {
+            return new Iterator<Integer>() {
+
+                long l = field;
+                int pos = 0;
+                int lMask = 1;
+
+                public Integer next() {
+                    for (; (l & lMask) == 0; lMask = lMask << 1) {
+                        pos++;
+                    }
+                    l &= ~lMask;
+                    return pos;
+                }
+
+                public boolean hasNext() {
+                    return l != 0;
+                }
+            };
+
+        }
+
+        public double probability() {
+            return 1D;
+        }
     }
 
     public static class ExceptionDispatchBlock extends BciBlock {
@@ -211,9 +280,10 @@
         this.method = method;
         exceptionHandlers = method.getExceptionHandlers();
         stream = new BytecodeStream(method.getCode());
-        this.blockMap = new BciBlock[method.getCodeSize()];
+        int codeSize = method.getCodeSize();
+        this.blockMap = new BciBlock[codeSize];
         this.blocks = new ArrayList<>();
-        this.loopHeaders = new BciBlock[64];
+        this.loopHeaders = new BciBlock[codeSize < 64 ? codeSize : 64];
     }
 
     /**
@@ -627,26 +697,12 @@
                     sb.append(" ");
                 }
                 sb.append(n).append("  Loop : ");
-                long l = b.loops;
-                int pos = 0;
-                while (l != 0) {
-                    int lMask = 1 << pos;
-                    if ((l & lMask) != 0) {
-                        sb.append("B").append(loopHeaders[pos].getId()).append(" ");
-                        l &= ~lMask;
-                    }
-                    pos++;
+                for (int pos : b.loopIdIterable()) {
+                    sb.append("B").append(loopHeaders[pos].getId()).append(" ");
                 }
                 sb.append(n).append("  Exits : ");
-                l = b.exits;
-                pos = 0;
-                while (l != 0) {
-                    int lMask = 1 << pos;
-                    if ((l & lMask) != 0) {
-                        sb.append("B").append(loopHeaders[pos].getId()).append(" ");
-                        l &= ~lMask;
-                    }
-                    pos++;
+                for (int pos : b.exitIdIterable()) {
+                    sb.append("B").append(loopHeaders[pos].getId()).append(" ");
                 }
                 sb.append(n);
             }
@@ -655,6 +711,13 @@
     }
 
     /**
+     * Get the header block for a loop index.
+     */
+    public BciBlock getLoopHeader(int index) {
+        return loopHeaders[index];
+    }
+
+    /**
      * The next available loop number.
      */
     private int nextLoop;
@@ -718,7 +781,7 @@
         for (BciBlock successor : block.getSuccessors()) {
             // Recursively process successors.
             loops |= computeBlockOrder(successor);
-            if (block.visited && successor.active) {
+            if (successor.active) {
                 // Reached block via backward branch.
                 block.isLoopEnd = true;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,101 @@
+/*
+ * 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.java;
+
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.graph.*;
+
+public class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure<Double> {
+
+    private static final double EPSILON = Double.MIN_NORMAL;
+    private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure();
+
+    private ComputeLoopFrequenciesClosure() {
+        // nothing to do
+    }
+
+    @Override
+    protected Double processNode(FixedNode node, Double currentState) {
+        // normal nodes never change the probability of a path
+        return currentState;
+    }
+
+    @Override
+    protected Double merge(MergeNode merge, List<Double> states) {
+        // a merge has the sum of all predecessor probabilities
+        return states.stream().collect(Collectors.summingDouble(d -> d));
+    }
+
+    @Override
+    protected Double afterSplit(BeginNode node, Double oldState) {
+        // a control split splits up the probability
+        ControlSplitNode split = (ControlSplitNode) node.predecessor();
+        return oldState * split.probability(node);
+    }
+
+    @Override
+    protected Map<LoopExitNode, Double> processLoop(LoopBeginNode loop, Double initialState) {
+        Map<LoopExitNode, Double> exitStates = ReentrantNodeIterator.processLoop(this, loop, 1D).exitStates;
+
+        double exitProbability = exitStates.values().stream().mapToDouble(d -> d).sum();
+        assert exitProbability <= 1D && exitProbability >= 0D;
+        if (exitProbability < EPSILON) {
+            exitProbability = EPSILON;
+        }
+        double loopFrequency = 1D / exitProbability;
+        loop.setLoopFrequency(loopFrequency);
+
+        double adjustmentFactor = initialState * loopFrequency;
+        exitStates.replaceAll((exitNode, probability) -> multiplySaturate(probability, adjustmentFactor));
+
+        return exitStates;
+    }
+
+    /**
+     * Multiplies a and b and saturates the result to 1/{@link Double#MIN_NORMAL}.
+     *
+     * @return a times b saturated to 1/{@link Double#MIN_NORMAL}
+     */
+    public static double multiplySaturate(double a, double b) {
+        double r = a * b;
+        if (r > 1 / Double.MIN_NORMAL) {
+            return 1 / Double.MIN_NORMAL;
+        }
+        return r;
+    }
+
+    /**
+     * Computes the frequencies of all loops in the given graph. This is done by performing a
+     * reverse postorder iteration and computing the probability of all fixed nodes. The combined
+     * probability of all exits of a loop can be used to compute the loop's expected frequency.
+     */
+    public static void compute(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            ReentrantNodeIterator.apply(INSTANCE, graph.start(), 1D);
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -25,10 +25,8 @@
 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 static com.oracle.graal.compiler.common.GraalOptions.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -38,6 +36,7 @@
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
@@ -46,7 +45,6 @@
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
@@ -152,7 +150,7 @@
             methodSynchronizedObject = null;
             this.currentGraph = graph;
             HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, graphBuilderConfig.eagerResolving());
-            this.parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, new BytecodeStream(method.getCode()), profilingInfo, method.getConstantPool(),
+            this.parser = createBytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, new BytecodeStream(method.getCode()), profilingInfo, method.getConstantPool(),
                             entryBCI);
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
@@ -161,6 +159,14 @@
                 filter.remove();
             }
             parser = null;
+
+            ComputeLoopFrequenciesClosure.compute(graph);
+        }
+
+        @SuppressWarnings("hiding")
+        protected BytecodeParser createBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
+                        HIRFrameStateBuilder frameState, BytecodeStream stream, ProfilingInfo profilingInfo, ConstantPool constantPool, int entryBCI) {
+            return new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, stream, profilingInfo, constantPool, entryBCI);
         }
 
         @Override
@@ -190,7 +196,7 @@
             }
         }
 
-        class BytecodeParser extends AbstractBytecodeParser<ValueNode, HIRFrameStateBuilder> {
+        public class BytecodeParser extends AbstractBytecodeParser<ValueNode, HIRFrameStateBuilder> {
 
             private BciBlock[] loopHeaders;
             private LocalLiveness liveness;
@@ -219,9 +225,9 @@
                     liveness = blockMap.liveness;
 
                     lastInstr = currentGraph.start();
-                    if (isSynchronized(method.getModifiers())) {
+                    if (method.isSynchronized()) {
                         // add a monitor enter to the start block
-                        currentGraph.start().setStateAfter(frameState.create(FrameState.BEFORE_BCI));
+                        currentGraph.start().setStateAfter(frameState.create(BytecodeFrame.BEFORE_BCI));
                         methodSynchronizedObject = synchronizedObject(frameState, method);
                         lastInstr = genMonitorEnter(methodSynchronizedObject);
                     }
@@ -289,7 +295,7 @@
                     unwindBlock = new ExceptionDispatchBlock();
                     unwindBlock.startBci = -1;
                     unwindBlock.endBci = -1;
-                    unwindBlock.deoptBci = FrameState.UNWIND_BCI;
+                    unwindBlock.deoptBci = method.isSynchronized() ? BytecodeFrame.UNWIND_BCI : BytecodeFrame.AFTER_EXCEPTION_BCI;
                     unwindBlock.setId(Integer.MAX_VALUE);
                 }
                 return unwindBlock;
@@ -409,7 +415,7 @@
             }
 
             private DispatchBeginNode handleException(ValueNode exceptionObject, int bci) {
-                assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci";
+                assert bci == BytecodeFrame.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));
 
                 BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock();
@@ -433,12 +439,13 @@
                     dispatchBegin.setStateAfter(dispatchState.create(bci));
                 } else {
                     dispatchBegin = currentGraph.add(new DispatchBeginNode());
+                    dispatchState.apush(exceptionObject);
                     dispatchBegin.setStateAfter(dispatchState.create(bci));
-                    dispatchState.apush(exceptionObject);
                     dispatchState.setRethrowException(true);
                 }
+                FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState);
                 FixedNode target = createTarget(dispatchBlock, dispatchState);
-                finishInstruction(dispatchBegin, dispatchState).setNext(target);
+                finishedDispatch.setNext(target);
                 return dispatchBegin;
             }
 
@@ -600,12 +607,12 @@
             }
 
             @Override
-            protected ValueNode genCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean b) {
-                return new CheckCastNode(type, object, profileForTypeCheck, b);
+            protected ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck) {
+                return new CheckCastNode(type, object, profileForTypeCheck, forStoreCheck);
             }
 
             @Override
-            protected ValueNode genInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck) {
+            protected ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck) {
                 return new InstanceOfNode(type, object, profileForTypeCheck);
             }
 
@@ -636,7 +643,7 @@
 
             @Override
             protected void emitNullCheck(ValueNode receiver) {
-                if (ObjectStamp.isObjectNonNull(receiver.stamp())) {
+                if (StampTool.isObjectNonNull(receiver.stamp())) {
                     return;
                 }
                 BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode(this));
@@ -723,7 +730,7 @@
                      * https://wikis.oracle.com/display/HotSpotInternals/Method+handles
                      * +and+invokedynamic
                      */
-                    boolean hasReceiver = !isStatic(((ResolvedJavaMethod) target).getModifiers());
+                    boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic();
                     Constant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL);
                     if (appendix != null) {
                         frameState.apush(ConstantNode.forConstant(appendix, metaAccess, currentGraph));
@@ -816,7 +823,7 @@
                     append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci())));
                 }
 
-                synchronizedEpilogue(FrameState.AFTER_BCI, x);
+                synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x);
                 if (frameState.lockDepth() != 0) {
                     throw new BailoutException("unbalanced monitors");
                 }
@@ -1089,7 +1096,7 @@
             }
 
             private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) {
-                if (isStatic(target.getModifiers())) {
+                if (target.isStatic()) {
                     return appendConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass));
                 } else {
                     return state.loadLocal(0);
@@ -1155,13 +1162,12 @@
             private void createUnwind() {
                 assert frameState.stackSize() == 1 : frameState;
                 ValueNode exception = frameState.apop();
-                append(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
-                synchronizedEpilogue(FrameState.AFTER_EXCEPTION_BCI, null);
+                synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null);
                 append(new UnwindNode(exception));
             }
 
             private void synchronizedEpilogue(int bci, ValueNode returnValue) {
-                if (Modifier.isSynchronized(method.getModifiers())) {
+                if (method.isSynchronized()) {
                     MonitorExitNode monitorExit = genMonitorExit(methodSynchronizedObject, returnValue);
                     if (returnValue != null) {
                         frameState.push(returnValue.getKind(), returnValue);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,6 @@
 package com.oracle.graal.java;
 
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -35,7 +33,6 @@
 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, HIRFrameStateBuilder> {
@@ -56,7 +53,7 @@
 
         int javaIndex = 0;
         int index = 0;
-        if (!isStatic(method.getModifiers())) {
+        if (!method.isStatic()) {
             // add the receiver
             ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass())));
             storeLocal(javaIndex, receiver);
@@ -329,6 +326,7 @@
         } finally {
             lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
             monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
+            assert lockedObjects.length == monitorIds.length;
         }
     }
 
@@ -339,6 +337,7 @@
     /**
      * @return the current lock depth
      */
+    @Override
     public int lockDepth() {
         assert lockedObjects.length == monitorIds.length;
         return lockedObjects.length;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,6 @@
 package com.oracle.graal.java;
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
-import static java.lang.reflect.Modifier.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -115,9 +113,9 @@
             if (node instanceof StoreFieldNode) {
                 ResolvedJavaField field = ((StoreFieldNode) node).field();
                 verify(field.getDeclaringClass().equals(declaringClass), node, "store to field " + format("%H.%n", field));
-                verify(isStatic(field.getModifiers()), node, "store to field " + format("%H.%n", field));
+                verify(field.isStatic(), node, "store to field " + format("%H.%n", field));
                 if (optionValueType.isAssignableFrom((ResolvedJavaType) field.getType())) {
-                    verify(isFinal(field.getModifiers()), node, "option field " + format("%H.%n", field) + " not final");
+                    verify(field.isFinal(), node, "option field " + format("%H.%n", field) + " not final");
                 } else {
                     verify((field.isSynthetic()), node, "store to non-synthetic field " + format("%H.%n", field));
                 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Fri May 30 15:09:09 2014 +0200
@@ -80,11 +80,11 @@
     Double delta;
 
     @Override
-    protected void assertEquals(Object expected, Object actual) {
+    protected void assertDeepEquals(Object expected, Object actual) {
         if (delta != null) {
             Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta);
         } else {
-            super.assertEquals(expected, actual);
+            super.assertDeepEquals(expected, actual);
         }
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_arraylength.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_arraylength.java	Fri May 30 15:09:09 2014 +0200
@@ -30,50 +30,95 @@
  */
 public class BC_arraylength extends JTTTest {
 
-    static int[] array1 = {1, 2, 3};
-    static char[] array2 = {'a', 'b', 'c', 'd'};
-    static Object[] array3 = new Object[5];
-    static Object[][] array4 = new Object[5][5];
+    static byte[] array0 = {1, 2};
+    static char[] array1 = {'a', 'b', 'c', 'd'};
+    static short[] array2 = {1, 2, 3, 4, 5, 6};
+    static int[] array3 = {1, 2, 3};
+    static long[] array4 = {1L, 2L, 3L, 4L};
+    static float[] array5 = {0.1f, 0.2f};
+    static double[] array6 = {0.1, 0.2, 0.3, 0.4};
+    static Object[] array7 = new Object[5];
+    static boolean[] array8 = {false, true, false};
+
+    public static int testByte(byte[] arg) {
+        return arg.length;
+    }
+
+    public static int testChar(char[] arg) {
+        return arg.length;
+    }
+
+    public static int testShort(short[] arg) {
+        return arg.length;
+    }
 
-    public static int test(int arg) {
-        if (arg == 1) {
-            return array1.length;
-        }
-        if (arg == 2) {
-            return array2.length;
-        }
-        if (arg == 3) {
-            return array3.length;
-        }
-        if (arg == 4) {
-            return array4[0].length;
-        }
-        return 42;
+    public static int testInt(int[] arg) {
+        return arg.length;
+    }
+
+    public static int testLong(long[] arg) {
+        return arg.length;
+    }
+
+    public static int testFloat(float[] arg) {
+        return arg.length;
+    }
+
+    public static int testDouble(double[] arg) {
+        return arg.length;
+    }
+
+    public static int testObject(Object[] arg) {
+        return arg.length;
+    }
+
+    public static int testBoolean(boolean[] arg) {
+        return arg.length;
     }
 
     @Test
     public void run0() throws Throwable {
-        runTest("test", 1);
+        runTest("testByte", array0);
     }
 
     @Test
     public void run1() throws Throwable {
-        runTest("test", 2);
+        runTest("testChar", array1);
     }
 
     @Test
     public void run2() throws Throwable {
-        runTest("test", 3);
+        runTest("testShort", array2);
     }
 
     @Test
     public void run3() throws Throwable {
-        runTest("test", 4);
+        runTest("testInt", array3);
     }
 
     @Test
     public void run4() throws Throwable {
-        runTest("test", 5);
+        runTest("testLong", array4);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("testFloat", array5);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("testDouble", array6);
+    }
+
+    @Test
+    public void run7() throws Throwable {
+        runTest("testObject", new Object[]{array7});
+    }
+
+    @Test
+    public void run8() throws Throwable {
+        runTest("testBoolean", array8);
     }
 
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,9 @@
 
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,12 +62,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -49,17 +50,17 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,17 +57,17 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_InNested extends JTTTest {
 
@@ -48,12 +49,12 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized01 extends JTTTest {
 
@@ -38,12 +39,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized02 extends JTTTest {
 
@@ -36,12 +37,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized03 extends JTTTest {
 
@@ -41,12 +42,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -37,27 +38,27 @@
         return sum;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 80);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,9 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -55,12 +56,12 @@
         return (int) (b + c + s + i + l + f + d);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 40);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1000);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -104,12 +105,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 40);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 80);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java	Fri May 30 15:09:09 2014 +0200
@@ -25,8 +25,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -106,7 +107,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,9 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,7 +49,7 @@
         return sum;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 15);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_series.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_series.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,8 @@
 
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
 
 /*
@@ -104,7 +106,8 @@
      * different implementation may return different results. The 11 ulp delta allowed for test(100)
      * tries to account for that but is not guaranteed to work forever.
      */
-    // @Test
+    @Ignore("failure-prone because of the variabiliy of pow/cos/sin")
+    @Test
     public void run0() throws Throwable {
         double expected = 0.6248571921291398d;
         runTestWithDelta(11 * Math.ulp(expected), "test", 100);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotspot;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /**
  * @bug 6196102
@@ -46,7 +47,7 @@
         return "ok";
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotspot;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 //@formatter:off
 
@@ -50,7 +51,7 @@
         return 95;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6959129.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6959129.java	Fri May 30 15:09:09 2014 +0200
@@ -22,30 +22,16 @@
  */
 package com.oracle.graal.jtt.hotspot;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
 
-//@formatter:off
-
-/**
- * @test
- * @bug 6959129
- * @summary COMPARISON WITH INTEGER.MAX_INT DOES NOT WORK CORRECTLY IN THE CLIENT VM.
- *
- *          This test will not run properly without assertions
- *
- * @run main/othervm -ea Test6959129
- */
 public class Test6959129 extends JTTTest {
 
-    public static int test() {
+    public static long test() {
         int min = Integer.MAX_VALUE - 30000;
         int max = Integer.MAX_VALUE;
-        try {
-            maxMoves(min, max);
-        } catch (AssertionError e) {
-            return 95;
-        }
-        return 97;
+        return maxMoves(min, max);
     }
 
     /**
@@ -55,7 +41,9 @@
         long n = n2;
         long moves = 0;
         while (n != 1) {
-            assert n > 1;
+            if (n <= 1) {
+                throw new IllegalStateException();
+            }
             if (isEven(n)) {
                 n = n / 2;
             } else {
@@ -86,7 +74,7 @@
         return maxmoves;
     }
 
-    //@Test
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -45,17 +46,17 @@
         C
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.io.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         out.println(test(10000));
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 10000);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,11 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import sun.misc.*;
 
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -55,7 +56,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -43,22 +44,22 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_Literal01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_asSubclass01 extends JTTTest {
 
@@ -53,27 +54,27 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_cast01 extends JTTTest {
 
@@ -57,27 +58,27 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_forName01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_forName02 extends JTTTest {
 
@@ -51,27 +52,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,32 +57,32 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,32 +49,32 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -41,17 +42,17 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,43 +22,16 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
 public final class Class_getInterfaces01 extends JTTTest {
 
-    public static String test(int i) {
-        switch (i) {
-            case 0:
-                return toString(I1.class);
-            case 1:
-                return toString(I2.class);
-            case 2:
-                return toString(C1.class);
-            case 3:
-                return toString(C2.class);
-            case 4:
-                return toString(C12.class);
-            default:
-                return null;
-        }
-    }
-
-    private static String toString(Class<?> klass) {
-        final Class<?>[] classes = klass.getInterfaces();
-        final StringBuilder sb = new StringBuilder();
-        boolean first = true;
-        for (Class<?> c : classes) {
-            if (!first) {
-                sb.append(' ');
-            } else {
-                first = false;
-            }
-            sb.append(c.getName());
-        }
-        return sb.toString();
+    public static Class<?>[] test(Class<?> clazz) {
+        return clazz.getInterfaces();
     }
 
     interface I1 {
@@ -81,29 +54,28 @@
 
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
-        runTest("test", 0);
+        runTest("test", I1.class);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
-        runTest("test", 1);
+        runTest("test", I2.class);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
-        runTest("test", 2);
+        runTest("test", C1.class);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
-        runTest("test", 3);
+        runTest("test", C2.class);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
-        runTest("test", 4);
+        runTest("test", C12.class);
     }
-
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/LambdaEagerTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/LambdaEagerTest.java	Fri May 30 15:09:09 2014 +0200
@@ -29,11 +29,11 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.OptionValue.OverrideScope;
-import com.oracle.graal.phases.*;
 
 public class LambdaEagerTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Object_getClass01 extends JTTTest {
 
@@ -49,27 +50,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_toString01 extends JTTTest {
 
@@ -47,17 +48,17 @@
         return string;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,17 +34,17 @@
         return ("id" + i).intern() == ("id" + i).intern();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,17 +34,17 @@
         return ("id" + i).intern().equals("id" + i);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.loop;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class LoopParseLong extends JTTTest {
 
@@ -98,7 +99,7 @@
         return negative ? result : -result;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("testShortened", "7", 10);
         runTest("testShortened", "-100", 10);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.loop;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         return "" + ('a' + count);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,7 +34,7 @@
         return p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/FloatingReads.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/FloatingReads.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
 
 public class FloatingReads extends JTTTest {
@@ -61,22 +63,22 @@
         return a + b + c;
     }
 
-    // @Test
+    @Test
     public void run0() {
         runTest("test", 10);
     }
 
-    // @Test
+    @Test
     public void run1() {
         runTest("test", 1000);
     }
 
-    // @Test
+    @Test
     public void run2() {
         runTest("test", 1);
     }
 
-    // @Test
+    @Test
     public void run3() {
         runTest("test", 0);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -155,32 +156,32 @@
         ((Matrix[]) array)[val % array.length] = new Matrix(number);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -57,7 +58,7 @@
         return Integer.valueOf(foo(new String[]{"asdf"}));
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         Object c = b;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -117,22 +118,22 @@
         return c2 ? 1 : 0;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 10);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 20);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 40);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.io.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -44,7 +45,7 @@
         return (String) arg;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", (Object) null);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.optimize;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  * Tests value numbering of instanceof operations.
@@ -76,17 +77,17 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -37,22 +38,22 @@
         return Class_getField01.class.getField(input).getName();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "field");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "field2");
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", "field3");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -42,27 +43,27 @@
         public String field4;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "field");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "field2");
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", "field3");
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", "field4");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -39,17 +40,17 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "main");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "xx");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -52,37 +53,37 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Class_newInstance03 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,47 +60,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,47 +62,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -87,47 +88,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,47 +62,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,47 +60,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -67,47 +68,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -69,47 +70,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -69,47 +70,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,27 +57,27 @@
         return arg.length;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -44,12 +45,12 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "test2");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,12 +49,12 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "test2");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -51,22 +52,22 @@
     public void method3(int arg1, Object arg2) {
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -51,22 +52,22 @@
     public void method3() {
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Monitor_contended01 extends JTTTest implements Runnable {
 
@@ -71,7 +72,7 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Monitor_notowner01 extends JTTTest {
 
@@ -62,7 +63,7 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitorenter01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitorenter01.java	Fri May 30 15:09:09 2014 +0200
@@ -41,7 +41,7 @@
         }
     }
 
-    @Test
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitorenter02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitorenter02.java	Fri May 30 15:09:09 2014 +0200
@@ -45,7 +45,7 @@
         }
     }
 
-    @Test
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait01 extends JTTTest implements Runnable {
 
@@ -57,22 +58,22 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run3() throws Throwable {
         runTest("test", 15);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait02 extends JTTTest implements Runnable {
 
@@ -57,17 +58,17 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait03 extends JTTTest implements Runnable {
 
@@ -63,17 +64,17 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait04 extends JTTTest implements Runnable {
 
@@ -67,32 +68,32 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/SynchronizedLoopExit01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/SynchronizedLoopExit01.java	Fri May 30 15:09:09 2014 +0200
@@ -30,9 +30,9 @@
 
 /**
  * Inspired by {@code com.sun.media.sound.DirectAudioDevice$DirectDL.drain()}.
- * 
+ *
  * Two loop exits hold a monitor while merging.
- * 
+ *
  */
 public final class SynchronizedLoopExit01 extends JTTTest {
 
@@ -53,7 +53,7 @@
         return b;
     }
 
-    @Test
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,22 +60,22 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_getState02 extends JTTTest {
 
@@ -33,7 +34,7 @@
         return new Thread().getState() == Thread.State.NEW;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,9 @@
 
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 //Test all, mainly monitors
 public class Thread_isInterrupted02 extends JTTTest {
@@ -85,12 +86,12 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0, 0);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1, 500);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -68,7 +69,7 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -66,7 +67,7 @@
 
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -66,7 +67,7 @@
         }
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join01 extends JTTTest implements Runnable {
 
@@ -43,7 +44,7 @@
         cont = false;
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Fri May 30 15:09:09 2014 +0200
@@ -27,8 +27,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join02 extends JTTTest implements Runnable {
 
@@ -50,7 +51,7 @@
         cont = false;
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Fri May 30 15:09:09 2014 +0200
@@ -27,8 +27,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join03 extends JTTTest implements Runnable {
 
@@ -47,7 +48,7 @@
         cont = false;
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_new01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_new02 extends JTTTest implements Runnable {
 
@@ -51,27 +52,27 @@
         // do nothing.
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_sleep01 extends JTTTest {
 
@@ -35,17 +36,17 @@
         return System.currentTimeMillis() - before >= i;
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 10);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 20);
     }
 
-    @LongTest
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 100);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_yield01.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_yield01.java	Fri May 30 15:09:09 2014 +0200
@@ -35,7 +35,7 @@
         return true;
     }
 
-    @Test
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri May 30 15:09:09 2014 +0200
@@ -39,8 +39,8 @@
 
     // @formatter:off
 
-    IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
-    LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
+    IADD, ISUB, IMUL, IUMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR,
+    LADD, LSUB, LMUL, LUMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR,
     FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
     INEG, LNEG, INOT, LNOT,
@@ -82,6 +82,27 @@
     }
 
     /**
+     * Unary operation with separate source and destination operand but register only.
+     */
+    public static class Unary2RegOp extends AMD64LIRInstruction {
+
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+
+        public Unary2RegOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            emit(crb, masm, opcode, result, x, null);
+        }
+    }
+
+    /**
      * Unary operation with single operand for source and destination.
      */
     public static class Unary1Op extends AMD64LIRInstruction {
@@ -321,6 +342,64 @@
         }
     }
 
+    public static class MulHighOp extends AMD64LIRInstruction {
+
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG}) public AllocatableValue lowResult;
+        @Def({REG}) public AllocatableValue highResult;
+        @Use({REG}) public AllocatableValue x;
+        @Use({REG, STACK}) public AllocatableValue y;
+
+        public MulHighOp(AMD64Arithmetic opcode, AllocatableValue y) {
+            PlatformKind kind = y.getPlatformKind();
+
+            this.opcode = opcode;
+            this.x = AMD64.rax.asValue(kind);
+            this.y = y;
+            this.lowResult = AMD64.rax.asValue(kind);
+            this.highResult = AMD64.rdx.asValue(kind);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(y)) {
+                switch (opcode) {
+                    case IMUL:
+                        masm.imull(asRegister(y));
+                        break;
+                    case IUMUL:
+                        masm.mull(asRegister(y));
+                        break;
+                    case LMUL:
+                        masm.imulq(asRegister(y));
+                        break;
+                    case LUMUL:
+                        masm.mulq(asRegister(y));
+                        break;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            } else {
+                switch (opcode) {
+                    case IMUL:
+                        masm.imull((AMD64Address) crb.asAddress(y));
+                        break;
+                    case IUMUL:
+                        masm.mull((AMD64Address) crb.asAddress(y));
+                        break;
+                    case LMUL:
+                        masm.imulq((AMD64Address) crb.asAddress(y));
+                        break;
+                    case LUMUL:
+                        masm.mulq((AMD64Address) crb.asAddress(y));
+                        break;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+        }
+    }
+
     public static class DivRemOp extends AMD64LIRInstruction {
 
         @Opcode private final AMD64Arithmetic opcode;
@@ -431,9 +510,6 @@
             case LNOT:
                 masm.notq(asLongReg(result));
                 break;
-            case L2I:
-                masm.andl(asIntReg(result), 0xFFFFFFFF);
-                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -473,6 +549,14 @@
                     assert asIntReg(src).equals(AMD64.rcx);
                     masm.shrl(asIntReg(dst));
                     break;
+                case IROL:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.roll(asIntReg(dst));
+                    break;
+                case IROR:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rorl(asIntReg(dst));
+                    break;
 
                 case LADD:
                     masm.addq(asLongReg(dst), asLongReg(src));
@@ -504,6 +588,14 @@
                     assert asIntReg(src).equals(AMD64.rcx);
                     masm.shrq(asLongReg(dst));
                     break;
+                case LROL:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rolq(asLongReg(dst));
+                    break;
+                case LROR:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rorq(asLongReg(dst));
+                    break;
 
                 case FADD:
                     masm.addss(asFloatReg(dst), asFloatReg(src));
@@ -568,6 +660,9 @@
                 case I2L:
                     masm.movslq(asLongReg(dst), asIntReg(src));
                     break;
+                case L2I:
+                    masm.movl(asIntReg(dst), asLongReg(src));
+                    break;
                 case F2D:
                     masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src));
                     break;
@@ -674,6 +769,12 @@
                 case IUSHR:
                     masm.shrl(asIntReg(dst), crb.asIntConst(src) & 31);
                     break;
+                case IROL:
+                    masm.roll(asIntReg(dst), crb.asIntConst(src) & 31);
+                    break;
+                case IROR:
+                    masm.rorl(asIntReg(dst), crb.asIntConst(src) & 31);
+                    break;
 
                 case LADD:
                     masm.addq(asLongReg(dst), crb.asIntConst(src));
@@ -702,6 +803,12 @@
                 case LUSHR:
                     masm.shrq(asLongReg(dst), crb.asIntConst(src) & 63);
                     break;
+                case LROL:
+                    masm.rolq(asLongReg(dst), crb.asIntConst(src) & 31);
+                    break;
+                case LROR:
+                    masm.rorq(asLongReg(dst), crb.asIntConst(src) & 31);
+                    break;
 
                 case FADD:
                     masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.lang.reflect.*;
@@ -38,7 +38,7 @@
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 /**
  * Emits code which compares two arrays of the same length. If the CPU supports any vector
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Fri May 30 15:09:09 2014 +0200
@@ -84,7 +84,7 @@
         }
 
         @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             if (isRegister(y)) {
                 switch (opcode) {
                     case BCMP:
@@ -129,9 +129,19 @@
                             throw GraalInternalError.shouldNotReachHere();
                         }
                         break;
+                    case ACMP:
+                        if (asConstant(y).isNull()) {
+                            masm.cmpq(address.toAddress(), 0);
+                        } else {
+                            throw GraalInternalError.shouldNotReachHere();
+                        }
+                        break;
                     default:
                         throw GraalInternalError.shouldNotReachHere();
                 }
+
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
             }
         }
 
@@ -139,6 +149,7 @@
         protected void verify() {
             super.verify();
             assert y instanceof Variable || y instanceof Constant;
+            assert kind != Kind.Long || !(y instanceof Constant) || NumUtil.isInt(((Constant) y).asLong());
         }
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Fri May 30 15:09:09 2014 +0200
@@ -432,6 +432,74 @@
         }
     }
 
+    @Opcode("ATOMIC_READ_AND_ADD")
+    public static class AtomicReadAndAddOp extends AMD64LIRInstruction {
+
+        private final Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Alive({COMPOSITE}) protected AMD64AddressValue address;
+        @Use protected AllocatableValue delta;
+
+        public AtomicReadAndAddOp(Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue delta) {
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.delta = delta;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            move(accessKind, crb, masm, result, delta);
+            if (crb.target.isMP) {
+                masm.lock();
+            }
+            switch (accessKind) {
+                case Int:
+                    masm.xaddl(address.toAddress(), asRegister(result));
+                    break;
+                case Long:
+                    masm.xaddq(address.toAddress(), asRegister(result));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Opcode("ATOMIC_READ_AND_WRITE")
+    public static class AtomicReadAndWriteOp extends AMD64LIRInstruction {
+
+        private final Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Alive({COMPOSITE}) protected AMD64AddressValue address;
+        @Use protected AllocatableValue newValue;
+
+        public AtomicReadAndWriteOp(Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue newValue) {
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.newValue = newValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            move(accessKind, crb, masm, result, newValue);
+            switch (accessKind) {
+                case Int:
+                    masm.xchgl(asRegister(result), address.toAddress());
+                    break;
+                case Long:
+                case Object:
+                    masm.xchgq(asRegister(result), address.toAddress());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
     public static void move(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Value input) {
         move(result.getKind(), crb, masm, result, input);
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Fri May 30 15:09:09 2014 +0200
@@ -45,7 +45,7 @@
     @Override
     public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         if (isRegister(y)) {
-            switch (y.getKind()) {
+            switch (kind) {
                 case Int:
                     masm.testl(asIntReg(y), address.toAddress());
                     break;
@@ -56,7 +56,7 @@
                     throw GraalInternalError.shouldNotReachHere();
             }
         } else if (isConstant(y)) {
-            switch (y.getKind()) {
+            switch (kind) {
                 case Int:
                     masm.testl(address.toAddress(), crb.asIntConst(y));
                     break;
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java	Fri May 30 15:09:09 2014 +0200
@@ -108,7 +108,7 @@
         private final String from;
         private final String to;
         @Def({REG}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
+        @Use({REG}) protected AllocatableValue x;
 
         public ConvertOp(AllocatableValue result, AllocatableValue x, String to, String from) {
             this.from = from;
@@ -123,52 +123,10 @@
         }
     }
 
-    public static class Op1Stack extends HSAILLIRInstruction {
-        @Opcode private final HSAILArithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
-
-        public Op1Stack(HSAILArithmetic opcode, Value result, Value x) {
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            emit(crb, masm, opcode, result, x, null);
-        }
-    }
-
-    public static class Op2Stack extends HSAILLIRInstruction {
+    public static class Op1Reg extends HSAILLIRInstruction {
         @Opcode private final HSAILArithmetic opcode;
         @Def({REG, HINT}) protected Value result;
         @Use({REG, CONST}) protected Value x;
-        @Alive({REG, CONST}) protected Value y;
-
-        public Op2Stack(HSAILArithmetic opcode, Value result, Value x, Value y) {
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            emit(crb, masm, opcode, result, x, y, null);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
-    public static class Op1Reg extends HSAILLIRInstruction {
-        @Opcode private final HSAILArithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG}) protected Value x;
 
         public Op1Reg(HSAILArithmetic opcode, Value result, Value x) {
             this.opcode = opcode;
@@ -185,7 +143,7 @@
     public static class Op2Reg extends HSAILLIRInstruction {
         @Opcode private final HSAILArithmetic opcode;
         @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
+        @Use({REG, CONST}) protected Value x;
         @Alive({REG, CONST}) protected Value y;
 
         public Op2Reg(HSAILArithmetic opcode, Value result, Value x, Value y) {
@@ -207,35 +165,10 @@
         }
     }
 
-    public static class Op2RegCommutative extends HSAILLIRInstruction {
-        @Opcode private final HSAILArithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
-        @Use({REG, CONST}) protected Value y;
-
-        public Op2RegCommutative(HSAILArithmetic opcode, Value result, Value x, Value y) {
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        protected void verify() {
-            super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
     public static class ShiftOp extends HSAILLIRInstruction {
         @Opcode private final HSAILArithmetic opcode;
         @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
+        @Use({REG, CONST}) protected Value x;
         @Alive({REG, CONST}) protected Value y;
 
         public ShiftOp(HSAILArithmetic opcode, Value result, Value x, Value y) {
@@ -295,7 +228,7 @@
 
     /**
      * Emits the HSAIL code for an arithmetic operation taking one input parameter.
-     * 
+     *
      * @param crb the CompilationResultBuilder
      * @param masm the HSAIL assembler
      * @param opcode the opcode of the arithmetic operation
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java	Fri May 30 15:09:09 2014 +0200
@@ -50,8 +50,8 @@
     public static class CompareOp extends HSAILLIRInstruction {
 
         @Opcode private final HSAILCompare opcode;
-        @Use({REG, STACK, CONST}) protected Value x;
-        @Use({REG, STACK, CONST}) protected Value y;
+        @Use({REG, CONST}) protected Value x;
+        @Use({REG, CONST}) protected Value y;
         @Def({REG}) protected Value z;
         private final Condition condition;
         public boolean unordered = false;
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Fri May 30 15:09:09 2014 +0200
@@ -84,11 +84,6 @@
         /**
          * Generates the code for this switch op.
          *
-         * The keys for switch statements in Java bytecode for of type int. However, Graal also
-         * generates a TypeSwitchNode (for method dispatch) which triggers the invocation of these
-         * routines with keys of type Long or Object. Currently we only support the
-         * IntegerSwitchNode so we throw an exception if the key isn't of type int.
-         *
          * @param crb the CompilationResultBuilder
          * @param masm the HSAIL assembler
          */
@@ -100,13 +95,13 @@
                     switch (key.getKind()) {
                         case Int:
                         case Long:
+                        case Object:
                             // Generate cascading compare and branches for each case.
                             masm.emitCompare(key.getKind(), key, keyConstants[index], HSAILCompare.conditionToString(condition), false, false);
                             masm.cbr(masm.nameOf(target));
                             break;
-                        case Object:
                         default:
-                            throw new GraalInternalError("switch only supported for int");
+                            throw new GraalInternalError("switch not supported for kind " + key.getKind());
                     }
                 }
             };
@@ -146,14 +141,15 @@
         protected MetaAccessProvider metaAccessProvider;
         protected String emitName;
         protected int codeBufferPos = -1;
-        protected int dregOopMap = 0;
+        private final boolean emitInfopoint;
 
-        public DeoptimizeOp(Value actionAndReason, LIRFrameState frameState, String emitName, MetaAccessProvider metaAccessProvider) {
+        public DeoptimizeOp(Value actionAndReason, LIRFrameState frameState, String emitName, boolean emitInfopoint, MetaAccessProvider metaAccessProvider) {
             super(Value.ILLEGAL);   // return with no ret value
             this.actionAndReason = actionAndReason;
             this.frameState = frameState;
             this.emitName = emitName;
             this.metaAccessProvider = metaAccessProvider;
+            this.emitInfopoint = emitInfopoint;
         }
 
         @Override
@@ -181,24 +177,18 @@
 
             masm.emitComment("/* HSAIL Deoptimization pos=" + codeBufferPos + ", bci=" + frameState.debugInfo().getBytecodePosition().getBCI() + ", frameState=" + frameState + " */");
 
-            // 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);
-                }
-            }
-
             AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
             AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
-            AllocatableValue dregOopMapReg = HSAIL.dregOopMapReg.asValue(Kind.Int);
             masm.emitMov(Kind.Int, actionAndReasonReg, actionAndReason);
             masm.emitMov(Kind.Int, codeBufferOffsetReg, Constant.forInt(codeBufferPos));
-            masm.emitMov(Kind.Int, dregOopMapReg, Constant.forInt(dregOopMap));
             masm.emitJumpToLabelName(masm.getDeoptLabelName());
 
-            // now record the debuginfo
-            crb.recordInfopoint(codeBufferPos, frameState, InfopointReason.IMPLICIT_EXCEPTION);
+            // Now record the debuginfo. If HSAIL deoptimization is off,
+            // no debuginfo is emitted and the kernel will return without
+            // a deoptimization.
+            if (emitInfopoint) {
+                crb.recordInfopoint(codeBufferPos, frameState, InfopointReason.IMPLICIT_EXCEPTION);
+            }
         }
 
         public LIRFrameState getFrameState() {
@@ -305,10 +295,10 @@
 
         @Opcode protected final HSAILCompare opcode;
         @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value trueValue;
-        @Use({REG, STACK, CONST}) protected Value falseValue;
-        @Use({REG, STACK, CONST}) protected Value left;
-        @Use({REG, STACK, CONST}) protected Value right;
+        @Use({REG, CONST}) protected Value trueValue;
+        @Use({REG, CONST}) protected Value falseValue;
+        @Use({REG, CONST}) protected Value left;
+        @Use({REG, CONST}) protected Value right;
         protected final Condition condition;
 
         public CondMoveOp(HSAILCompare opcode, Variable left, Variable right, Variable result, Condition condition, Value trueValue, Value falseValue) {
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Fri May 30 15:09:09 2014 +0200
@@ -63,29 +63,6 @@
     }
 
     @Opcode("MOVE")
-    public static class SpillMoveOp extends AbstractMoveOp {
-
-        @Def({REG, STACK}) protected AllocatableValue result;
-        @Use({REG, STACK, CONST}) protected Value input;
-
-        public SpillMoveOp(Kind moveKind, AllocatableValue result, Value input) {
-            super(moveKind);
-            this.result = result;
-            this.input = input;
-        }
-
-        @Override
-        public Value getInput() {
-            return input;
-        }
-
-        @Override
-        public AllocatableValue getResult() {
-            return result;
-        }
-    }
-
-    @Opcode("MOVE")
     public static class MoveToRegOp extends AbstractMoveOp {
 
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -252,67 +229,6 @@
         }
     }
 
-    public static class LoadCompressedPointer extends LoadOp {
-
-        private final long base;
-        private final int shift;
-        private final int alignment;
-        @Temp({REG}) private AllocatableValue scratch;
-
-        public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, HSAILAddressValue address, LIRFrameState state, long base, int shift, int alignment) {
-            super(kind, result, address, state);
-            this.base = base;
-            this.shift = shift;
-            this.alignment = alignment;
-            this.scratch = scratch;
-            assert kind == Kind.Object || kind == Kind.Long;
-        }
-
-        @Override
-        public void emitMemAccess(HSAILAssembler masm) {
-            // we will do a 32 bit load, zero extending into a 64 bit register
-            masm.emitLoad(result, address.toAddress(), "u32");
-            boolean testForNull = (kind == Kind.Object);
-            decodePointer(masm, result, base, shift, alignment, testForNull);
-        }
-    }
-
-    public static class StoreCompressedPointer extends HSAILLIRInstruction {
-
-        protected final Kind kind;
-        private final long base;
-        private final int shift;
-        private final int alignment;
-        @Temp({REG}) private AllocatableValue scratch;
-        @Alive({REG}) protected AllocatableValue input;
-        @Alive({COMPOSITE}) protected HSAILAddressValue address;
-        @State protected LIRFrameState state;
-
-        public StoreCompressedPointer(Kind kind, HSAILAddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long base, int shift, int alignment) {
-            this.base = base;
-            this.shift = shift;
-            this.alignment = alignment;
-            this.scratch = scratch;
-            this.kind = kind;
-            this.address = address;
-            this.state = state;
-            this.input = input;
-            assert kind == Kind.Object || kind == Kind.Long;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            masm.emitMov(kind, scratch, input);
-            boolean testForNull = (kind == Kind.Object);
-            encodePointer(masm, scratch, base, shift, alignment, testForNull);
-            if (state != null) {
-                throw new InternalError("NYI");
-                // crb.recordImplicitException(masm.position(), state);
-            }
-            masm.emitStore(scratch, address.toAddress(), "u32");
-        }
-    }
-
     public static class CompressPointer extends HSAILLIRInstruction {
 
         private final long base;
@@ -402,7 +318,8 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            throw new InternalError("NYI");
+            HSAILAddress addr = address.toAddress();
+            masm.emitLea(result, addr);
         }
     }
 
@@ -446,6 +363,65 @@
         }
     }
 
+    @Opcode("ATOMIC_READ_AND_ADD")
+    public static class AtomicReadAndAddOp extends HSAILLIRInstruction {
+
+        private final Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Use({COMPOSITE}) protected HSAILAddressValue address;
+        @Use({REG, CONST}) protected Value delta;
+
+        public AtomicReadAndAddOp(Kind accessKind, AllocatableValue result, HSAILAddressValue address, Value delta) {
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.delta = delta;
+        }
+
+        public HSAILAddressValue getAddress() {
+            return address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+            switch (accessKind) {
+                case Int:
+                case Long:
+                    masm.emitAtomicAdd(result, address.toAddress(), delta);
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Opcode("ATOMIC_READ_AND_WRITE")
+    public static class AtomicReadAndWriteOp extends HSAILLIRInstruction {
+
+        private final Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Use({COMPOSITE}) protected HSAILAddressValue address;
+        @Use({REG, CONST}) protected Value newValue;
+
+        public AtomicReadAndWriteOp(Kind accessKind, AllocatableValue result, HSAILAddressValue address, Value newValue) {
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.newValue = newValue;
+        }
+
+        public HSAILAddressValue getAddress() {
+            return address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+            masm.emitAtomicExch(accessKind, result, address.toAddress(), newValue);
+        }
+    }
+
     public static class NullCheckOp extends HSAILLIRInstruction {
 
         @Use protected Value input;
@@ -489,27 +465,4 @@
         }
     }
 
-    @Opcode("ATOMICADD")
-    public static class AtomicGetAndAddOp extends HSAILLIRInstruction {
-
-        @Def protected AllocatableValue result;
-        @Use({COMPOSITE}) protected HSAILAddressValue address;
-        @Use({REG, CONST}) protected Value delta;
-
-        public AtomicGetAndAddOp(AllocatableValue result, HSAILAddressValue address, Value delta) {
-            this.result = result;
-            this.address = address;
-            this.delta = delta;
-        }
-
-        public HSAILAddressValue getAddress() {
-            return address;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            masm.emitAtomicAdd(result, address.toAddress(), delta);
-        }
-    }
-
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Fri May 30 15:09:09 2014 +0200
@@ -59,7 +59,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 public enum SPARCArithmetic {
     // @formatter:off
@@ -68,7 +68,7 @@
     FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
     INEG, LNEG, FNEG, DNEG, INOT, LNOT,
-    I2L, L2I, I2B, I2C, I2S,
+    L2I, B2I, S2I, B2L, S2L, I2L,
     F2D, D2F,
     I2F, I2D, F2I, D2I,
     L2F, L2D, F2L, D2L,
@@ -586,11 +586,11 @@
                 case L2I:
                     new Signx(asLongReg(src), asIntReg(dst)).emit(masm);
                     break;
-                case I2B:
+                case B2I:
                     new Sll(asIntReg(src), 24, asIntReg(dst)).emit(masm);
                     new Srl(asIntReg(dst), 24, asIntReg(dst)).emit(masm);
                     break;
-                case I2C:
+                case S2I:
                     new Sll(asIntReg(src), 16, asIntReg(dst)).emit(masm);
                     new Srl(asIntReg(dst), 16, asIntReg(dst)).emit(masm);
                     break;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Fri May 30 15:09:09 2014 +0200
@@ -40,7 +40,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.lir.gen.*;
 
 public class SPARCBitManipulationOp extends SPARCLIRInstruction {
 
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Fri May 30 15:09:09 2014 +0200
@@ -270,61 +270,61 @@
     @Opcode("CMOVE")
     public static class CondMoveOp extends SPARCLIRInstruction {
 
+        private final Kind kind;
+
         @Def({REG, HINT}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Use({REG, STACK, CONST}) protected Value falseValue;
 
         private final ConditionFlag condition;
-        private final CC cCode;
 
-        public CondMoveOp(Variable result, Condition condition, CC cCode, Variable trueValue, Value falseValue) {
+        public CondMoveOp(Kind kind, Variable result, Condition condition, Variable trueValue, Value falseValue) {
+            this.kind = kind;
             this.result = result;
             this.condition = intCond(condition);
             this.trueValue = trueValue;
             this.falseValue = falseValue;
-            this.cCode = cCode;
         }
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            cmove(crb, masm, result, false, condition, cCode, false, trueValue, falseValue);
+            // check that we don't overwrite an input operand before it is used.
+            assert !result.equals(trueValue);
+
+            SPARCMove.move(crb, masm, result, falseValue);
+            cmove(crb, masm, kind, result, condition, trueValue);
         }
     }
 
     @Opcode("CMOVE")
     public static class FloatCondMoveOp extends SPARCLIRInstruction {
 
+        private final Kind kind;
+
         @Def({REG}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Alive({REG}) protected Value falseValue;
+
         private final ConditionFlag condition;
         private final boolean unorderedIsTrue;
-        private final CC cCode;
 
-        public FloatCondMoveOp(Variable result, Condition condition, CC cCode, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+        public FloatCondMoveOp(Kind kind, Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+            this.kind = kind;
             this.result = result;
             this.condition = floatCond(condition);
             this.unorderedIsTrue = unorderedIsTrue;
             this.trueValue = trueValue;
             this.falseValue = falseValue;
-            this.cCode = cCode;
         }
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            cmove(crb, masm, result, true, condition, cCode, unorderedIsTrue, trueValue, falseValue);
-        }
-    }
+            // check that we don't overwrite an input operand before it is used.
+            assert !result.equals(trueValue);
 
-    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, boolean isFloat, ConditionFlag condition, CC cCode, boolean unorderedIsTrue, Value trueValue,
-                    Value falseValue) {
-        // check that we don't overwrite an input operand before it is used.
-        assert !result.equals(trueValue);
+            SPARCMove.move(crb, masm, result, falseValue);
+            cmove(crb, masm, kind, result, condition, trueValue);
 
-        SPARCMove.move(crb, masm, result, falseValue);
-        cmove(crb, masm, result, condition, cCode, trueValue);
-
-        if (isFloat) {
             if (unorderedIsTrue && !trueOnUnordered(condition)) {
                 // cmove(crb, masm, result, ConditionFlag.Parity, trueValue);
                 throw GraalInternalError.unimplemented();
@@ -335,16 +335,19 @@
         }
     }
 
-    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, ConditionFlag cond, CC cCode, Value other) {
+    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Kind kind, Value result, ConditionFlag cond, Value other) {
         if (!isRegister(other)) {
             SPARCMove.move(crb, masm, result, other);
-            throw new InternalError("result should be scratch");
+            throw GraalInternalError.shouldNotReachHere("result should be scratch");
         }
         assert !asRegister(other).equals(asRegister(result)) : "other already overwritten by previous move";
-        switch (other.getKind()) {
+        switch (kind) {
             case Int:
+                new Movcc(cond, CC.Icc, asRegister(other), asRegister(result)).emit(masm);
+                break;
             case Long:
-                new Movcc(cond, cCode, asRegister(other), asRegister(result)).emit(masm);
+            case Object:
+                new Movcc(cond, CC.Xcc, asRegister(other), asRegister(result)).emit(masm);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.lir.*;
 
 /**
@@ -33,7 +34,7 @@
  *
  * <pre>
  *   Base       Contents
- *
+ * 
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
@@ -88,8 +89,7 @@
 
     @Override
     protected int alignFrameSize(int size) {
-        int x = size + (target.stackAlignment - 1);
-        return (x / target.stackAlignment) * target.stackAlignment;
+        return NumUtil.roundUp(size, target.stackAlignment);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,32 +23,14 @@
 package com.oracle.graal.lir.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CompilationResult.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Add;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lduh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Membar;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Rdpc;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Sth;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cas;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Casx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Clr;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setuw;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
@@ -154,32 +136,33 @@
 
         @Override
         public void emitMemAccess(SPARCMacroAssembler masm) {
-            SPARCAddress addr = address.toAddress();
+            final SPARCAddress addr = address.toAddress();
+            final Register dst = asRegister(result);
             switch (kind) {
                 case Boolean:
                 case Byte:
-                    new Ldsb(addr, asRegister(result)).emit(masm);
+                    new Ldsb(addr, dst).emit(masm);
                     break;
                 case Short:
-                    new Ldsh(addr, asRegister(result)).emit(masm);
+                    new Ldsh(addr, dst).emit(masm);
                     break;
                 case Char:
-                    new Lduh(addr, asRegister(result)).emit(masm);
+                    new Lduh(addr, dst).emit(masm);
                     break;
                 case Int:
-                    new Ldsw(addr, asRegister(result)).emit(masm);
+                    new Ldsw(addr, dst).emit(masm);
                     break;
                 case Long:
-                    new Ldx(addr, asRegister(result)).emit(masm);
+                    new Ldx(addr, dst).emit(masm);
                     break;
                 case Float:
-                    new Ldf(addr, asRegister(result)).emit(masm);
+                    new Ldf(addr, dst).emit(masm);
                     break;
                 case Double:
-                    new Lddf(addr, asRegister(result)).emit(masm);
+                    new Lddf(addr, dst).emit(masm);
                     break;
                 case Object:
-                    new Ldx(addr, asRegister(result)).emit(masm);
+                    new Ldx(addr, dst).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -190,29 +173,41 @@
     public static class LoadAddressOp extends SPARCLIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
-        @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue addressValue;
-        protected SPARCAddress address;
+        @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue address;
 
         public LoadAddressOp(AllocatableValue result, SPARCAddressValue address) {
             this.result = result;
-            this.addressValue = address;
-        }
-
-        public LoadAddressOp(AllocatableValue result, SPARCAddress address) {
-            this.result = result;
             this.address = address;
         }
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            if (address == null) {
-                address = addressValue.toAddress();
+            SPARCAddress addr = address.toAddress();
+            if (addr.hasIndex()) {
+                new Add(addr.getBase(), addr.getIndex(), asLongReg(result)).emit(masm);
+            } else {
+                new Add(addr.getBase(), addr.getDisplacement(), asLongReg(result)).emit(masm);
             }
-            if (address.hasIndex()) {
-                new Add(address.getBase(), address.getIndex(), asLongReg(result)).emit(masm);
-            } else {
-                new Add(address.getBase(), address.getDisplacement(), asLongReg(result)).emit(masm);
-            }
+        }
+    }
+
+    public static class LoadDataAddressOp extends SPARCLIRInstruction {
+
+        @Def({REG}) protected AllocatableValue result;
+        private final byte[] data;
+
+        public LoadDataAddressOp(AllocatableValue result, byte[] data) {
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            RawData rawData = new RawData(data, 16);
+            SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(rawData);
+            assert addr == masm.getPlaceholder();
+            final boolean forceRelocatable = true;
+            new Setx(0, asRegister(result), forceRelocatable).emit(masm);
         }
     }
 
@@ -334,12 +329,10 @@
     public static class StoreConstantOp extends MemOp {
 
         protected final Constant input;
-        private final boolean compress;
 
-        public StoreConstantOp(Kind kind, SPARCAddressValue address, Constant input, LIRFrameState state, boolean compress) {
+        public StoreConstantOp(Kind kind, SPARCAddressValue address, Constant input, LIRFrameState state) {
             super(kind, address, state);
             this.input = input;
-            this.compress = compress;
             if (!input.isDefaultForKind()) {
                 throw GraalInternalError.shouldNotReachHere("Can only store null constants to memory");
             }
@@ -361,11 +354,7 @@
                     break;
                 case Long:
                 case Object:
-                    if (compress) {
-                        new Stw(g0, address.toAddress()).emit(masm);
-                    } else {
-                        new Stx(g0, address.toAddress()).emit(masm);
-                    }
+                    new Stx(g0, address.toAddress()).emit(masm);
                     break;
                 case Float:
                 case Double:
@@ -403,19 +392,25 @@
     }
 
     private static void reg2reg(SPARCAssembler masm, Value result, Value input) {
-        if (asRegister(input).equals(asRegister(result))) {
+        final Register src = asRegister(input);
+        final Register dst = asRegister(result);
+        if (src.equals(dst)) {
             return;
         }
         switch (input.getKind()) {
             case Int:
             case Long:
             case Object:
-                new Mov(asRegister(input), asRegister(result)).emit(masm);
+                new Mov(src, dst).emit(masm);
                 break;
             case Float:
+                new Fmovs(src, dst).emit(masm);
+                break;
             case Double:
+                new Fmovd(src, dst).emit(masm);
+                break;
             default:
-                throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
+                throw GraalInternalError.shouldNotReachHere();
         }
     }
 
@@ -431,7 +426,11 @@
                 new Stx(src, dst).emit(masm);
                 break;
             case Float:
+                new Stf(src, dst).emit(masm);
+                break;
             case Double:
+                new Stdf(src, dst).emit(masm);
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -469,7 +468,7 @@
                     }
                 }
                 break;
-            case Long: {
+            case Long:
                 if (crb.codeCache.needsDataPatch(input)) {
                     crb.recordInlineDataInCode(input);
                     new Setx(input.asLong(), asRegister(result), true).emit(masm);
@@ -481,20 +480,10 @@
                     }
                 }
                 break;
-            }
-            case Double: {
-                // This is *not* the same as 'constant == 0.0d' in the case where constant is -0.0d
-                assert !crb.codeCache.needsDataPatch(input);
-                new Setx(Double.doubleToRawLongBits(input.asDouble()), asDoubleReg(result)).emit(masm);
+            case Float:
+                new Ldf((SPARCAddress) crb.asFloatConstRef(input), asFloatReg(result)).emit(masm);
                 break;
-            }
-            case Float: {
-                // This is *not* the same as 'constant == 0.0d' in the case where constant is -0.0d
-                assert !crb.codeCache.needsDataPatch(input);
-                new Setx(Double.doubleToRawLongBits(input.asFloat()), asFloatReg(result)).emit(masm);
-                break;
-            }
-            case Object: {
+            case Object:
                 if (input.isNull()) {
                     new Clr(asRegister(result)).emit(masm);
                 } else if (crb.target.inlineObjects) {
@@ -508,7 +497,6 @@
                     throw GraalInternalError.shouldNotReachHere("the patched offset might be too big for the load");
                 }
                 break;
-            }
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.sparc;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
+
+    /**
+     * The registers (potentially) saved by this operation.
+     */
+    protected final Register[] savedRegisters;
+
+    /**
+     * The slots to which the registers are saved.
+     */
+    @Def(STACK) protected final StackSlot[] slots;
+
+    /**
+     * Specifies if {@link #remove(Set)} should have an effect.
+     */
+    protected final boolean supportsRemove;
+
+    /**
+     *
+     * @param savedRegisters the registers saved by this operation which may be subject to
+     *            {@linkplain #remove(Set) pruning}
+     * @param slots the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
+     */
+    public SPARCSaveRegistersOp(Register[] savedRegisters, StackSlot[] slots, boolean supportsRemove) {
+        this.savedRegisters = savedRegisters;
+        this.slots = slots;
+        this.supportsRemove = supportsRemove;
+    }
+
+    private static void saveRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, StackSlot result, Register register) {
+        RegisterValue input = register.asValue(result.getKind());
+        SPARCMove.move(crb, masm, result, input);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                saveRegister(crb, masm, slots[i], savedRegisters[i]);
+            }
+        }
+    }
+
+    public StackSlot[] getSlots() {
+        return slots;
+    }
+
+    public boolean supportsRemove() {
+        return supportsRemove;
+    }
+
+    public int remove(Set<Register> doNotSave) {
+        if (!supportsRemove) {
+            throw new UnsupportedOperationException();
+        }
+        return prune(doNotSave, savedRegisters);
+    }
+
+    static int prune(Set<Register> toRemove, Register[] registers) {
+        int pruned = 0;
+        for (int i = 0; i < registers.length; i++) {
+            if (registers[i] != null) {
+                if (toRemove.contains(registers[i])) {
+                    registers[i] = null;
+                    pruned++;
+                }
+            }
+        }
+        return pruned;
+    }
+
+    public RegisterSaveLayout getMap(FrameMap frameMap) {
+        int total = 0;
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                total++;
+            }
+        }
+        Register[] keys = new Register[total];
+        int[] values = new int[total];
+        if (total != 0) {
+            int mapIndex = 0;
+            for (int i = 0; i < savedRegisters.length; i++) {
+                if (savedRegisters[i] != null) {
+                    keys[mapIndex] = savedRegisters[i];
+                    values[mapIndex] = frameMap.indexForStackSlot(slots[i]);
+                    mapIndex++;
+                }
+            }
+            assert mapIndex == total;
+        }
+        return new RegisterSaveLayout(keys, values);
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri May 30 15:09:09 2014 +0200
@@ -86,7 +86,7 @@
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
         ValueFieldScanner scanner = new ValueFieldScanner(calc);
-        scanner.scan(clazz);
+        scanner.scan(getClazz());
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
         copyInto(componentOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
@@ -108,7 +108,7 @@
         }
 
         @Override
-        protected void scan(Class<?> clazz) {
+        public void scan(Class<?> clazz) {
             super.scan(clazz);
         }
 
@@ -127,7 +127,7 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" component[");
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" component[");
         for (int i = 0; i < componentOffsets.length; i++) {
             str.append(i == 0 ? "" : ", ").append(componentOffsets[i]);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri May 30 15:09:09 2014 +0200
@@ -113,6 +113,15 @@
     }
 
     /**
+     * Gets the size of a stack slot.
+     *
+     * @return stack slot size
+     */
+    public int stackSlotSize() {
+        return target.wordSize;
+    }
+
+    /**
      * Gets the frame size of the compiled frame, not including the size of the
      * {@link Architecture#getReturnAddressSize() return address slot}.
      *
@@ -208,8 +217,8 @@
      * @return the index of the stack slot
      */
     public int indexForStackSlot(StackSlot slot) {
-        assert offsetForStackSlot(slot) % target.wordSize == 0;
-        return offsetForStackSlot(slot) / target.wordSize;
+        assert offsetForStackSlot(slot) % stackSlotSize() == 0;
+        return offsetForStackSlot(slot) / stackSlotSize();
     }
 
     /**
@@ -259,7 +268,7 @@
      * @param kind the {@link PlatformKind} to be stored in the spill slot.
      * @return the size in bytes
      */
-    protected int spillSlotSize(PlatformKind kind) {
+    public int spillSlotSize(PlatformKind kind) {
         return target.getSizeInBytes(kind);
     }
 
@@ -321,7 +330,7 @@
         if (slots == 0) {
             return null;
         }
-        spillSize += (slots * target.wordSize);
+        spillSize += (slots * stackSlotSize());
 
         if (!objects.isEmpty()) {
             assert objects.length() <= slots;
@@ -329,7 +338,7 @@
             for (int slotIndex = 0; slotIndex < slots; slotIndex++) {
                 StackSlot objectSlot = null;
                 if (objects.get(slotIndex)) {
-                    objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * target.wordSize);
+                    objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * stackSlotSize());
                     objectStackSlots.add(objectSlot);
                     if (outObjectStackSlots != null) {
                         outObjectStackSlots.add(objectSlot);
@@ -352,7 +361,7 @@
     }
 
     public ReferenceMap initReferenceMap(boolean hasRegisters) {
-        ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / target.wordSize);
+        ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / stackSlotSize());
         for (StackSlot slot : objectStackSlots) {
             setReference(slot, refMap);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri May 30 15:09:09 2014 +0200
@@ -118,7 +118,7 @@
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
         InstructionFieldScanner scanner = new InstructionFieldScanner(calc);
-        scanner.scan(clazz);
+        scanner.scan(getClazz());
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
         copyInto(useOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
@@ -177,7 +177,7 @@
         }
 
         @Override
-        protected void scan(Class<?> clazz) {
+        public void scan(Class<?> clazz) {
             if (clazz.getAnnotation(Opcode.class) != null) {
                 opcodeConstant = clazz.getAnnotation(Opcode.class).value();
             }
@@ -213,7 +213,7 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" use[");
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
         for (int i = 0; i < useOffsets.length; i++) {
             str.append(i == 0 ? "" : ", ").append(useOffsets[i]);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri May 30 15:09:09 2014 +0200
@@ -31,7 +31,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Fri May 30 15:09:09 2014 +0200
@@ -26,12 +26,11 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.StandardOp.BranchOp;
 import com.oracle.graal.lir.StandardOp.JumpOp;
-import com.oracle.graal.nodes.cfg.*;
 
 /**
  * LIR instructions such as {@link JumpOp} and {@link BranchOp} need to reference their target
- * {@link Block}. However, direct references are not possible since the control flow graph (and
- * therefore successors lists) can be changed by optimizations - and fixing the instructions is
+ * {@link AbstractBlock}. However, direct references are not possible since the control flow graph
+ * (and therefore successors lists) can be changed by optimizations - and fixing the instructions is
  * error prone. Therefore, we represent an edge to block B from block A via the tuple {@code (A,
  * successor-index-of-B)}. That is, indirectly by storing the index into the successor list of A.
  * Note therefore that the successor list cannot be re-ordered.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Fri May 30 15:09:09 2014 +0200
@@ -92,14 +92,8 @@
         compilationResult.setTotalFrameSize(frameSize);
     }
 
-    private static final CompilationResult.Mark[] NO_REFS = {};
-
     public CompilationResult.Mark recordMark(Object id) {
-        return compilationResult.recordMark(asm.position(), id, NO_REFS);
-    }
-
-    public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) {
-        return compilationResult.recordMark(asm.position(), id, references);
+        return compilationResult.recordMark(asm.position(), id);
     }
 
     public void blockComment(String s) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/ArithmeticLIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.gen;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * This interface can be used to generate LIR for arithmetic operations.
+ */
+public interface ArithmeticLIRGenerator {
+
+    PlatformKind getPlatformKind(Stamp stamp);
+
+    Value emitNegate(Value input);
+
+    Value emitAdd(Value a, Value b);
+
+    Value emitSub(Value a, Value b);
+
+    Value emitMul(Value a, Value b);
+
+    Value emitMulHigh(Value a, Value b);
+
+    Value emitUMulHigh(Value a, Value b);
+
+    Value emitDiv(Value a, Value b, LIRFrameState state);
+
+    Value emitRem(Value a, Value b, LIRFrameState state);
+
+    Value emitUDiv(Value a, Value b, LIRFrameState state);
+
+    Value emitURem(Value a, Value b, LIRFrameState state);
+
+    Value emitNot(Value input);
+
+    Value emitAnd(Value a, Value b);
+
+    Value emitOr(Value a, Value b);
+
+    Value emitXor(Value a, Value b);
+
+    Value emitShl(Value a, Value b);
+
+    Value emitShr(Value a, Value b);
+
+    Value emitUShr(Value a, Value b);
+
+    Value emitFloatConvert(FloatConvert op, Value inputVal);
+
+    Value emitReinterpret(PlatformKind to, Value inputVal);
+
+    Value emitNarrow(Value inputVal, int bits);
+
+    Value emitSignExtend(Value inputVal, int fromBits, int toBits);
+
+    Value emitZeroExtend(Value inputVal, int fromBits, int toBits);
+
+    Value emitMathAbs(Value input);
+
+    Value emitMathSqrt(Value input);
+
+    Value emitMathLog(Value input, boolean base10);
+
+    Value emitMathCos(Value input);
+
+    Value emitMathSin(Value input);
+
+    Value emitMathTan(Value input);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Fri May 30 15:09:09 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.lir.gen;
+
+import com.oracle.graal.lir.*;
+
+public interface LIRGenerationResult {
+    FrameMap getFrameMap();
+
+    LIR getLIR();
+
+    boolean hasForeignCall();
+
+    void setForeignCall(boolean b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Fri May 30 15:09:09 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.lir.gen;
+
+import com.oracle.graal.lir.*;
+
+public class LIRGenerationResultBase implements LIRGenerationResult {
+    private final LIR lir;
+    private final FrameMap frameMap;
+    /**
+     * Records whether the code being generated makes at least one foreign call.
+     */
+    private boolean hasForeignCall;
+
+    public LIRGenerationResultBase(LIR lir, FrameMap frameMap) {
+        this.lir = lir;
+        this.frameMap = frameMap;
+    }
+
+    public LIR getLIR() {
+        return lir;
+    }
+
+    /**
+     * Determines whether the code being generated makes at least one foreign call.
+     */
+    public boolean hasForeignCall() {
+        return hasForeignCall;
+    }
+
+    public final void setForeignCall(boolean hasForeignCall) {
+        this.hasForeignCall = hasForeignCall;
+    }
+
+    public final FrameMap getFrameMap() {
+        return frameMap;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.gen;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.api.meta.Value.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.lir.LIR.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.options.*;
+
+/**
+ * This class traverses the HIR instructions and generates LIR instructions from them.
+ */
+public abstract class LIRGenerator implements LIRGeneratorTool, PlatformKindTool {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Print HIR along side LIR as the latter is generated")
+        public static final OptionValue<Boolean> PrintIRWithLIR = new OptionValue<>(false);
+        @Option(help = "The trace level for the LIR generator")
+        public static final OptionValue<Integer> TraceLIRGeneratorLevel = new OptionValue<>(0);
+        // @formatter:on
+    }
+
+    private final CodeGenProviders providers;
+    private final CallingConvention cc;
+
+    private AbstractBlock<?> currentBlock;
+
+    /**
+     * Handle for an operation that loads a constant into a variable. The operation starts in the
+     * first block where the constant is used but will eventually be
+     * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the
+     * constant.
+     */
+    public static class LoadConstant implements Comparable<LoadConstant> {
+        /**
+         * The index of {@link #op} within {@link #block}'s instruction list or -1 if {@code op} is
+         * to be moved to a dominator block.
+         */
+        int index;
+
+        /**
+         * The operation that loads the constant.
+         */
+        private final LIRInstruction op;
+
+        /**
+         * The block that does or will contain {@link #op}. This is initially the block where the
+         * first usage of the constant is seen during LIR generation.
+         */
+        AbstractBlock<?> block;
+
+        /**
+         * The variable into which the constant is loaded.
+         */
+        final Variable variable;
+
+        public LoadConstant(Variable variable, AbstractBlock<?> block, int index, LIRInstruction op) {
+            this.variable = variable;
+            this.block = block;
+            this.index = index;
+            this.op = op;
+        }
+
+        /**
+         * Sorts {@link LoadConstant} objects according to their enclosing blocks. This is used to
+         * group loads per block in {@link LIRGenerator#insertConstantLoads()}.
+         */
+        public int compareTo(LoadConstant o) {
+            if (block.getId() < o.block.getId()) {
+                return -1;
+            }
+            if (block.getId() > o.block.getId()) {
+                return 1;
+            }
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return block + "#" + op;
+        }
+
+        /**
+         * Removes the {@link #op} from its original location if it is still at that location.
+         */
+        public void unpin(LIR lir) {
+            if (index >= 0) {
+                // Replace the move with a filler op so that the operation
+                // list does not need to be adjusted.
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                instructions.set(index, new NoOp(null, -1));
+                index = -1;
+            }
+        }
+
+        public AbstractBlock<?> getBlock() {
+            return block;
+        }
+
+        public void setBlock(AbstractBlock<?> block) {
+            this.block = block;
+        }
+
+        public Variable getVariable() {
+            return variable;
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public void setIndex(int index) {
+            this.index = index;
+        }
+    }
+
+    private Map<Constant, LoadConstant> constantLoads;
+
+    private LIRGenerationResult res;
+
+    public LIRGenerator(CodeGenProviders providers, CallingConvention cc, LIRGenerationResult res) {
+        this.res = res;
+        this.providers = providers;
+        this.cc = cc;
+    }
+
+    /**
+     * Returns true if the redundant move elimination optimization should be done after register
+     * allocation.
+     */
+    public boolean canEliminateRedundantMoves() {
+        return true;
+    }
+
+    @Override
+    public TargetDescription target() {
+        return getCodeCache().getTarget();
+    }
+
+    public CodeGenProviders getProviders() {
+        return providers;
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
+    }
+
+    @Override
+    public CodeCacheProvider getCodeCache() {
+        return providers.getCodeCache();
+    }
+
+    @Override
+    public ForeignCallsProvider getForeignCalls() {
+        return providers.getForeignCalls();
+    }
+
+    /**
+     * Creates a new {@linkplain Variable variable}.
+     *
+     * @param platformKind The kind of the new variable.
+     * @return a new variable
+     */
+    @Override
+    public Variable newVariable(PlatformKind platformKind) {
+        return new Variable(platformKind, res.getLIR().nextVariable());
+    }
+
+    @Override
+    public RegisterAttributes attributes(Register register) {
+        return res.getFrameMap().registerConfig.getAttributesMap()[register.number];
+    }
+
+    @Override
+    public abstract Variable emitMove(Value input);
+
+    public AllocatableValue asAllocatable(Value value) {
+        if (isAllocatableValue(value)) {
+            return asAllocatableValue(value);
+        } else {
+            return emitMove(value);
+        }
+    }
+
+    public Variable load(Value value) {
+        if (!isVariable(value)) {
+            return emitMove(value);
+        }
+        return (Variable) value;
+    }
+
+    public Value loadNonConst(Value value) {
+        if (isConstant(value) && !canInlineConstant((Constant) value)) {
+            return emitMove(value);
+        }
+        return value;
+    }
+
+    /**
+     * Determines if only oop maps are required for the code generated from the LIR.
+     */
+    public boolean needOnlyOopMaps() {
+        return false;
+    }
+
+    /**
+     * Gets the ABI specific operand used to return a value of a given kind from a method.
+     *
+     * @param kind the kind of value being returned
+     * @return the operand representing the ABI defined location used return a value of kind
+     *         {@code kind}
+     */
+    public AllocatableValue resultOperandFor(Kind kind) {
+        if (kind == Kind.Void) {
+            return ILLEGAL;
+        }
+        return res.getFrameMap().registerConfig.getReturnRegister(kind).asValue(kind);
+    }
+
+    public void append(LIRInstruction op) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
+            TTY.println(op.toStringWithIdPrefix());
+            TTY.println();
+        }
+        assert LIRVerifier.verify(op);
+        res.getLIR().getLIRforBlock(currentBlock).add(op);
+    }
+
+    public boolean hasBlockEnd(AbstractBlock<?> block) {
+        List<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
+        if (ops.size() == 0) {
+            return false;
+        }
+        return ops.get(ops.size() - 1) instanceof BlockEndOp;
+    }
+
+    public final void doBlockStart(AbstractBlock<?> block) {
+        if (Options.PrintIRWithLIR.getValue()) {
+            TTY.print(block.toString());
+        }
+
+        currentBlock = block;
+
+        // set up the list of LIR instructions
+        assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block";
+        res.getLIR().setLIRforBlock(block, new ArrayList<LIRInstruction>());
+
+        append(new LabelOp(new Label(block.getId()), block.isAligned()));
+
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
+            TTY.println("BEGIN Generating LIR for block B" + block.getId());
+        }
+    }
+
+    public final void doBlockEnd(AbstractBlock<?> block) {
+
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
+            TTY.println("END Generating LIR for block B" + block.getId());
+        }
+
+        currentBlock = null;
+
+        if (Options.PrintIRWithLIR.getValue()) {
+            TTY.println();
+        }
+    }
+
+    public void emitIncomingValues(Value[] params) {
+        ((LabelOp) res.getLIR().getLIRforBlock(currentBlock).get(0)).setIncomingValues(params);
+    }
+
+    public abstract void emitJump(LabelRef label);
+
+    public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability);
+
+    public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
+
+    public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+    public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+    public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+    protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
+
+    public static AllocatableValue toStackKind(AllocatableValue value) {
+        if (value.getKind().getStackKind() != value.getKind()) {
+            // We only have stack-kinds in the LIR, so convert the operand kind for values from the
+            // calling convention.
+            if (isRegister(value)) {
+                return asRegister(value).asValue(value.getKind().getStackKind());
+            } else if (isStackSlot(value)) {
+                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args) {
+        LIRFrameState state = null;
+        if (linkage.canDeoptimize()) {
+            if (frameState != null) {
+                state = frameState;
+            } else {
+                assert needOnlyOopMaps();
+                state = new LIRFrameState(null, null, null);
+            }
+        }
+
+        // move the arguments into the correct location
+        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
+        res.getFrameMap().callsMethod(linkageCc);
+        assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
+        Value[] argLocations = new Value[args.length];
+        for (int i = 0; i < args.length; i++) {
+            Value arg = args[i];
+            AllocatableValue loc = linkageCc.getArgument(i);
+            emitMove(loc, arg);
+            argLocations[i] = loc;
+        }
+        res.setForeignCall(true);
+        emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
+
+        if (isLegal(linkageCc.getReturn())) {
+            return emitMove(linkageCc.getReturn());
+        } else {
+            return null;
+        }
+    }
+
+    public void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
+        int keyCount = keyConstants.length;
+        SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
+        long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
+        double tableSwitchDensity = keyCount / (double) valueRange;
+        /*
+         * This heuristic tries to find a compromise between the effort for the best switch strategy
+         * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
+         * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
+         * gradually with additional effort.
+         */
+        if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) {
+            emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
+        } else {
+            int minValue = keyConstants[0].asInt();
+            assert valueRange < Integer.MAX_VALUE;
+            LabelRef[] targets = new LabelRef[(int) valueRange];
+            for (int i = 0; i < valueRange; i++) {
+                targets[i] = defaultTarget;
+            }
+            for (int i = 0; i < keyCount; i++) {
+                targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
+            }
+            emitTableSwitch(minValue, defaultTarget, targets, value);
+        }
+    }
+
+    public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+    protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
+
+    public CallingConvention getCallingConvention() {
+        return cc;
+    }
+
+    @Override
+    public void beforeRegisterAllocation() {
+        insertConstantLoads();
+    }
+
+    /**
+     * Moves deferred {@linkplain LoadConstant loads} of constants into blocks dominating all usages
+     * of the constant. Any operations inserted into a block are guaranteed to be immediately prior
+     * to the first control flow instruction near the end of the block.
+     */
+    private void insertConstantLoads() {
+        if (constantLoads != null) {
+            // Remove loads where all usages are in the same block.
+            for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) {
+                LoadConstant lc = iter.next().getValue();
+
+                // Move loads of constant outside of loops
+                if (OptScheduleOutOfLoops.getValue()) {
+                    AbstractBlock<?> outOfLoopDominator = lc.block;
+                    while (outOfLoopDominator.getLoop() != null) {
+                        outOfLoopDominator = outOfLoopDominator.getDominator();
+                    }
+                    if (outOfLoopDominator != lc.block) {
+                        lc.unpin(res.getLIR());
+                        lc.block = outOfLoopDominator;
+                    }
+                }
+
+                if (lc.index != -1) {
+                    assert res.getLIR().getLIRforBlock(lc.block).get(lc.index) == lc.op;
+                    iter.remove();
+                }
+            }
+            if (constantLoads.isEmpty()) {
+                return;
+            }
+
+            // Sorting groups the loads per block.
+            LoadConstant[] groupedByBlock = constantLoads.values().toArray(new LoadConstant[constantLoads.size()]);
+            Arrays.sort(groupedByBlock);
+
+            int groupBegin = 0;
+            while (true) {
+                int groupEnd = groupBegin + 1;
+                AbstractBlock<?> block = groupedByBlock[groupBegin].block;
+                while (groupEnd < groupedByBlock.length && groupedByBlock[groupEnd].block == block) {
+                    groupEnd++;
+                }
+                int groupSize = groupEnd - groupBegin;
+
+                List<LIRInstruction> ops = res.getLIR().getLIRforBlock(block);
+                int lastIndex = ops.size() - 1;
+                assert ops.get(lastIndex) instanceof BlockEndOp;
+                int insertionIndex = lastIndex;
+                for (int i = Math.max(0, lastIndex - MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END); i < lastIndex; i++) {
+                    if (getExceptionEdge(ops.get(i)) != null) {
+                        insertionIndex = i;
+                        break;
+                    }
+                }
+
+                if (groupSize == 1) {
+                    ops.add(insertionIndex, groupedByBlock[groupBegin].op);
+                } else {
+                    assert groupSize > 1;
+                    List<LIRInstruction> moves = new ArrayList<>(groupSize);
+                    for (int i = groupBegin; i < groupEnd; i++) {
+                        moves.add(groupedByBlock[i].op);
+                    }
+                    ops.addAll(insertionIndex, moves);
+                }
+
+                if (groupEnd == groupedByBlock.length) {
+                    break;
+                }
+                groupBegin = groupEnd;
+            }
+            constantLoads = null;
+        }
+    }
+
+    /**
+     * Gets a garbage value for a given kind.
+     */
+    protected Constant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((Kind) kind) {
+            case Boolean:
+                return Constant.FALSE;
+            case Byte:
+                return Constant.forByte((byte) dead);
+            case Char:
+                return Constant.forChar((char) dead);
+            case Short:
+                return Constant.forShort((short) dead);
+            case Int:
+                return Constant.forInt((int) dead);
+            case Double:
+                return Constant.forDouble(Double.longBitsToDouble(dead));
+            case Float:
+                return Constant.forFloat(Float.intBitsToFloat((int) dead));
+            case Long:
+                return Constant.forLong(dead);
+            case Object:
+                return Constant.NULL_OBJECT;
+            default:
+                throw new IllegalArgumentException(kind.toString());
+        }
+    }
+
+    /**
+     * Default implementation: Return the Java stack kind for each stamp.
+     */
+    public PlatformKind getPlatformKind(Stamp stamp) {
+        return stamp.getPlatformKind(this);
+    }
+
+    public PlatformKind getIntegerKind(int bits) {
+        if (bits <= 8) {
+            return Kind.Byte;
+        } else if (bits <= 16) {
+            return Kind.Short;
+        } else if (bits <= 32) {
+            return Kind.Int;
+        } else {
+            assert bits <= 64;
+            return Kind.Long;
+        }
+    }
+
+    public PlatformKind getFloatingKind(int bits) {
+        switch (bits) {
+            case 32:
+                return Kind.Float;
+            case 64:
+                return Kind.Double;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public PlatformKind getObjectKind() {
+        return Kind.Object;
+    }
+
+    public abstract void emitBitCount(Variable result, Value operand);
+
+    public abstract void emitBitScanForward(Variable result, Value operand);
+
+    public abstract void emitBitScanReverse(Variable result, Value operand);
+
+    public abstract void emitByteSwap(Variable result, Value operand);
+
+    public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+    public AbstractBlock<?> getCurrentBlock() {
+        return currentBlock;
+    }
+
+    void setCurrentBlock(AbstractBlock<?> block) {
+        currentBlock = block;
+    }
+
+    public LIRGenerationResult getResult() {
+        return res;
+    }
+
+    public Map<Constant, LoadConstant> getConstantLoads() {
+        return constantLoads;
+    }
+
+    public void setConstantLoads(Map<Constant, LoadConstant> constantLoads) {
+        this.constantLoads = constantLoads;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.gen;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.LIRGenerator.*;
+
+public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
+
+    CodeGenProviders getProviders();
+
+    TargetDescription target();
+
+    MetaAccessProvider getMetaAccess();
+
+    CodeCacheProvider getCodeCache();
+
+    ForeignCallsProvider getForeignCalls();
+
+    AbstractBlock<?> getCurrentBlock();
+
+    LIRGenerationResult getResult();
+
+    boolean hasBlockEnd(AbstractBlock<?> block);
+
+    void doBlockStart(AbstractBlock<?> block);
+
+    void doBlockEnd(AbstractBlock<?> block);
+
+    Map<Constant, LoadConstant> getConstantLoads();
+
+    void setConstantLoads(Map<Constant, LoadConstant> constantLoads);
+
+    Value emitLoad(PlatformKind kind, Value address, LIRFrameState state);
+
+    void emitStore(PlatformKind kind, Value address, Value input, LIRFrameState state);
+
+    void emitNullCheck(Value address, LIRFrameState state);
+
+    Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
+
+    /**
+     * Emit an atomic read-and-add instruction.
+     *
+     * @param address address of the value to be read and written
+     * @param delta the value to be added
+     */
+    default Value emitAtomicReadAndAdd(Value address, Value delta) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emit an atomic read-and-write instruction.
+     *
+     * @param address address of the value to be read and written
+     * @param newValue the new value to be written
+     */
+    default Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state);
+
+    Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
+
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for most
+     * operations, i.e., for commonly used arithmetic, logical, and comparison operations.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    boolean canInlineConstant(Constant c);
+
+    /**
+     * 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.
+     */
+    boolean canStoreConstant(Constant c);
+
+    RegisterAttributes attributes(Register register);
+
+    Variable newVariable(PlatformKind kind);
+
+    Variable emitMove(Value input);
+
+    void emitMove(AllocatableValue dst, Value src);
+
+    /**
+     * Emits an op that loads the address of some raw data.
+     *
+     * @param dst the variable into which the address is loaded
+     * @param data the data to be installed with the generated code
+     */
+    void emitData(AllocatableValue dst, byte[] data);
+
+    Value emitAddress(Value base, long displacement, Value index, int scale);
+
+    Value emitAddress(StackSlot slot);
+
+    void emitMembar(int barriers);
+
+    void emitUnwind(Value operand);
+
+    /**
+     * Called just before register allocation is performed on the LIR owned by this generator.
+     * Overriding implementations of this method must call the overridden method.
+     */
+    void beforeRegisterAllocation();
+
+    void emitIncomingValues(Value[] params);
+
+    /**
+     * Emits a return instruction. Implementations need to insert a move if the input is not in the
+     * correct location.
+     */
+    void emitReturn(Value input);
+
+    AllocatableValue asAllocatable(Value value);
+
+    Variable load(Value value);
+
+    Value loadNonConst(Value value);
+
+    /**
+     * Returns true if the redundant move elimination optimization should be done after register
+     * allocation.
+     */
+    boolean canEliminateRedundantMoves();
+
+    /**
+     * Determines if only oop maps are required for the code generated from the LIR.
+     */
+    boolean needOnlyOopMaps();
+
+    /**
+     * Gets the ABI specific operand used to return a value of a given kind from a method.
+     *
+     * @param kind the kind of value being returned
+     * @return the operand representing the ABI defined location used return a value of kind
+     *         {@code kind}
+     */
+    AllocatableValue resultOperandFor(Kind kind);
+
+    void append(LIRInstruction op);
+
+    void emitJump(LabelRef label);
+
+    void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability);
+
+    void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
+
+    void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+    Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+    Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+    void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value);
+
+    void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+    CallingConvention getCallingConvention();
+
+    void emitBitCount(Variable result, Value operand);
+
+    void emitBitScanForward(Variable result, Value operand);
+
+    void emitBitScanReverse(Variable result, Value operand);
+
+    void emitByteSwap(Variable result, Value operand);
+
+    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
 
 public class BasicInductionVariable extends InductionVariable {
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 public class CountedLoopInfo {
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Fri May 30 15:09:09 2014 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
 
 public class DerivedScaledInductionVariable extends InductionVariable {
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.loop;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.graph.*;
@@ -35,7 +37,7 @@
 
     public InductionVariables(LoopEx loop) {
         this.loop = loop;
-        ivs = new IdentityHashMap<>();
+        ivs = newNodeIdentityMap();
         findDerived(findBasic());
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Fri May 30 15:09:09 2014 +0200
@@ -91,7 +91,7 @@
     }
 
     public LoopBeginNode loopBegin() {
-        return (LoopBeginNode) lirLoop().header.getBeginNode();
+        return (LoopBeginNode) lirLoop().getHeader().getBeginNode();
     }
 
     public FixedNode predecessor() {
@@ -111,10 +111,10 @@
     }
 
     public LoopEx parent() {
-        if (lirLoop.parent == null) {
+        if (lirLoop.getParent() == null) {
             return null;
         }
-        return data.loop(lirLoop.parent);
+        return data.loop(lirLoop.getParent());
     }
 
     public int size() {
@@ -123,7 +123,7 @@
 
     @Override
     public String toString() {
-        return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + lirLoop().depth + ") " + loopBegin();
+        return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + lirLoop().getDepth() + ") " + loopBegin();
     }
 
     private class InvariantPredicate implements NodePredicate {
@@ -237,9 +237,9 @@
             if (b == untilBlock) {
                 continue;
             }
-            if (lirLoop().exits.contains(b)) {
+            if (lirLoop().getExits().contains(b)) {
                 exits.add((LoopExitNode) b.getBeginNode());
-            } else if (lirLoop().blocks.contains(b)) {
+            } else if (lirLoop().getBlocks().contains(b)) {
                 blocks.add(b.getBeginNode());
                 work.addAll(b.getDominated());
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri May 30 15:09:09 2014 +0200
@@ -66,7 +66,7 @@
     }
 
     public boolean contains(Node n) {
-        return nodes().contains(n);
+        return nodes().isMarkedAndGrow(n);
     }
 
     @SuppressWarnings("unchecked")
@@ -96,7 +96,7 @@
         return original;
     }
 
-    public abstract NodeIterable<Node> nodes();
+    public abstract NodeBitMap nodes();
 
     public StructuredGraph graph() {
         LoopEx l;
@@ -155,7 +155,7 @@
     }
 
     protected static NodeBitMap computeNodes(Graph graph, Iterable<BeginNode> blocks, Iterable<LoopExitNode> earlyExits) {
-        final NodeBitMap nodes = graph.createNodeBitMap(true);
+        final NodeBitMap nodes = graph.createNodeBitMap();
         for (BeginNode b : blocks) {
             if (b.isDeleted()) {
                 continue;
@@ -187,7 +187,7 @@
             }
         }
 
-        final NodeBitMap notloopNodes = graph.createNodeBitMap(true);
+        final NodeBitMap notloopNodes = graph.createNodeBitMap();
         for (BeginNode b : blocks) {
             if (b.isDeleted()) {
                 continue;
@@ -302,7 +302,7 @@
     protected void mergeEarlyExits() {
         assert isDuplicate();
         StructuredGraph graph = graph();
-        for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) {
+        for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().getExits())) {
             LoopExitNode loopEarlyExit = (LoopExitNode) earlyExit;
             FixedNode next = loopEarlyExit.next();
             if (loopEarlyExit.isDeleted() || !this.original().contains(loopEarlyExit)) {
@@ -336,8 +336,8 @@
                  *
                  * We now update the original fragment's nodes accordingly:
                  */
-                state.applyToVirtual(node -> original.nodes.clear(node));
-                exitState.applyToVirtual(node -> original.nodes.mark(node));
+                state.applyToVirtual(node -> original.nodes.clearAndGrow(node));
+                exitState.applyToVirtual(node -> original.nodes.markAndGrow(node));
             }
             FrameState finalExitState = exitState;
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,13 @@
  */
 package com.oracle.graal.loop;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
@@ -100,7 +102,7 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
+    public NodeBitMap nodes() {
         if (nodes == null) {
             LoopFragmentWhole whole = loop().whole();
             whole.nodes(); // init nodes bitmap in whole
@@ -114,7 +116,7 @@
                 FrameState exitState = exit.stateAfter();
                 if (exitState != null) {
                     exitState.applyToVirtual(v -> {
-                        if (v.usages().filter(n -> nodes.isMarked(n) && !(n instanceof VirtualState && exitState.isPartOfThisState((VirtualState) n))).isEmpty()) {
+                        if (v.usages().filter(n -> nodes.isMarked(n) && n != exit).isEmpty()) {
                             nodes.clear(v);
                         }
                     });
@@ -201,10 +203,10 @@
         for (LoopExitNode exit : exits()) {
             FrameState exitState = exit.stateAfter();
             if (exitState != null) {
-                exitState.applyToVirtual(v -> usagesToPatch.mark(v));
+                exitState.applyToVirtual(v -> usagesToPatch.markAndGrow(v));
             }
             for (ProxyNode proxy : exit.proxies()) {
-                usagesToPatch.mark(proxy);
+                usagesToPatch.markAndGrow(proxy);
             }
         }
 
@@ -230,7 +232,7 @@
             newPhis.add(newPhi);
             for (Node usage : phi.usages().snapshot()) {
                 // patch only usages that should use the new phi ie usages that were peeled
-                if (usagesToPatch.isMarked(usage)) {
+                if (usagesToPatch.isMarkedAndGrow(usage)) {
                     usage.replaceFirstInput(phi, newPhi);
                 }
             }
@@ -287,7 +289,7 @@
                 reverseEnds.put(duplicate, le);
             }
         }
-        mergedInitializers = new IdentityHashMap<>();
+        mergedInitializers = newNodeIdentityMap();
         BeginNode newExit;
         StructuredGraph graph = graph();
         if (endsToMerge.size() == 1) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideBefore.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideBefore.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.loop;
 
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 
 public class LoopFragmentInsideBefore extends LoopFragmentInside {
@@ -51,8 +50,7 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
-        // TODO Auto-generated method stub
+    public NodeBitMap nodes() {
         return null;
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideFrom.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideFrom.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.loop;
 
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 
 public class LoopFragmentInsideFrom extends LoopFragmentInside {
@@ -51,8 +50,7 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
-        // TODO Auto-generated method stub
+    public NodeBitMap nodes() {
         return null;
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Fri May 30 15:09:09 2014 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 
@@ -55,10 +54,10 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
+    public NodeBitMap nodes() {
         if (nodes == null) {
             Loop<Block> lirLoop = loop().lirLoop();
-            nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.blocks), LoopFragment.toHirExits(lirLoop.exits));
+            nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.getBlocks()), LoopFragment.toHirExits(lirLoop.getExits()));
         }
         return nodes;
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.loop;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.function.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
 
 public abstract class LoopPolicies {
 
@@ -37,12 +38,12 @@
     }
 
     // TODO (gd) change when inversion is available
-    public static boolean shouldPeel(LoopEx loop, NodesToDoubles probabilities) {
+    public static boolean shouldPeel(LoopEx loop, ToDoubleFunction<FixedNode> probabilities) {
         if (loop.detectCounted()) {
             return false;
         }
         LoopBeginNode loopBegin = loop.loopBegin();
-        double entryProbability = probabilities.get(loopBegin.forwardEnd());
+        double entryProbability = probabilities.applyAsDouble(loopBegin.forwardEnd());
         return entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue();
     }
 
@@ -70,10 +71,8 @@
         double maxProbability = 0;
         for (Node successor : controlSplit.successors()) {
             BeginNode branch = (BeginNode) successor;
-            inBranchTotal += loop.nodesInLoopFrom(branch, postDom).cardinality(); // this may count
-                                                                                  // twice because
-                                                                                  // of fall-through
-                                                                                  // in switches
+            // this may count twice because of fall-through in switches
+            inBranchTotal += loop.nodesInLoopFrom(branch, postDom).count();
             double probability = controlSplit.probability(branch);
             if (probability > maxProbability) {
                 maxProbability = probability;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.loop;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.Graph.Mark;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.loop;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
@@ -32,8 +34,8 @@
 
 public class LoopsData {
 
-    private Map<Loop<Block>, LoopEx> lirLoopToEx = new IdentityHashMap<>();
-    private Map<LoopBeginNode, LoopEx> loopBeginToEx = new IdentityHashMap<>();
+    private Map<Loop<Block>, LoopEx> lirLoopToEx = newIdentityMap();
+    private Map<LoopBeginNode, LoopEx> loopBeginToEx = newNodeIdentityMap();
     private ControlFlowGraph cfg;
 
     public LoopsData(final StructuredGraph graph) {
@@ -68,7 +70,7 @@
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o1.lirLoop().depth - o2.lirLoop().depth;
+                return o1.lirLoop().getDepth() - o2.lirLoop().getDepth();
             }
         });
         return loops;
@@ -80,7 +82,7 @@
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o2.lirLoop().depth - o1.lirLoop().depth;
+                return o2.lirLoop().getDepth() - o1.lirLoop().getDepth();
             }
         });
         return loops;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -37,7 +37,7 @@
         if (context.getOptimisticOptimizations().useLoopLimitChecks()) {
             loops.detectedCountedLoops();
             for (LoopEx loop : loops.countedLoops()) {
-                if (loop.lirLoop().children.isEmpty() && loop.counted().getStamp().getBits() <= 32) {
+                if (loop.lirLoop().getChildren().isEmpty() && loop.counted().getStamp().getBits() <= 32) {
                     boolean hasSafepoint = false;
                     for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
                         hasSafepoint |= loopEnd.canSafepoint();
@@ -54,7 +54,7 @@
         for (LoopEx loop : loops.countedLoops()) {
             for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
                 Block b = loops.controlFlowGraph().blockFor(loopEnd);
-                blocks: while (b != loop.lirLoop().header) {
+                blocks: while (b != loop.lirLoop().getHeader()) {
                     assert b != null;
                     for (FixedNode node : b.getNodes()) {
                         if (node instanceof Invoke || node instanceof ForeignCallNode) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.loop.phases;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.function.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 
@@ -37,7 +38,7 @@
     protected void run(StructuredGraph graph) {
         if (graph.hasLoops()) {
             if (LoopPeeling.getValue()) {
-                NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
+                ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
                 LoopsData data = new LoopsData(graph);
                 for (LoopEx loop : data.outterFirst()) {
                     if (LoopPolicies.shouldPeel(loop, probabilities)) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.loop.phases;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Fri May 30 15:09:09 2014 +0200
@@ -293,4 +293,10 @@
         testZeroExtendShort(-1, 1, 0, 0xFFFF);
         testZeroExtendShort(Short.MIN_VALUE, Short.MAX_VALUE, 0, 0xFFFF);
     }
+
+    @Test
+    public void testIllegalJoin() {
+        assertFalse(new IntegerStamp(32, 0, 0xff00, 0, 0xff00).join(new IntegerStamp(32, 1, 0xff, 0x00, 0xff)).isLegal());
+        assertFalse(new IntegerStamp(32, 0x100, 0xff00, 0, 0xff00).join(new IntegerStamp(32, 0, 0xff, 0x00, 0xff)).isLegal());
+    }
 }
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java	Fri May 30 15:09:09 2014 +0200
@@ -26,34 +26,16 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.type.*;
 
-public class ObjectStampJoinTest extends GraalCompilerTest {
-
-    private static class A {
-
-    }
-
-    private static class B extends A {
-
-    }
-
-    private static class C extends B implements I {
+public class ObjectStampJoinTest extends ObjectStampTest {
 
-    }
-
-    private static class D extends A {
-
-    }
-
-    private abstract static class E extends A {
-
-    }
-
-    private interface I {
-
-    }
+    // class A
+    // class B extends A
+    // class C extends B implements I
+    // class D extends A
+    // abstract class E extends A
+    // interface I
 
     @Test
     public void testJoin0() {
@@ -81,7 +63,7 @@
     public void testJoin3() {
         Stamp d = StampFactory.declared(getType(D.class));
         Stamp c = StampFactory.declared(getType(C.class));
-        Assert.assertTrue(ObjectStamp.isObjectAlwaysNull(join(c, d)));
+        Assert.assertTrue(StampTool.isObjectAlwaysNull(join(c, d)));
     }
 
     @Test
@@ -96,9 +78,9 @@
         Stamp dExact = StampFactory.exact(getType(D.class));
         Stamp c = StampFactory.declared(getType(C.class));
         Stamp join = join(c, dExact);
-        Assert.assertTrue(ObjectStamp.isObjectAlwaysNull(join));
-        Assert.assertNull(ObjectStamp.typeOrNull(join));
-        Assert.assertFalse(ObjectStamp.isExactType(join));
+        Assert.assertTrue(StampTool.isObjectAlwaysNull(join));
+        Assert.assertNull(StampTool.typeOrNull(join));
+        Assert.assertFalse(StampTool.isExactType(join));
     }
 
     @Test
@@ -107,8 +89,8 @@
         Stamp alwaysNull = StampFactory.alwaysNull();
         Stamp join = join(alwaysNull, dExactNonNull);
         Assert.assertFalse(join.isLegal());
-        Assert.assertFalse(ObjectStamp.isObjectNonNull(join));
-        Assert.assertFalse(ObjectStamp.isObjectAlwaysNull(join));
+        Assert.assertFalse(StampTool.isObjectNonNull(join));
+        Assert.assertFalse(StampTool.isObjectAlwaysNull(join));
     }
 
     @Test
@@ -116,16 +98,34 @@
         Stamp aExact = StampFactory.exact(getType(A.class));
         Stamp e = StampFactory.declared(getType(E.class));
         Stamp join = join(aExact, e);
-        Assert.assertTrue(ObjectStamp.isObjectAlwaysNull(join));
-        Assert.assertNull(ObjectStamp.typeOrNull(join));
-        Assert.assertFalse(ObjectStamp.isExactType(join));
+        Assert.assertTrue(StampTool.isObjectAlwaysNull(join));
+        Assert.assertNull(StampTool.typeOrNull(join));
+        Assert.assertFalse(StampTool.isExactType(join));
+    }
+
+    @Test
+    public void testJoin8() {
+        Stamp bExact = StampFactory.exactNonNull(getType(B.class));
+        Stamp dExact = StampFactory.exact(getType(D.class));
+        Stamp join = join(bExact, dExact);
+        Assert.assertFalse(join.isLegal());
+    }
+
+    @Test
+    public void testJoin9() {
+        Stamp bExact = StampFactory.exact(getType(B.class));
+        Stamp dExact = StampFactory.exact(getType(D.class));
+        Stamp join = join(bExact, dExact);
+        Assert.assertTrue(StampTool.isObjectAlwaysNull(join));
+        Assert.assertNull(StampTool.typeOrNull(join));
+        Assert.assertNull(StampTool.typeOrNull(join));
     }
 
     @Test
     public void testJoinInterface0() {
         Stamp a = StampFactory.declared(getType(A.class));
-        Stamp b = StampFactory.declared(getType(I.class));
-        Assert.assertNotSame(StampFactory.illegal(Kind.Object), join(a, b));
+        Stamp i = StampFactory.declared(getType(I.class));
+        Assert.assertNotSame(StampFactory.illegal(Kind.Object), join(a, i));
     }
 
     @Test
@@ -145,14 +145,4 @@
         Assert.assertEquals(StampFactory.illegal(Kind.Object), join);
     }
 
-    private static Stamp join(Stamp a, Stamp b) {
-        Stamp ab = a.join(b);
-        Stamp ba = b.join(a);
-        Assert.assertEquals(ab, ba);
-        return ab;
-    }
-
-    private ResolvedJavaType getType(Class<?> clazz) {
-        return getMetaAccess().lookupJavaType(clazz);
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampMeetTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,122 @@
+/*
+ * 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.nodes.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+
+public class ObjectStampMeetTest extends ObjectStampTest {
+
+    // class A
+    // class B extends A
+    // class C extends B implements I
+    // class D extends A
+    // abstract class E extends A
+    // interface I
+
+    @Test
+    public void testMeet0() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp b = StampFactory.declared(getType(B.class));
+        Assert.assertEquals(a, meet(a, b));
+    }
+
+    @Test
+    public void testMeet1() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp aNonNull = StampFactory.declaredNonNull(getType(A.class));
+        Stamp b = StampFactory.declared(getType(B.class));
+        Stamp bNonNull = StampFactory.declaredNonNull(getType(B.class));
+        Assert.assertEquals(a, meet(aNonNull, b));
+        Assert.assertEquals(aNonNull, meet(aNonNull, bNonNull));
+    }
+
+    @Test
+    public void testMeet2() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp aExact = StampFactory.exactNonNull(getType(A.class));
+        Stamp b = StampFactory.declared(getType(B.class));
+        Assert.assertEquals(a, meet(aExact, b));
+    }
+
+    @Test
+    public void testMeet3() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp d = StampFactory.declared(getType(D.class));
+        Stamp c = StampFactory.declared(getType(C.class));
+        Assert.assertEquals(a, meet(c, d));
+    }
+
+    @Test
+    public void testMeet4() {
+        Stamp dExactNonNull = StampFactory.exactNonNull(getType(D.class));
+        Stamp cExactNonNull = StampFactory.exactNonNull(getType(C.class));
+        Stamp aNonNull = StampFactory.declaredNonNull(getType(A.class));
+        Assert.assertEquals(aNonNull, meet(cExactNonNull, dExactNonNull));
+    }
+
+    @Test
+    public void testMeet() {
+        Stamp dExact = StampFactory.exact(getType(D.class));
+        Stamp c = StampFactory.declared(getType(C.class));
+        Stamp a = StampFactory.declared(getType(A.class));
+        Assert.assertEquals(a, meet(dExact, c));
+    }
+
+    @Test
+    public void testMeet6() {
+        Stamp dExactNonNull = StampFactory.exactNonNull(getType(D.class));
+        Stamp alwaysNull = StampFactory.alwaysNull();
+        Stamp dExact = StampFactory.exact(getType(D.class));
+        Assert.assertEquals(dExact, meet(dExactNonNull, alwaysNull));
+    }
+
+    @Test
+    public void testMeet7() {
+        Stamp aExact = StampFactory.exact(getType(A.class));
+        Stamp e = StampFactory.declared(getType(E.class));
+        Stamp a = StampFactory.declared(getType(A.class));
+        Assert.assertEquals(a, meet(aExact, e));
+    }
+
+    @Test
+    public void testMeetInterface0() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp i = StampFactory.declared(getType(I.class));
+        Assert.assertEquals(StampFactory.declared(getType(Object.class)), meet(a, i));
+    }
+
+    @Test
+    public void testMeetIllegal1() {
+        for (Class<?> clazz : new Class<?>[]{A.class, B.class, C.class, D.class, E.class, I.class, Object.class}) {
+            ResolvedJavaType type = getType(clazz);
+            for (Stamp test : new Stamp[]{StampFactory.declared(type), StampFactory.declaredNonNull(type), StampFactory.exact(type), StampFactory.exactNonNull(type)}) {
+                if (!type.isAbstract() || !((ObjectStamp) test).isExactType()) {
+                    Assert.assertEquals("meeting illegal and " + test, test, meet(StampFactory.illegal(Kind.Object), test));
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,74 @@
+/*
+ * 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.nodes.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+
+public class ObjectStampTest extends GraalCompilerTest {
+
+    protected static class A {
+
+    }
+
+    protected static class B extends A {
+
+    }
+
+    protected static class C extends B implements I {
+
+    }
+
+    protected static class D extends A {
+
+    }
+
+    protected abstract static class E extends A {
+
+    }
+
+    protected interface I {
+
+    }
+
+    protected static Stamp join(Stamp a, Stamp b) {
+        Stamp ab = a.join(b);
+        Stamp ba = b.join(a);
+        Assert.assertEquals(ab, ba);
+        return ab;
+    }
+
+    protected static Stamp meet(Stamp a, Stamp b) {
+        Stamp ab = a.meet(b);
+        Stamp ba = b.meet(a);
+        Assert.assertEquals(ab, ba);
+        return ab;
+    }
+
+    protected ResolvedJavaType getType(Class<?> clazz) {
+        return getMetaAccess().lookupJavaType(clazz);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,8 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This node represents an unconditional explicit request for immediate deoptimization.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,9 +24,9 @@
 
 import java.util.*;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public abstract class AbstractEndNode extends FixedNode implements IterableNodeType, LIRLowerable {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, GuardingNode {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri May 30 15:09:09 2014 +0200
@@ -32,7 +32,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
 public class BeginNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, GuardingNode, AnchoringNode, IterableNodeType {
@@ -70,12 +70,8 @@
     }
 
     public static BeginNode prevBegin(FixedNode from) {
-        Node prevBegin = from;
-        while (prevBegin != null) {
-            if (prevBegin instanceof BeginNode) {
-                return (BeginNode) prevBegin;
-            }
-            prevBegin = prevBegin.predecessor();
+        for (BeginNode begin : GraphUtil.predecessorIterable(from).filter(BeginNode.class)) {
+            return begin;
         }
         return null;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public abstract class BinaryLogicNode extends LogicNode implements LIRLowerable, MemoryArithmeticLIRLowerable {
-
-    @Input private ValueNode x;
-    @Input private ValueNode y;
-
-    public ValueNode x() {
-        return x;
-    }
-
-    public ValueNode y() {
-        return y;
-    }
-
-    protected void setX(ValueNode x) {
-        updateUsages(this.x, x);
-        this.x = x;
-    }
-
-    protected void setY(ValueNode y) {
-        updateUsages(this.y, y);
-        this.y = y;
-    }
-
-    public BinaryLogicNode(ValueNode x, ValueNode y) {
-        assert x != null && y != null && x.getKind() == y.getKind();
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
-        return super.verify();
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-    }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return false;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable {
+
+    @Input private ValueNode x;
+    @Input private ValueNode y;
+
+    public ValueNode x() {
+        return x;
+    }
+
+    public ValueNode y() {
+        return y;
+    }
+
+    protected void setX(ValueNode x) {
+        updateUsages(this.x, x);
+        this.x = x;
+    }
+
+    protected void setY(ValueNode y) {
+        updateUsages(this.y, y);
+        this.y = y;
+    }
+
+    public BinaryOpLogicNode(ValueNode x, ValueNode y) {
+        assert x != null && y != null && x.getKind() == y.getKind();
+        this.x = x;
+        this.y = y;
+    }
+
+    public abstract TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY);
+
+    @Override
+    public boolean verify() {
+        assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
+        return super.verify();
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        switch (evaluate(tool.getConstantReflection(), x(), y())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A node that results in a platform dependent breakpoint instruction being emitted. A number of
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Extension})
 public abstract class CallTargetNode extends ValueNode implements LIRLowerable {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(nameTemplate = "ConditionAnchor(!={p#negated})", allowedUsageTypes = {InputType.Guard})
 public final class ConditionAnchorNode extends FixedWithNextNode implements Canonicalizable, Lowerable, GuardingNode {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri May 30 15:09:09 2014 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code ConstantNode} represents a {@link Constant constant}.
@@ -154,13 +153,7 @@
     }
 
     public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
-        if (stamp instanceof PrimitiveStamp) {
-            return forPrimitive(stamp, constant, graph);
-        } else {
-            ConstantNode ret = forConstant(constant, metaAccess, graph);
-            assert ret.stamp().isCompatible(stamp);
-            return ret;
-        }
+        return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess)));
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -63,7 +63,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, this);
+        gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, gen.state(this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -55,7 +55,7 @@
     }
 
     public void generate(NodeLIRBuilderTool generator) {
-        generator.getLIRGeneratorTool().emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), this);
+        generator.getLIRGeneratorTool().emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), generator.state(this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,4 +44,9 @@
     public FixedWithNextNode(Stamp stamp) {
         super(stamp);
     }
+
+    @Override
+    public FixedWithNextNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri May 30 15:09:09 2014 +0200
@@ -51,41 +51,6 @@
 
     private boolean duringCall;
 
-    /**
-     * This BCI should be used for frame states that are built for code with no meaningful BCI.
-     */
-    public static final int UNKNOWN_BCI = -5;
-
-    /**
-     * The BCI for the exception unwind block, i.e., the block containing the {@link UnwindNode}.
-     * This block and node is synthetic and has no representation in bytecode.
-     */
-    public static final int UNWIND_BCI = -1;
-
-    /**
-     * When a node whose frame state has this BCI value is inlined, its frame state will be replaced
-     * with the frame state before the inlined invoke node.
-     */
-    public static final int BEFORE_BCI = -2;
-
-    /**
-     * When a node whose frame state has this BCI value is inlined, its frame state will be replaced
-     * with the frame state {@linkplain Invoke#stateAfter() after} the inlined invoke node.
-     */
-    public static final int AFTER_BCI = -3;
-
-    /**
-     * When a node whose frame state has this BCI value is inlined, its frame state will be replaced
-     * with the frame state at the exception edge of the inlined invoke node.
-     */
-    public static final int AFTER_EXCEPTION_BCI = -4;
-
-    /**
-     * This BCI should be used for frame states that cannot be the target of a deoptimization, like
-     * snippet frame states.
-     */
-    public static final int INVALID_FRAMESTATE_BCI = -6;
-
     @Input(InputType.State) private FrameState outerFrameState;
 
     /**
@@ -130,8 +95,8 @@
         this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
         this.rethrowException = rethrowException;
         this.duringCall = duringCall;
-        assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
-        assert values.size() - localsSize - stackSize == monitorIds.size();
+        assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack";
+        assert this.locksSize() == this.monitorIds.size();
     }
 
     /**
@@ -141,7 +106,8 @@
      */
     public FrameState(int bci) {
         this(null, bci, Collections.<ValueNode> emptyList(), 0, 0, false, false, Collections.<MonitorIdNode> emptyList(), Collections.<EscapeObjectState> emptyList());
-        assert bci == BEFORE_BCI || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == UNKNOWN_BCI || bci == INVALID_FRAMESTATE_BCI;
+        assert bci == BytecodeFrame.BEFORE_BCI || bci == BytecodeFrame.AFTER_BCI || bci == BytecodeFrame.AFTER_EXCEPTION_BCI || bci == BytecodeFrame.UNKNOWN_BCI ||
+                        bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
     }
 
     public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks, MonitorIdNode[] monitorIds, boolean rethrowException, boolean duringCall) {
@@ -254,6 +220,19 @@
      * correctly in slot encoding: a long or double will be followed by a null slot.
      */
     public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
+        return duplicateModified(newBci, method, newRethrowException, popKind, pushedValues);
+    }
+
+    /**
+     * Creates a copy of this frame state with one stack element of type popKind popped from the
+     * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted
+     * correctly in slot encoding: a long or double will be followed by a null slot.
+     */
+    public FrameState duplicateModified(Kind popKind, ValueNode... pushedValues) {
+        return duplicateModified(bci, method, rethrowException, popKind, pushedValues);
+    }
+
+    private FrameState duplicateModified(int newBci, ResolvedJavaMethod newMethod, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
         ArrayList<ValueNode> copy = new ArrayList<>(values.subList(0, localsSize + stackSize));
         if (popKind != Kind.Void) {
             if (stackAt(stackSize() - 1) == null) {
@@ -272,7 +251,7 @@
         int newStackSize = copy.size() - localsSize;
         copy.addAll(values.subList(localsSize + stackSize, values.size()));
 
-        FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
+        FrameState other = graph().add(new FrameState(newMethod, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -401,13 +380,26 @@
                 properties.put("sourceLine", ste.getLineNumber());
             }
         }
+        if (bci == BytecodeFrame.AFTER_BCI) {
+            properties.put("bci", "AFTER_BCI");
+        } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+            properties.put("bci", "AFTER_EXCEPTION_BCI");
+        } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            properties.put("bci", "INVALID_FRAMESTATE_BCI");
+        } else if (bci == BytecodeFrame.BEFORE_BCI) {
+            properties.put("bci", "BEFORE_BCI");
+        } else if (bci == BytecodeFrame.UNKNOWN_BCI) {
+            properties.put("bci", "UNKNOWN_BCI");
+        } else if (bci == BytecodeFrame.UNWIND_BCI) {
+            properties.put("bci", "UNWIND_BCI");
+        }
         properties.put("locksSize", values.size() - stackSize - localsSize);
         return properties;
     }
 
     @Override
     public boolean verify() {
-        assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks");
+        assertTrue(locksSize() == monitorIds.size(), "mismatch in number of locks");
         for (ValueNode value : values) {
             assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
             assertTrue(value == null || value instanceof VirtualObjectNode || (value.getKind() != Kind.Void), "unexpected value: %s", value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A guard is a node that deoptimizes based on a conditional expression. Guards are not attached to
@@ -107,7 +107,8 @@
         } else if (condition() instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition();
             if (c.getValue() != negated) {
-                return graph().start();
+                this.replaceAtUsages(null);
+                return null;
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(nameTemplate = "GuardPhi({i#values})", allowedUsageTypes = {InputType.Guard})
 public class GuardPhiNode extends PhiNode implements GuardingNode {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,13 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Guard})
-public class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy {
+public class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable {
 
     @Input(InputType.Guard) private GuardingNode value;
 
@@ -38,6 +38,10 @@
     }
 
     @Override
+    public void generate(NodeLIRBuilderTool generator) {
+    }
+
+    @Override
     public ValueNode value() {
         return value.asNode();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Fri May 30 15:09:09 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A node that changes the type of its input, usually narrowing it. For example, a GuardedValueNode
@@ -39,10 +38,12 @@
 public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
+    private final Stamp piStamp;
 
     public GuardedValueNode(ValueNode object, GuardingNode guard, Stamp stamp) {
         super(stamp, guard);
         this.object = object;
+        this.piStamp = stamp;
     }
 
     public GuardedValueNode(ValueNode object, GuardingNode guard) {
@@ -62,10 +63,10 @@
 
     @Override
     public boolean inferStamp() {
-        if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
-            return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp()));
+        if (piStamp instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
+            return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) piStamp));
         }
-        return updateStamp(object().stamp().join(stamp()));
+        return updateStamp(object().stamp().join(piStamp));
     }
 
     @Override
@@ -78,7 +79,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (getGuard() == graph().start() || getGuard() == null) {
+        if (getGuard() == null) {
             if (stamp().equals(object().stamp())) {
                 return object();
             } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri May 30 15:09:09 2014 +0200
@@ -41,6 +41,7 @@
     @Input(InputType.Condition) private LogicNode condition;
     private final DeoptimizationReason reason;
     private final DeoptimizationAction action;
+    private final Stamp piStamp;
     private boolean negated;
 
     public ValueNode object() {
@@ -51,6 +52,18 @@
         return condition;
     }
 
+    public boolean isNegated() {
+        return negated;
+    }
+
+    public DeoptimizationReason getReason() {
+        return reason;
+    }
+
+    public DeoptimizationAction getAction() {
+        return action;
+    }
+
     /**
      * Constructor for {@link #guardingNonNull(Object)} node intrinsic.
      */
@@ -69,6 +82,7 @@
     public GuardingPiNode(ValueNode object, ValueNode condition, boolean negateCondition, DeoptimizationReason reason, DeoptimizationAction action, Stamp stamp) {
         super(stamp);
         assert stamp != null;
+        this.piStamp = stamp;
         this.object = object;
         this.condition = (LogicNode) condition;
         this.reason = reason;
@@ -88,14 +102,14 @@
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this) != null && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
+        if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(stamp().join(object().stamp()));
+        return updateStamp(piStamp.join(object().stamp()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/HeapAccess.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/HeapAccess.java	Fri May 30 15:09:09 2014 +0200
@@ -49,9 +49,4 @@
      * Gets the write barrier type for that particular access.
      */
     BarrierType getBarrierType();
-
-    /**
-     * Returns whether or not the heap access is a compressed pointer candidate.
-     */
-    boolean isCompressible();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
@@ -34,17 +35,15 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 /**
  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
  * of a comparison.
  */
-public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
 
     @Successor private BeginNode trueSuccessor;
     @Successor private BeginNode falseSuccessor;
@@ -133,11 +132,6 @@
     }
 
     @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return gen.emitIfMemory(this, access);
-    }
-
-    @Override
     public boolean verify() {
         assertTrue(condition() != null, "missing condition");
         assertTrue(trueSuccessor() != null, "missing trueSuccessor");
@@ -155,61 +149,27 @@
             LogicNegationNode negation = (LogicNegationNode) condition();
             IfNode newIfNode = graph().add(new IfNode(negation.getInput(), falseSucc, trueSucc, 1 - trueSuccessorProbability));
             predecessor().replaceFirstSuccessor(this, newIfNode);
-            this.safeDelete();
+            GraphUtil.killWithUnusedFloatingInputs(this);
             return;
         }
-        if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
-            // push similar nodes upwards through the if, thereby deduplicating them
-            do {
-                BeginNode trueSucc = trueSuccessor();
-                BeginNode falseSucc = falseSuccessor();
-                if (trueSucc.getClass() == BeginNode.class && falseSucc.getClass() == BeginNode.class && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
-                    FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
-                    FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
-                    NodeClass nodeClass = trueNext.getNodeClass();
-                    if (trueNext.getClass() == falseNext.getClass()) {
-                        if (nodeClass.inputsEqual(trueNext, falseNext) && nodeClass.valueEqual(trueNext, falseNext)) {
-                            falseNext.replaceAtUsages(trueNext);
-                            graph().removeFixed(falseNext);
-                            FixedNode next = trueNext.next();
-                            trueNext.setNext(null);
-                            trueNext.replaceAtPredecessor(next);
-                            graph().addBeforeFixed(this, trueNext);
-                            for (Node usage : trueNext.usages().snapshot()) {
-                                if (usage.getNodeClass().valueNumberable() && !usage.getNodeClass().isLeafNode()) {
-                                    Node newNode = graph().findDuplicate(usage);
-                                    if (newNode != null) {
-                                        usage.replaceAtUsages(newNode);
-                                        usage.safeDelete();
-                                    }
-                                }
-                                if (usage.isAlive()) {
-                                    tool.addToWorkList(usage);
-                                }
-                            }
-                            continue;
-                        }
-                    }
-                }
-            } while (false);
-        }
-
         if (condition() instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition();
             if (c.getValue()) {
                 tool.deleteBranch(falseSuccessor());
                 tool.addToWorkList(trueSuccessor());
                 graph().removeSplit(this, trueSuccessor());
-                return;
             } else {
                 tool.deleteBranch(trueSuccessor());
                 tool.addToWorkList(falseSuccessor());
                 graph().removeSplit(this, falseSuccessor());
-                return;
             }
-        } else if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
+            return;
+        }
+        if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
 
-            if (removeOrMaterializeIf(tool)) {
+            pushNodesThroughIf(tool);
+
+            if (checkForUnsignedCompare(tool) || removeOrMaterializeIf(tool)) {
                 return;
             }
         }
@@ -226,7 +186,7 @@
                 // Reordering of those two if statements is beneficial from the point of view of
                 // their probabilities.
                 if (prepareForSwap(tool.getConstantReflection(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) {
-                    // Reording is allowed from (if1 => begin => if2) to (if2 => begin => if1).
+                    // Reordering is allowed from (if1 => begin => if2) to (if2 => begin => if1).
                     assert intermediateBegin.next() == nextIf;
                     BeginNode bothFalseBegin = nextIf.falseSuccessor();
                     nextIf.setFalseSuccessor(null);
@@ -250,6 +210,144 @@
         }
     }
 
+    private void pushNodesThroughIf(SimplifierTool tool) {
+        assert trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty();
+        // push similar nodes upwards through the if, thereby deduplicating them
+        do {
+            BeginNode trueSucc = trueSuccessor();
+            BeginNode falseSucc = falseSuccessor();
+            if (trueSucc.getClass() == BeginNode.class && falseSucc.getClass() == BeginNode.class && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
+                FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
+                FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
+                NodeClass nodeClass = trueNext.getNodeClass();
+                if (trueNext.getClass() == falseNext.getClass()) {
+                    if (nodeClass.inputsEqual(trueNext, falseNext) && nodeClass.valueEqual(trueNext, falseNext)) {
+                        falseNext.replaceAtUsages(trueNext);
+                        graph().removeFixed(falseNext);
+                        FixedNode next = trueNext.next();
+                        trueNext.setNext(null);
+                        trueNext.replaceAtPredecessor(next);
+                        graph().addBeforeFixed(this, trueNext);
+                        for (Node usage : trueNext.usages().snapshot()) {
+                            if (usage.getNodeClass().valueNumberable() && !usage.getNodeClass().isLeafNode()) {
+                                Node newNode = graph().findDuplicate(usage);
+                                if (newNode != null) {
+                                    usage.replaceAtUsages(newNode);
+                                    usage.safeDelete();
+                                }
+                            }
+                            if (usage.isAlive()) {
+                                tool.addToWorkList(usage);
+                            }
+                        }
+                        continue;
+                    }
+                }
+            }
+        } while (false);
+    }
+
+    /**
+     * Recognize a couple patterns that can be merged into an unsigned compare.
+     *
+     * @param tool
+     * @return true if a replacement was done.
+     */
+    private boolean checkForUnsignedCompare(SimplifierTool tool) {
+        assert trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty();
+        if (condition() instanceof IntegerLessThanNode) {
+            IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
+            Constant y = lessThan.y().stamp().asConstant();
+            if (y != null && y.asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
+                IfNode ifNode2 = (IfNode) falseSuccessor().next();
+                if (ifNode2.condition() instanceof IntegerLessThanNode) {
+                    IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
+                    BeginNode falseSucc = ifNode2.falseSuccessor();
+                    BeginNode trueSucc = ifNode2.trueSuccessor();
+                    IntegerBelowThanNode below = null;
+                    /*
+                     * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
+                     * <positive> into an unsigned compare.
+                     */
+                    if (lessThan2.x() == lessThan.x() && lessThan2.y().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.y().stamp()).isPositive() &&
+                                    sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
+                        below = graph().unique(new IntegerBelowThanNode(lessThan2.x(), lessThan2.y()));
+                        // swap direction
+                        BeginNode tmp = falseSucc;
+                        falseSucc = trueSucc;
+                        trueSucc = tmp;
+                    } else if (lessThan2.y() == lessThan.x() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
+                        /*
+                         * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
+                         * !(<positive> > x), into x <| positive + 1. This can only be done for
+                         * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
+                         * appear to be interesting.
+                         */
+                        Constant positive = lessThan2.x().asConstant();
+                        if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getKind().getMaxValue()) {
+                            ConstantNode newLimit = ConstantNode.forIntegerKind(positive.getKind(), positive.asLong() + 1, graph());
+                            below = graph().unique(new IntegerBelowThanNode(lessThan.x(), newLimit));
+                        }
+                    }
+                    if (below != null) {
+                        ifNode2.setTrueSuccessor(null);
+                        ifNode2.setFalseSuccessor(null);
+
+                        IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
+                        // Remove the < 0 test.
+                        tool.deleteBranch(trueSuccessor);
+                        graph().removeSplit(this, falseSuccessor);
+
+                        // Replace the second test with the new one.
+                        ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
+                        ifNode2.safeDelete();
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check it these two blocks end up at the same place. Meeting at the same merge, or
+     * deoptimizing in the same way.
+     */
+    private static boolean sameDestination(BeginNode succ1, BeginNode succ2) {
+        Node next1 = succ1.next();
+        Node next2 = succ2.next();
+        if (next1 instanceof EndNode && next2 instanceof EndNode) {
+            EndNode end1 = (EndNode) next1;
+            EndNode end2 = (EndNode) next2;
+            if (end1.merge() == end2.merge()) {
+                // They go to the same MergeNode
+                return true;
+            }
+        } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
+            DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
+            DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
+            if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) {
+                // Same deoptimization reason and action.
+                return true;
+            }
+        } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) {
+            LoopExitNode exit1 = (LoopExitNode) next1;
+            LoopExitNode exit2 = (LoopExitNode) next2;
+            if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) {
+                // Exit the same loop and end up at the same place.
+                return true;
+            }
+        } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) {
+            ReturnNode exit1 = (ReturnNode) next1;
+            ReturnNode exit2 = (ReturnNode) next2;
+            if (exit1.result() == exit2.result()) {
+                // Exit the same loop and end up at the same place.
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static boolean prepareForSwap(ConstantReflectionProvider constantReflection, LogicNode a, LogicNode b, double probabilityA, double probabilityB) {
         if (a instanceof InstanceOfNode) {
             InstanceOfNode instanceOfA = (InstanceOfNode) a;
@@ -380,34 +478,28 @@
      * @return true if a transformation was made, false otherwise
      */
     private boolean removeOrMaterializeIf(SimplifierTool tool) {
+        assert trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty();
         if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
             AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
             MergeNode merge = trueEnd.merge();
-            if (merge == falseEnd.merge() && merge.forwardEndCount() == 2 && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
+            if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
                 Iterator<PhiNode> phis = merge.phis().iterator();
                 if (!phis.hasNext()) {
-                    // empty if construct with no phis: remove it
-                    removeEmptyIf(tool);
+                    tool.addToWorkList(condition());
+                    removeThroughFalseBranch(tool);
                     return true;
                 } else {
                     PhiNode singlePhi = phis.next();
                     if (!phis.hasNext()) {
                         // one phi at the merge of an otherwise empty if construct: try to convert
                         // into a MaterializeNode
-                        boolean inverted = trueEnd == merge.forwardEndAt(1);
-                        ValueNode trueValue = singlePhi.valueAt(inverted ? 1 : 0);
-                        ValueNode falseValue = singlePhi.valueAt(inverted ? 0 : 1);
-                        if (trueValue.getKind() != falseValue.getKind()) {
-                            return false;
-                        }
-                        if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
-                            return false;
-                        }
+                        ValueNode trueValue = singlePhi.valueAt(trueEnd);
+                        ValueNode falseValue = singlePhi.valueAt(falseEnd);
                         ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
                         if (conditional != null) {
-                            graph().replaceFloating(singlePhi, conditional);
-                            removeEmptyIf(tool);
+                            singlePhi.setValueAt(trueEnd, conditional);
+                            removeThroughFalseBranch(tool);
                             return true;
                         }
                     }
@@ -421,12 +513,6 @@
             ValueNode falseValue = falseEnd.result();
             ConditionalNode conditional = null;
             if (trueValue != null) {
-                if (trueValue.getKind() != falseValue.getKind()) {
-                    return false;
-                }
-                if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
-                    return false;
-                }
                 conditional = canonicalizeConditionalCascade(trueValue, falseValue);
                 if (conditional == null) {
                     return false;
@@ -440,7 +526,19 @@
         return false;
     }
 
+    protected void removeThroughFalseBranch(SimplifierTool tool) {
+        BeginNode trueBegin = trueSuccessor();
+        graph().removeSplitPropagate(this, trueBegin, tool);
+        tool.addToWorkList(trueBegin);
+    }
+
     private ConditionalNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) {
+        if (trueValue.getKind() != falseValue.getKind()) {
+            return null;
+        }
+        if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
+            return null;
+        }
         if (trueValue.isConstant() && falseValue.isConstant()) {
             return graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
         } else {
@@ -524,6 +622,11 @@
      * @return true if a transformation was made, false otherwise
      */
     private boolean removeIntermediateMaterialization(SimplifierTool tool) {
+        if (!(predecessor() instanceof MergeNode) || predecessor() instanceof LoopBeginNode) {
+            return false;
+        }
+        MergeNode merge = (MergeNode) predecessor();
+
         if (!(condition() instanceof CompareNode)) {
             return false;
         }
@@ -533,16 +636,6 @@
             return false;
         }
 
-        if (!(predecessor() instanceof MergeNode)) {
-            return false;
-        }
-
-        if (predecessor() instanceof LoopBeginNode) {
-            return false;
-        }
-
-        MergeNode merge = (MergeNode) predecessor();
-
         // Only consider merges with a single usage that is both a phi and an operand of the
         // comparison
         NodeIterable<Node> mergeUsages = merge.usages();
@@ -606,6 +699,18 @@
         connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool);
         connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool);
 
+        if (this.trueSuccessorProbability == 0.0) {
+            for (AbstractEndNode endNode : trueEnds) {
+                propagateZeroProbability(endNode);
+            }
+        }
+
+        if (this.trueSuccessorProbability == 1.0) {
+            for (AbstractEndNode endNode : falseEnds) {
+                propagateZeroProbability(endNode);
+            }
+        }
+
         /*
          * Remove obsolete ends only after processing all ends, otherwise oldTrueSuccessor or
          * oldFalseSuccessor might have been removed if it is a LoopExitNode.
@@ -627,6 +732,42 @@
         return true;
     }
 
+    private void propagateZeroProbability(FixedNode startNode) {
+        Node prev = null;
+        for (FixedNode node : GraphUtil.predecessorIterable(startNode)) {
+            if (node instanceof IfNode) {
+                IfNode ifNode = (IfNode) node;
+                if (ifNode.trueSuccessor() == prev) {
+                    if (ifNode.trueSuccessorProbability == 0.0) {
+                        return;
+                    } else if (ifNode.trueSuccessorProbability == 1.0) {
+                        continue;
+                    } else {
+                        ifNode.setTrueSuccessorProbability(0.0);
+                        return;
+                    }
+                } else if (ifNode.falseSuccessor() == prev) {
+                    if (ifNode.trueSuccessorProbability == 1.0) {
+                        return;
+                    } else if (ifNode.trueSuccessorProbability == 0.0) {
+                        continue;
+                    } else {
+                        ifNode.setTrueSuccessorProbability(1.0);
+                        return;
+                    }
+                } else {
+                    throw new GraalInternalError("Illegal state");
+                }
+            } else if (node instanceof MergeNode && !(node instanceof LoopBeginNode)) {
+                for (AbstractEndNode endNode : ((MergeNode) node).cfgPredecessors()) {
+                    propagateZeroProbability(endNode);
+                }
+                return;
+            }
+            prev = node;
+        }
+    }
+
     private static boolean checkFrameState(FixedNode start) {
         FixedNode node = start;
         while (true) {
@@ -738,38 +879,4 @@
 
         return null;
     }
-
-    private void removeEmptyIf(SimplifierTool tool) {
-        BeginNode originalTrueSuccessor = trueSuccessor();
-        BeginNode originalFalseSuccessor = falseSuccessor();
-        assert originalTrueSuccessor.next() instanceof AbstractEndNode && originalFalseSuccessor.next() instanceof AbstractEndNode;
-
-        AbstractEndNode trueEnd = (AbstractEndNode) originalTrueSuccessor.next();
-        AbstractEndNode falseEnd = (AbstractEndNode) originalFalseSuccessor.next();
-        assert trueEnd.merge() == falseEnd.merge();
-
-        FixedWithNextNode pred = (FixedWithNextNode) predecessor();
-        MergeNode merge = trueEnd.merge();
-        merge.prepareDelete(pred);
-        assert merge.usages().isEmpty();
-        originalTrueSuccessor.prepareDelete();
-        originalFalseSuccessor.prepareDelete();
-
-        FixedNode next = merge.next();
-        FrameState state = merge.stateAfter();
-        merge.setNext(null);
-        setTrueSuccessor(null);
-        setFalseSuccessor(null);
-        pred.setNext(next);
-        safeDelete();
-        originalTrueSuccessor.safeDelete();
-        originalFalseSuccessor.safeDelete();
-        merge.safeDelete();
-        trueEnd.safeDelete();
-        falseEnd.safeDelete();
-        if (state != null) {
-            tool.removeIfUnused(state);
-        }
-        tool.addToWorkList(next);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Fri May 30 15:09:09 2014 +0200
@@ -43,6 +43,6 @@
 
     @Override
     public String targetName() {
-        return "Indirect#" + ((JavaMethod) target()).getName();
+        return MetaUtil.format("Indirect#%h.%n", target());
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,9 +23,9 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Nodes of this type are inserted into the graph to denote points of interest to debugging.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Fri May 30 15:09:09 2014 +0200
@@ -25,7 +25,9 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, GuardedNode {
 
@@ -78,4 +80,23 @@
     default ResolvedJavaType getContextType() {
         return getContextMethod().getDeclaringClass();
     }
+
+    @Override
+    default void computeStateDuring(FrameState stateAfter) {
+        FrameState newStateDuring = stateAfter.duplicateModified(bci(), stateAfter.rethrowException(), asNode().getKind());
+        newStateDuring.setDuringCall(true);
+        setStateDuring(newStateDuring);
+    }
+
+    default ValueNode getReceiver() {
+        return callTarget().arguments().get(0);
+    }
+
+    default ResolvedJavaType getReceiverType() {
+        ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver());
+        if (receiverType == null) {
+            receiverType = ((MethodCallTargetNode) callTarget()).targetMethod().getDeclaringClass();
+        }
+        return receiverType;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -36,7 +36,7 @@
  * The {@code InvokeNode} represents all kinds of method calls.
  */
 @NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}", allowedUsageTypes = {InputType.Memory})
-public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
+public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single, IterableNodeType {
 
     @Input(InputType.Extension) private CallTargetNode callTarget;
     @Input(InputType.State) private FrameState stateDuring;
@@ -96,12 +96,15 @@
 
     @Override
     public boolean isAllowedUsageType(InputType type) {
-        if (getKind() != Kind.Void) {
-            if (callTarget instanceof MethodCallTargetNode && ((MethodCallTargetNode) callTarget).targetMethod().getAnnotation(NodeIntrinsic.class) != null) {
-                return true;
+        if (!super.isAllowedUsageType(type)) {
+            if (getKind() != Kind.Void) {
+                if (callTarget instanceof MethodCallTargetNode && ((MethodCallTargetNode) callTarget).targetMethod().getAnnotation(NodeIntrinsic.class) != null) {
+                    return true;
+                }
             }
+            return false;
         }
-        return super.isAllowedUsageType(type);
+        return true;
     }
 
     @Override
@@ -185,13 +188,6 @@
     }
 
     @Override
-    public void computeStateDuring(FrameState stateAfter) {
-        FrameState newStateDuring = stateAfter.duplicateModified(bci(), stateAfter.rethrowException(), getKind());
-        newStateDuring.setDuringCall(true);
-        setStateDuring(newStateDuring);
-    }
-
-    @Override
     public GuardingNode getGuard() {
         return guard;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri May 30 15:09:09 2014 +0200
@@ -37,7 +37,7 @@
     private static final double EXCEPTION_PROBA = 1e-5;
 
     @Successor private BeginNode next;
-    @Successor private DispatchBeginNode exceptionEdge;
+    @Successor private BeginNode exceptionEdge;
     @Input(InputType.Extension) private CallTargetNode callTarget;
     @Input(InputType.State) private FrameState stateDuring;
     @Input(InputType.State) private FrameState stateAfter;
@@ -47,7 +47,7 @@
     private boolean useForInlining;
     private double exceptionProbability;
 
-    public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci) {
+    public InvokeWithExceptionNode(CallTargetNode callTarget, BeginNode exceptionEdge, int bci) {
         super(callTarget.returnStamp());
         this.exceptionEdge = exceptionEdge;
         this.bci = bci;
@@ -57,11 +57,11 @@
         this.exceptionProbability = EXCEPTION_PROBA;
     }
 
-    public DispatchBeginNode exceptionEdge() {
+    public BeginNode exceptionEdge() {
         return exceptionEdge;
     }
 
-    public void setExceptionEdge(DispatchBeginNode x) {
+    public void setExceptionEdge(BeginNode x) {
         updatePredecessor(exceptionEdge, x);
         exceptionEdge = x;
     }
@@ -223,13 +223,6 @@
     }
 
     @Override
-    public void computeStateDuring(FrameState tempStateAfter) {
-        FrameState newStateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), getKind());
-        newStateDuring.setDuringCall(true);
-        setStateDuring(newStateDuring);
-    }
-
-    @Override
     public GuardingNode getGuard() {
         return guard;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,9 +24,9 @@
 
 import static com.oracle.graal.graph.InputType.*;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {Condition})
 public abstract class LogicNode extends FloatingNode {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,10 +25,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Extension})
 public abstract class MemoryMapNode extends FloatingNode {
@@ -41,5 +41,5 @@
 
     public abstract Set<LocationIdentity> getLocations();
 
-    public abstract void replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode);
+    public abstract boolean replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,9 +23,9 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code PhiNode} represents the merging of dataflow in the memory graph.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class MemoryProxyNode extends ProxyNode implements MemoryProxy, LIRLowerable {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -107,7 +107,7 @@
         ends.clear();
     }
 
-    public NodeIterable<AbstractEndNode> forwardEnds() {
+    public NodeInputList<AbstractEndNode> forwardEnds() {
         return ends;
     }
 
@@ -155,7 +155,7 @@
                 return;
             }
             for (PhiNode phi : phis()) {
-                if (phi.usages().filter(isNotA(FrameState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
+                if (phi.usages().filter(isNotA(VirtualState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
                     return;
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Fri May 30 15:09:09 2014 +0200
@@ -82,6 +82,10 @@
         values().set(i, x);
     }
 
+    public void setValueAt(AbstractEndNode end, ValueNode x) {
+        setValueAt(merge().phiPredecessorIndex(end), x);
+    }
+
     public ValueNode valueAt(AbstractEndNode pred) {
         return valueAt(merge().phiPredecessorIndex(pred));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri May 30 15:09:09 2014 +0200
@@ -43,6 +43,7 @@
 public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
+    private final Stamp piStamp;
 
     public ValueNode object() {
         return object;
@@ -50,16 +51,18 @@
 
     public PiNode(ValueNode object, Stamp stamp) {
         super(stamp);
+        this.piStamp = stamp;
         this.object = object;
     }
 
     public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
         super(stamp, (GuardingNode) anchor);
         this.object = object;
+        this.piStamp = stamp;
     }
 
     public PiNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
-        this(object, StampFactory.object(toType, exactType, nonNull || ObjectStamp.isObjectNonNull(object.stamp())));
+        this(object, StampFactory.object(toType, exactType, nonNull || StampTool.isObjectNonNull(object.stamp())));
     }
 
     @Override
@@ -71,22 +74,29 @@
 
     @Override
     public boolean inferStamp() {
-        if (stamp() == StampFactory.forNodeIntrinsic()) {
+        if (piStamp == StampFactory.forNodeIntrinsic()) {
             return false;
         }
-        return updateStamp(stamp().join(object().stamp()));
+        if (piStamp instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
+            return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) piStamp));
+        }
+        return updateStamp(piStamp.join(object().stamp()));
     }
 
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this) != null && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
+        if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
+        if (stamp() == StampFactory.forNodeIntrinsic()) {
+            /* The actual stamp has not been set yet. */
+            return this;
+        }
         inferStamp();
         if (stamp().equals(object().stamp())) {
             return object();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public final class ReturnNode extends ControlSinkNode implements LIRLowerable, IterableNodeType {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Marks a position in the graph where a safepoint should be emitted.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Fri May 30 15:09:09 2014 +0200
@@ -29,6 +29,8 @@
  */
 public interface StateSplit extends NodeWithState {
 
+    FixedNode asNode();
+
     /**
      * Gets the {@link FrameState} corresponding to the state of the JVM after execution of this
      * node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri May 30 15:09:09 2014 +0200
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
@@ -231,7 +232,7 @@
     }
 
     public boolean hasLoops() {
-        return getNodes(LoopBeginNode.class).isNotEmpty();
+        return hasNode(LoopBeginNode.class);
     }
 
     public void removeFloating(FloatingNode node) {
@@ -303,6 +304,10 @@
     }
 
     public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor) {
+        removeSplitPropagate(node, survivingSuccessor, null);
+    }
+
+    public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor, SimplifierTool tool) {
         assert node != null;
         assert node.usages().isEmpty();
         assert survivingSuccessor != null;
@@ -313,7 +318,7 @@
         for (Node successor : snapshot) {
             if (successor != null && successor.isAlive()) {
                 if (successor != survivingSuccessor) {
-                    GraphUtil.killCFG(successor);
+                    GraphUtil.killCFG(successor, tool);
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Fri May 30 15:09:09 2014 +0200
@@ -75,7 +75,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (ObjectStamp.isExactType(object)) {
+        if (StampTool.isExactType(object)) {
             // The profile is useless - we know the type!
             return object;
         } else if (object instanceof TypeProfileProxyNode) {
@@ -96,8 +96,8 @@
                 Debug.log("Improved profile via other profile.");
                 return TypeProfileProxyNode.create(object, newProfile);
             }
-        } else if (ObjectStamp.typeOrNull(object) != null) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(object);
+        } else if (StampTool.typeOrNull(object) != null) {
+            ResolvedJavaType type = StampTool.typeOrNull(object);
             ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype();
             if (uniqueConcrete != null) {
                 // Profile is useless => remove.
@@ -109,7 +109,7 @@
                 return this;
             }
             lastCheckedType = type;
-            JavaTypeProfile newProfile = this.profile.restrict(type, ObjectStamp.isObjectNonNull(object));
+            JavaTypeProfile newProfile = this.profile.restrict(type, StampTool.isObjectNonNull(object));
             if (newProfile != this.profile) {
                 Debug.log("Improved profile via static type information.");
                 if (newProfile.getTypes().length == 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable {
+
+    @Input private ValueNode object;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    protected void setX(ValueNode object) {
+        updateUsages(this.object, object);
+        this.object = object;
+    }
+
+    public UnaryOpLogicNode(ValueNode object) {
+        assert object != null;
+        this.object = object;
+    }
+
+    public abstract TriState evaluate(ValueNode forObject);
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,8 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Unwinds the current frame to an exception handler in the caller frame.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This class represents a value within the graph, including local variables, phis, and all other
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Fri May 30 15:09:09 2014 +0200
@@ -54,10 +54,6 @@
 
     @Override
     public boolean inferStamp() {
-        return inferPhiStamp();
-    }
-
-    public boolean inferPhiStamp() {
         return updateStamp(StampTool.meet(values()));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Fri May 30 15:09:09 2014 +0200
@@ -45,6 +45,10 @@
 
     public abstract void applyToNonVirtual(NodeClosure<? super ValueNode> closure);
 
+    /**
+     * Performs a <b>pre-order</b> iteration over all elements reachable from this state that are a
+     * subclass of {@link VirtualState}.
+     */
     public abstract void applyToVirtual(VirtualClosure closure);
 
     public abstract boolean isPartOfThisState(VirtualState state);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -92,13 +92,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitAnd(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAndMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code BinaryNode} class is the base of arithmetic and logic operations with two inputs.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Fri May 30 15:09:09 2014 +0200
@@ -30,7 +30,7 @@
 /**
  * The {@code LogicNode} class definition.
  */
-public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode {
+public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     /**
      * Constructs a new logic operation node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
@@ -35,7 +36,7 @@
  * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
  * into variants that do not materialize the value (CompareIf, CompareGuard...)
  */
-public abstract class CompareNode extends BinaryLogicNode implements Canonicalizable {
+public abstract class CompareNode extends BinaryOpLogicNode {
 
     /**
      * Constructs a new Compare instruction.
@@ -90,53 +91,66 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return TriState.get(condition().foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue()));
+        }
+        return TriState.UNKNOWN;
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant() && tool.getMetaAccess() != null) {
-            return LogicConstantNode.forBoolean(condition().foldCondition(x().asConstant(), y().asConstant(), tool.getConstantReflection(), unorderedIsTrue()), graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
         if (x().isConstant()) {
-            if (y() instanceof ConditionalNode) {
-                return optimizeConditional(x().asConstant(), (ConditionalNode) y(), tool.getConstantReflection(), condition().mirror());
-            } else if (y() instanceof NormalizeCompareNode) {
-                return optimizeNormalizeCmp(x().asConstant(), (NormalizeCompareNode) y(), true);
+            if ((result = canonicalizeSymmetricConstant(tool, x().asConstant(), y(), true)) != this) {
+                return result;
             }
         } else if (y().isConstant()) {
-            if (x() instanceof ConditionalNode) {
-                return optimizeConditional(y().asConstant(), (ConditionalNode) x(), tool.getConstantReflection(), condition());
-            } else if (x() instanceof NormalizeCompareNode) {
-                return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x(), false);
+            if ((result = canonicalizeSymmetricConstant(tool, y().asConstant(), x(), false)) != this) {
+                return result;
             }
-        }
-        if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
+        } else if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
             ConvertNode convertX = (ConvertNode) x();
             ConvertNode convertY = (ConvertNode) y();
-            if (convertX.isLossless() && convertY.isLossless() && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
-                setX(convertX.getInput());
-                setY(convertY.getInput());
+            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
+                return graph().unique(duplicateModified(convertX.getInput(), convertY.getInput()));
             }
-        } else if (x() instanceof ConvertNode && y().isConstant()) {
-            ConvertNode convertX = (ConvertNode) x();
-            ConstantNode newY = canonicalConvertConstant(convertX, y().asConstant());
-            if (newY != null) {
-                setX(convertX.getInput());
-                setY(newY);
+
+        }
+        return this;
+    }
+
+    protected abstract CompareNode duplicateModified(ValueNode newX, ValueNode newY);
+
+    protected Node canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        if (nonConstant instanceof BinaryNode) {
+            if (nonConstant instanceof ConditionalNode) {
+                return optimizeConditional(constant, (ConditionalNode) nonConstant, tool.getConstantReflection(), mirrored ? condition().mirror() : condition());
+            } else if (nonConstant instanceof NormalizeCompareNode) {
+                return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored);
             }
-        } else if (y() instanceof ConvertNode && x().isConstant()) {
-            ConvertNode convertY = (ConvertNode) y();
-            ConstantNode newX = canonicalConvertConstant(convertY, x().asConstant());
-            if (newX != null) {
-                setX(newX);
-                setY(convertY.getInput());
+        } else if (nonConstant instanceof ConvertNode) {
+            ConvertNode convert = (ConvertNode) nonConstant;
+            ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant);
+            if (newConstant != null) {
+                if (mirrored) {
+                    return graph().unique(duplicateModified(newConstant, convert.getInput()));
+                } else {
+                    return graph().unique(duplicateModified(convert.getInput(), newConstant));
+                }
             }
         }
         return this;
     }
 
-    private static ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
-        if (convert.isLossless()) {
+    private ConstantNode canonicalConvertConstant(CanonicalizerTool tool, ConvertNode convert, Constant constant) {
+        if (convert.preservesOrder(condition())) {
             Constant reverseConverted = convert.reverse(constant);
             if (convert.convert(reverseConverted).equals(constant)) {
-                return ConstantNode.forPrimitive(convert.getInput().stamp(), reverseConverted, convert.graph());
+                return ConstantNode.forConstant(convert.getInput().stamp(), reverseConverted, tool.getMetaAccess(), convert.graph());
             }
         }
         return null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,12 +26,12 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note
@@ -82,7 +82,7 @@
                 IntegerStamp equalsXStamp = (IntegerStamp) equals.x().stamp();
                 if (equalsXStamp.upMask() == 1) {
                     if (x().asConstant().equals(Constant.INT_0) && y().asConstant().equals(Constant.INT_1)) {
-                        return equals.x();
+                        return IntegerConvertNode.convertUnsigned(equals.x(), stamp());
                     }
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 
@@ -47,8 +48,23 @@
 
     public abstract Constant reverse(Constant c);
 
+    /**
+     * Check whether a conversion is lossless.
+     *
+     * @return true iff reverse(convert(c)) == c for all c
+     */
     public abstract boolean isLossless();
 
+    /**
+     * Check whether a conversion preserves comparison order.
+     *
+     * @param op a comparison operator
+     * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2
+     */
+    public boolean preservesOrder(Condition op) {
+        return isLossless();
+    }
+
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "+")
@@ -84,13 +84,4 @@
         }
         return false;
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAddMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,9 +25,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
-public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     private final boolean isStrictFP;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,59 +24,19 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
-
-    public enum FloatConvert {
-        F2I,
-        D2I,
-        F2L,
-        D2L,
-        I2F,
-        L2F,
-        D2F,
-        I2D,
-        L2D,
-        F2D;
-
-        public FloatConvert reverse() {
-            switch (this) {
-                case D2F:
-                    return F2D;
-                case D2I:
-                    return I2D;
-                case D2L:
-                    return L2D;
-                case F2D:
-                    return D2F;
-                case F2I:
-                    return I2F;
-                case F2L:
-                    return L2F;
-                case I2D:
-                    return D2I;
-                case I2F:
-                    return F2I;
-                case L2D:
-                    return D2L;
-                case L2F:
-                    return F2L;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
+public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
 
     private final FloatConvert op;
 
@@ -206,12 +166,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getInput())));
     }
-
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitFloatConvertMemory(getOp(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
@@ -60,13 +60,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitDiv(builder.operand(x()), builder.operand(y()), null));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitDivMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,17 +22,21 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
 public final class FloatEqualsNode extends CompareNode {
 
     /**
      * Constructs a new floating point equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -51,4 +55,28 @@
     public boolean unorderedIsTrue() {
         return false;
     }
+
+    @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (forX.stamp() instanceof FloatStamp && forY.stamp() instanceof FloatStamp) {
+            FloatStamp xStamp = (FloatStamp) forX.stamp();
+            FloatStamp yStamp = (FloatStamp) forY.stamp();
+            if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
+                return TriState.TRUE;
+            } else if (xStamp.alwaysDistinct(yStamp)) {
+                return TriState.FALSE;
+            }
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatEqualsNode(newX, newY);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerEqualsNode(newX, newY);
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,14 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "<")
 public final class FloatLessThanNode extends CompareNode {
@@ -35,7 +38,7 @@
 
     /**
      * Constructs a new floating point comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      * @param unorderedIsTrue whether a comparison that is undecided (involving NaNs, etc.) leads to
@@ -59,10 +62,20 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y() && !unorderedIsTrue()) {
-            return LogicConstantNode.contradiction(graph());
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) {
+            return TriState.FALSE;
         }
-        return super.canonical(tool);
+        return super.evaluate(constantReflection, forX, forY);
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatLessThanNode(newX, newY, unorderedIsTrue);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerLessThanNode(newX, newY);
+        }
+        throw GraalInternalError.shouldNotReachHere();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
@@ -70,13 +70,4 @@
         }
         builder.setResult(this, gen.emitMul(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitMulMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,12 +26,12 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
-public final class FloatRemNode extends FloatArithmeticNode implements Canonicalizable {
+public class FloatRemNode extends FloatArithmeticNode implements Canonicalizable, Lowerable {
 
     public FloatRemNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) {
         super(stamp, x, y, isStrictFP);
@@ -57,16 +57,12 @@
     }
 
     @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitRem(builder.operand(x()), builder.operand(y()), null));
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
     }
 
     @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;
+    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+        builder.setResult(this, gen.emitRem(builder.operand(x()), builder.operand(y()), null));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "-")
@@ -79,13 +79,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSubMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Fri May 30 15:09:09 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
@@ -31,4 +31,9 @@
     public FloatingNode(Stamp stamp) {
         super(stamp);
     }
+
+    @Override
+    public FloatingNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -101,13 +101,4 @@
         }
         builder.setResult(this, gen.emitAdd(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAddMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
         super(stamp, x, y);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,25 +23,27 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|<|")
 public final class IntegerBelowThanNode extends CompareNode {
 
     /**
      * Constructs a new unsigned integer comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
     public IntegerBelowThanNode(ValueNode x, ValueNode y) {
         super(x, y);
-        assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
-        assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
+        assert x.stamp() instanceof IntegerStamp;
+        assert y.stamp() instanceof IntegerStamp;
     }
 
     @Override
@@ -55,28 +57,38 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.contradiction(graph());
-        } else {
-            if (x().isConstant() && x().asConstant().asLong() == 0) {
-                // 0 |<| y is the same as 0 != y
-                return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
-            }
-
-            if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-                IntegerStamp xStamp = (IntegerStamp) x().stamp();
-                IntegerStamp yStamp = (IntegerStamp) y().stamp();
-                if (yStamp.isPositive()) {
-                    if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
-                        return LogicConstantNode.tautology(graph());
-                    } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
-                        return LogicConstantNode.contradiction(graph());
-                    }
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.FALSE;
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (yStamp.isPositive()) {
+                if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+                    return TriState.TRUE;
+                } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+                    return TriState.FALSE;
                 }
             }
         }
+        return super.evaluate(constantReflection, forX, forY);
+    }
 
-        return super.canonical(tool);
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
+        }
+        if (x().isConstant() && x().asConstant().asLong() == 0) {
+            // 0 |<| y is the same as 0 != y
+            return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
+        }
+        return this;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new IntegerBelowThanNode(newX, newY);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,12 +27,11 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
 
     private final int resultBits;
 
@@ -76,6 +75,14 @@
     }
 
     public static ValueNode convert(ValueNode input, Stamp stamp) {
+        return convert(input, stamp, false);
+    }
+
+    public static ValueNode convertUnsigned(ValueNode input, Stamp stamp) {
+        return convert(input, stamp, true);
+    }
+
+    public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend) {
         StructuredGraph graph = input.graph();
         IntegerStamp fromStamp = (IntegerStamp) input.stamp();
         IntegerStamp toStamp = (IntegerStamp) stamp;
@@ -85,6 +92,9 @@
             result = input;
         } else if (toStamp.getBits() < fromStamp.getBits()) {
             result = graph.unique(new NarrowNode(input, toStamp.getBits()));
+        } else if (zeroExtend) {
+            // toStamp.getBits() > fromStamp.getBits()
+            result = graph.unique(new ZeroExtendNode(input, toStamp.getBits()));
         } else {
             // toStamp.getBits() > fromStamp.getBits()
             result = graph.unique(new SignExtendNode(input, toStamp.getBits()));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri May 30 15:09:09 2014 +0200
@@ -108,7 +108,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,13 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
@@ -35,7 +37,7 @@
 
     /**
      * Constructs a new integer equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -71,68 +73,71 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (GraphUtil.unproxify(x()) == GraphUtil.unproxify(y())) {
-            return LogicConstantNode.tautology(graph());
-        } else if (x().stamp().alwaysDistinct(y().stamp())) {
-            return LogicConstantNode.contradiction(graph());
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatEqualsNode(newX, newY);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerEqualsNode(newX, newY);
         }
+        throw GraalInternalError.shouldNotReachHere();
+    }
 
-        ValueNode result = canonicalizeSymmetric(x(), y());
-        if (result != null) {
-            return result;
+    @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.TRUE;
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return TriState.FALSE;
         }
-
-        result = canonicalizeSymmetric(y(), x());
-        if (result != null) {
-            return result;
-        }
-
-        return super.canonical(tool);
+        return super.evaluate(constantReflection, forX, forY);
     }
 
-    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())));
+    @Override
+    protected Node canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        if (constant.asLong() == 0) {
+            if (nonConstant instanceof AndNode) {
+                AndNode andNode = (AndNode) nonConstant;
+                return graph().unique(new IntegerTestNode(andNode.x(), andNode.y()));
+            } else if (nonConstant instanceof ShiftNode) {
+                if (nonConstant instanceof LeftShiftNode) {
+                    LeftShiftNode shift = (LeftShiftNode) nonConstant;
+                    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 (nonConstant instanceof RightShiftNode) {
+                    RightShiftNode shift = (RightShiftNode) nonConstant;
+                    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())));
+                } else if (nonConstant instanceof UnsignedRightShiftNode) {
+                    UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant;
+                    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;
+        return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,18 +23,21 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "<")
 public final class IntegerLessThanNode extends CompareNode {
 
     /**
      * Constructs a new integer comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -71,22 +74,42 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.FALSE;
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (xStamp.upperBound() < yStamp.lowerBound()) {
+                return TriState.TRUE;
+            } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
+                return TriState.FALSE;
+            }
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.contradiction(graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
         if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-            IntegerStamp xStamp = (IntegerStamp) x().stamp();
-            IntegerStamp yStamp = (IntegerStamp) y().stamp();
-            if (xStamp.upperBound() < yStamp.lowerBound()) {
-                return LogicConstantNode.tautology(graph());
-            } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
-                return LogicConstantNode.contradiction(graph());
-            }
-            if (IntegerStamp.sameSign(xStamp, yStamp)) {
+            if (IntegerStamp.sameSign((IntegerStamp) x().stamp(), (IntegerStamp) y().stamp())) {
                 return graph().unique(new IntegerBelowThanNode(x(), y()));
             }
         }
-        return super.canonical(tool);
+        return this;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) {
+            return new FloatLessThanNode(newX, newY, true);
+        } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) {
+            return new IntegerLessThanNode(newX, newY);
+        }
+        throw GraalInternalError.shouldNotReachHere();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,10 +27,9 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "*")
 public class IntegerMulNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode {
@@ -86,13 +85,4 @@
         }
         builder.setResult(this, gen.emitMul(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitMulMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Fri May 30 15:09:09 2014 +0200
@@ -38,6 +38,11 @@
     }
 
     @Override
+    public boolean inferStamp() {
+        return updateStamp(StampTool.rem(x().stamp(), y().stamp()));
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && y().isConstant()) {
             long y = y().asConstant().asLong();
@@ -63,7 +68,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -121,13 +121,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSubMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,17 +22,17 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This node will perform a "test" operation on its arguments. Its result is equivalent to the
  * expression "(x &amp; y) == 0", meaning that it will return true if (and only if) no bit is set in
  * both x and y.
  */
-public class IntegerTestNode extends BinaryLogicNode implements Canonicalizable {
+public class IntegerTestNode extends BinaryOpLogicNode {
 
     /**
      * Constructs a new Test instruction.
@@ -45,19 +45,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            return LogicConstantNode.forBoolean((x().asConstant().asLong() & y().asConstant().asLong()) == 0, graph());
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return TriState.get((forX.asConstant().asLong() & forY.asConstant().asLong()) == 0);
         }
         if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-            IntegerStamp xStamp = (IntegerStamp) x().stamp();
-            IntegerStamp yStamp = (IntegerStamp) y().stamp();
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
             if ((xStamp.upMask() & yStamp.upMask()) == 0) {
-                return LogicConstantNode.tautology(graph());
+                return TriState.TRUE;
             } else if ((xStamp.downMask() & yStamp.downMask()) != 0) {
-                return LogicConstantNode.contradiction(graph());
+                return TriState.FALSE;
             }
         }
-        return this;
+        return TriState.UNKNOWN;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,8 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -32,21 +34,15 @@
 /**
  * An IsNullNode will be true if the supplied value is null, and false if it is non-null.
  */
-public final class IsNullNode extends LogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
-
-    @Input private ValueNode object;
-
-    public ValueNode object() {
-        return object;
-    }
+public final class IsNullNode extends UnaryOpLogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
 
     /**
      * Constructs a new IsNullNode instruction.
-     * 
+     *
      * @param object the instruction producing the object to check against null
      */
     public IsNullNode(ValueNode object) {
-        this.object = object;
+        super(object);
     }
 
     @Override
@@ -63,20 +59,31 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        Constant constant = object().asConstant();
-        if (constant != null) {
-            assert constant.getKind() == Kind.Object;
-            return LogicConstantNode.forBoolean(constant.isNull(), graph());
-        }
-        if (ObjectStamp.isObjectNonNull(object.stamp())) {
-            return LogicConstantNode.contradiction(graph());
+        switch (evaluate(object())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
         }
         return this;
     }
 
     @Override
+    public TriState evaluate(ValueNode forObject) {
+        Constant constant = forObject.asConstant();
+        if (constant != null) {
+            assert constant.getKind() == Kind.Object;
+            return TriState.get(constant.isNull());
+        }
+        if (StampTool.isObjectNonNull(forObject.stamp())) {
+            return TriState.FALSE;
+        }
+        return TriState.UNKNOWN;
+    }
+
+    @Override
     public void virtualize(VirtualizerTool tool) {
-        if (tool.getObjectState(object) != null) {
+        if (tool.getObjectState(object()) != null) {
             tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,11 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -40,7 +41,8 @@
     }
 
     public static long narrow(long value, int resultBits) {
-        return value & IntegerStamp.defaultMask(resultBits);
+        long ret = value & IntegerStamp.defaultMask(resultBits);
+        return SignExtendNode.signExtend(ret, resultBits);
     }
 
     @Override
@@ -107,13 +109,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitNarrow(builder.operand(getInput()), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitNarrowMemory(getResultBits(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,9 +23,9 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Returns -1, 0, or 1 if either x &lt; y, x == y, or x &gt; y. If the comparison is undecided (one
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,10 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,19 +23,21 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
 public final class ObjectEqualsNode extends CompareNode implements Virtualizable {
 
     /**
      * Constructs a new object equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -56,21 +58,28 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.tautology(graph());
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.TRUE;
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return TriState.FALSE;
+        } else {
+            return super.evaluate(constantReflection, forX, forY);
         }
+    }
 
-        if (ObjectStamp.isObjectAlwaysNull(x())) {
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
+        }
+        if (StampTool.isObjectAlwaysNull(x())) {
             return graph().unique(new IsNullNode(y()));
-        } else if (ObjectStamp.isObjectAlwaysNull(y())) {
+        } else if (StampTool.isObjectAlwaysNull(y())) {
             return graph().unique(new IsNullNode(x()));
         }
-        if (x().stamp().alwaysDistinct(y().stamp())) {
-            return LogicConstantNode.contradiction(graph());
-        }
-
-        return super.canonical(tool);
+        return this;
     }
 
     private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
@@ -110,7 +119,7 @@
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 * 
+                 *
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
@@ -129,4 +138,9 @@
             }
         }
     }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new ObjectEqualsNode(newX, newY);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -77,13 +77,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitOr(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitOrMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,17 +27,16 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code ReinterpretNode} class represents a reinterpreting conversion that changes the stamp
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
 
     @Input private ValueNode value;
 
@@ -109,15 +108,6 @@
         builder.setResult(this, gen.emitReinterpret(kind, builder.operand(value())));
     }
 
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitReinterpretMemory(stamp(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
-
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
         return value.graph().unique(new ReinterpretNode(toKind, value));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,9 +26,9 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = ">>")
 public final class RightShiftNode extends ShiftNode implements Canonicalizable {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,11 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -108,13 +109,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSignExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSignExtendMemory(access, getInputBits(), getResultBits());
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "|/|")
 public class UnsignedDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
@@ -73,7 +72,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = "|%|")
 public class UnsignedRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable {
@@ -72,7 +71,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(x()), gen.operand(y()), this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(x()), gen.operand(y()), gen.state(this)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,8 +26,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -76,13 +76,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitXor(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitXorMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,12 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -64,6 +65,19 @@
     }
 
     @Override
+    public boolean preservesOrder(Condition op) {
+        switch (op) {
+            case GE:
+            case GT:
+            case LE:
+            case LT:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         ValueNode ret = canonicalConvert();
         if (ret != null) {
@@ -102,13 +116,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitZeroExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Fri May 30 15:09:09 2014 +0200
@@ -25,14 +25,16 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 
 public final class Block extends AbstractBlockBase<Block> {
 
     protected final BeginNode beginNode;
 
     protected FixedNode endNode;
+
+    protected double probability;
     protected Loop<Block> loop;
 
     protected List<Block> dominated;
@@ -54,8 +56,12 @@
         return loop;
     }
 
+    public void setLoop(Loop<Block> loop) {
+        this.loop = loop;
+    }
+
     public int getLoopDepth() {
-        return loop == null ? 0 : loop.depth;
+        return loop == null ? 0 : loop.getDepth();
     }
 
     public boolean isLoopHeader() {
@@ -67,7 +73,8 @@
     }
 
     public boolean isExceptionEntry() {
-        return getBeginNode() instanceof ExceptionObjectNode;
+        Node predecessor = getBeginNode().predecessor();
+        return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge();
     }
 
     public Block getFirstPredecessor() {
@@ -174,4 +181,12 @@
         return getDominator().isDominatedBy(block);
     }
 
+    public double probability() {
+        return probability;
+    }
+
+    public void setProbability(double probability) {
+        assert probability >= 0 && Double.isFinite(probability);
+        this.probability = probability;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlocksToDoubles.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.cfg;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-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/CFGVerifier.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java	Fri May 30 15:09:09 2014 +0200
@@ -31,7 +31,7 @@
     public static boolean verify(ControlFlowGraph cfg) {
         for (Block block : cfg.getBlocks()) {
             assert block.getId() >= 0;
-            assert cfg.getBlocks()[block.getId()] == block;
+            assert cfg.getBlocks().get(block.getId()) == block;
 
             for (Block pred : block.getPredecessors()) {
                 assert pred.getSuccessors().contains(block);
@@ -82,25 +82,25 @@
                 }
             }
 
-            assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block : block.beginNode;
+            assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().getHeader() == block : block.beginNode;
         }
 
         if (cfg.getLoops() != null) {
             for (Loop<Block> loop : cfg.getLoops()) {
-                assert loop.header.isLoopHeader();
+                assert loop.getHeader().isLoopHeader();
 
-                for (Block block : loop.blocks) {
-                    assert block.getId() >= loop.header.getId();
+                for (Block block : loop.getBlocks()) {
+                    assert block.getId() >= loop.getHeader().getId();
 
                     Loop<?> blockLoop = block.getLoop();
                     while (blockLoop != loop) {
                         assert blockLoop != null;
-                        blockLoop = blockLoop.parent;
+                        blockLoop = blockLoop.getParent();
                     }
 
                     if (!(block.isLoopHeader() && block.getLoop() == loop)) {
                         for (Block pred : block.getPredecessors()) {
-                            if (!loop.blocks.contains(pred)) {
+                            if (!loop.getBlocks().contains(pred)) {
                                 assert false : "Loop " + loop + " does not contain " + pred;
                                 return false;
                             }
@@ -108,12 +108,12 @@
                     }
                 }
 
-                for (Block block : loop.exits) {
-                    assert block.getId() >= loop.header.getId();
+                for (Block block : loop.getExits()) {
+                    assert block.getId() >= loop.getHeader().getId();
 
                     Loop<?> blockLoop = block.getLoop();
                     while (blockLoop != null) {
-                        blockLoop = blockLoop.parent;
+                        blockLoop = blockLoop.getParent();
                         assert blockLoop != loop;
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Fri May 30 15:09:09 2014 +0200
@@ -35,7 +35,7 @@
     public final StructuredGraph graph;
 
     private final NodeMap<Block> nodeToBlock;
-    private Block[] reversePostOrder;
+    private List<Block> reversePostOrder;
     private List<Loop<Block>> loops;
 
     public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) {
@@ -61,15 +61,15 @@
 
     protected ControlFlowGraph(StructuredGraph graph) {
         this.graph = graph;
-        this.nodeToBlock = graph.createNodeMap(true);
+        this.nodeToBlock = graph.createNodeMap();
     }
 
-    public Block[] getBlocks() {
+    public List<Block> getBlocks() {
         return reversePostOrder;
     }
 
     public Block getStartBlock() {
-        return reversePostOrder[0];
+        return reversePostOrder.get(0);
     }
 
     public Iterable<Block> postOrder() {
@@ -79,16 +79,16 @@
             public Iterator<Block> iterator() {
                 return new Iterator<Block>() {
 
-                    private int nextIndex = reversePostOrder.length - 1;
+                    private ListIterator<Block> it = reversePostOrder.listIterator(reversePostOrder.size());
 
                     @Override
                     public boolean hasNext() {
-                        return nextIndex >= 0;
+                        return it.hasPrevious();
                     }
 
                     @Override
                     public Block next() {
-                        return reversePostOrder[nextIndex--];
+                        return it.previous();
                     }
 
                     @Override
@@ -188,11 +188,11 @@
         // Compute reverse postorder and number blocks.
         assert postOrder.size() <= numBlocks : "some blocks originally created can be unreachable, so actual block list can be shorter";
         numBlocks = postOrder.size();
-        reversePostOrder = new Block[numBlocks];
+        reversePostOrder = new ArrayList<>(numBlocks);
         for (int i = 0; i < numBlocks; i++) {
             Block block = postOrder.get(numBlocks - i - 1);
             block.setId(i);
-            reversePostOrder[i] = block;
+            reversePostOrder.add(block);
         }
     }
 
@@ -200,21 +200,32 @@
     private void connectBlocks() {
         for (Block block : reversePostOrder) {
             List<Block> predecessors = new ArrayList<>(4);
+            double probability = block.getBeginNode() instanceof StartNode ? 1D : 0D;
             for (Node predNode : block.getBeginNode().cfgPredecessors()) {
                 Block predBlock = nodeToBlock.get(predNode);
                 if (predBlock.getId() >= 0) {
                     predecessors.add(predBlock);
+                    probability += predBlock.probability;
                 }
             }
+            if (predecessors.size() == 1 && predecessors.get(0).getEndNode() instanceof ControlSplitNode) {
+                probability *= ((ControlSplitNode) predecessors.get(0).getEndNode()).probability(block.getBeginNode());
+            }
             if (block.getBeginNode() instanceof LoopBeginNode) {
-                for (LoopEndNode predNode : ((LoopBeginNode) block.getBeginNode()).orderedLoopEnds()) {
+                LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode();
+                probability *= loopBegin.loopFrequency();
+                for (LoopEndNode predNode : loopBegin.orderedLoopEnds()) {
                     Block predBlock = nodeToBlock.get(predNode);
                     if (predBlock.getId() >= 0) {
                         predecessors.add(predBlock);
                     }
                 }
             }
+            if (probability > 1. / Double.MIN_NORMAL) {
+                probability = 1. / Double.MIN_NORMAL;
+            }
             block.setPredecessors(predecessors);
+            block.setProbability(probability);
 
             List<Block> successors = new ArrayList<>(4);
             for (Node suxNode : block.getEndNode().cfgSuccessors()) {
@@ -249,10 +260,10 @@
                     Block exitBlock = nodeToBlock.get(exit);
                     assert exitBlock.getPredecessorCount() == 1;
                     computeLoopBlocks(exitBlock.getFirstPredecessor(), loop);
-                    loop.exits.add(exitBlock);
+                    loop.getExits().add(exitBlock);
                 }
                 List<Block> unexpected = new LinkedList<>();
-                for (Block b : loop.blocks) {
+                for (Block b : loop.getBlocks()) {
                     for (Block sux : b.getSuccessors()) {
                         if (sux.loop != loop) {
                             BeginNode begin = sux.getBeginNode();
@@ -271,10 +282,10 @@
     }
 
     private static void addBranchToLoop(Loop<Block> l, Block b) {
-        if (l.blocks.contains(b)) {
+        if (l.getBlocks().contains(b)) {
             return;
         }
-        l.blocks.add(b);
+        l.getBlocks().add(b);
         b.loop = l;
         for (Block sux : b.getSuccessors()) {
             addBranchToLoop(l, sux);
@@ -285,13 +296,13 @@
         if (block.getLoop() == loop) {
             return;
         }
-        assert block.loop == loop.parent;
+        assert block.loop == loop.getParent();
         block.loop = loop;
 
-        assert !loop.blocks.contains(block);
-        loop.blocks.add(block);
+        assert !loop.getBlocks().contains(block);
+        loop.getBlocks().add(block);
 
-        if (block != loop.header) {
+        if (block != loop.getHeader()) {
             for (Block pred : block.getPredecessors()) {
                 computeLoopBlocks(pred, loop);
             }
@@ -299,9 +310,9 @@
     }
 
     private void computeDominators() {
-        assert reversePostOrder[0].getPredecessorCount() == 0 : "start block has no predecessor and therefore no dominator";
-        for (int i = 1; i < reversePostOrder.length; i++) {
-            Block block = reversePostOrder[i];
+        assert reversePostOrder.get(0).getPredecessorCount() == 0 : "start block has no predecessor and therefore no dominator";
+        for (int i = 1; i < reversePostOrder.size(); i++) {
+            Block block = reversePostOrder.get(i);
             assert block.getPredecessorCount() > 0;
             Block dominator = null;
             for (Block pred : block.getPredecessors()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Fri May 30 15:09:09 2014 +0200
@@ -33,6 +33,6 @@
 
     @Override
     public long numBackedges() {
-        return ((LoopBeginNode) header.getBeginNode()).loopEnds().count();
+        return ((LoopBeginNode) getHeader().getBeginNode()).loopEnds().count();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,15 +22,15 @@
  */
 package com.oracle.graal.nodes.debug;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This node can be used to add a counter to the code that will estimate the dynamic number of calls
  * by adding an increment to the compiled code. This should of course only be used for
  * debugging/testing purposes.
- * 
+ *
  * A unique counter will be created for each unique name passed to the constructor. Depending on the
  * value of withContext, the name of the root method is added to the counter's name.
  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,9 +23,9 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode {
@@ -63,12 +63,12 @@
         return initialization;
     }
 
-    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible) {
-        this(object, value, location, barrierType, compressible, false);
+    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
+        this(object, value, location, barrierType, false);
     }
 
-    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible, boolean initialization) {
-        super(object, location, StampFactory.forVoid(), barrierType, compressible);
+    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
+        super(object, location, StampFactory.forVoid(), barrierType);
         this.value = value;
         this.initialization = initialization;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,12 +23,13 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that is the sum of two other location nodes. Can represent locations in the form of
@@ -37,8 +38,8 @@
 @NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
 public final class AddLocationNode extends LocationNode implements Canonicalizable {
 
-    @Input private ValueNode x;
-    @Input private ValueNode y;
+    @Input(InputType.Association) private ValueNode x;
+    @Input(InputType.Association) private ValueNode y;
 
     protected LocationNode getX() {
         return (LocationNode) x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -77,7 +78,7 @@
     @Override
     public void virtualize(VirtualizerTool tool) {
         ValueNode v = tool.getReplacedValue(getValue());
-        ResolvedJavaType type = ObjectStamp.typeOrNull(stamp());
+        ResolvedJavaType type = StampTool.typeOrNull(stamp());
 
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A node that represents an exception thrown implicitly by a Java bytecode. It can be lowered to
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,9 +23,10 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that has a constant displacement. Can represent addresses of the form [base + disp]
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Fri May 30 15:09:09 2014 +0200
@@ -37,7 +37,6 @@
     @Input(InputType.Association) private ValueNode location;
     private boolean nullCheck;
     private BarrierType barrierType;
-    private boolean compressible;
 
     public ValueNode object() {
         return object;
@@ -65,20 +64,19 @@
     }
 
     public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp) {
-        this(object, location, stamp, null, BarrierType.NONE, false);
+        this(object, location, stamp, null, BarrierType.NONE);
     }
 
-    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) {
-        this(object, location, stamp, null, barrierType, compressible);
+    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
+        this(object, location, stamp, null, barrierType);
     }
 
-    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
+    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
         super(stamp);
         this.object = object;
         this.location = location;
         this.guard = guard;
         this.barrierType = barrierType;
-        this.compressible = compressible;
     }
 
     @Override
@@ -101,9 +99,4 @@
     public BarrierType getBarrierType() {
         return barrierType;
     }
-
-    @Override
-    public boolean isCompressible() {
-        return compressible;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable, ValueProxy {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Fri May 30 15:09:09 2014 +0200
@@ -35,12 +35,12 @@
         super(object, location, stamp);
     }
 
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
-        super(object, location, stamp, guard, barrierType, compressible);
+    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(object, location, stamp, guard, barrierType);
     }
 
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) {
-        super(object, location, stamp, barrierType, compressible);
+    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
+        super(object, location, stamp, barrierType);
     }
 
     public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Fri May 30 15:09:09 2014 +0200
@@ -32,7 +32,6 @@
     @Input private ValueNode object;
     @Input(InputType.Association) private LocationNode location;
     private BarrierType barrierType;
-    private boolean compressible;
 
     public ValueNode object() {
         return object;
@@ -56,12 +55,11 @@
         this.location = location;
     }
 
-    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
+    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
         super(stamp, guard);
         this.object = object;
         this.location = location;
         this.barrierType = barrierType;
-        this.compressible = compressible;
     }
 
     @Override
@@ -69,11 +67,6 @@
         return barrierType;
     }
 
-    @Override
-    public boolean isCompressible() {
-        return compressible;
-    }
-
     public boolean canNullCheck() {
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri May 30 15:09:09 2014 +0200
@@ -38,15 +38,15 @@
     @Input(InputType.Memory) private MemoryNode lastLocationAccess;
 
     public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) {
-        this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE, false);
+        this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE);
     }
 
     public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
-        this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE, false);
+        this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE);
     }
 
-    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
-        super(object, location, stamp, guard, barrierType, compressible);
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(object, location, stamp, guard, barrierType);
         this.lastLocationAccess = lastLocationAccess;
     }
 
@@ -63,20 +63,20 @@
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
         PlatformKind readKind = gen.getLIRGeneratorTool().getPlatformKind(stamp());
-        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, null));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
-            return graph().unique(new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType(), isCompressible()));
+            return graph().unique(new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType()));
         }
-        return ReadNode.canonicalizeRead(this, location(), object(), tool, isCompressible());
+        return ReadNode.canonicalizeRead(this, location(), object(), tool);
     }
 
     @Override
     public FixedAccessNode asFixedNode() {
-        return graph().add(new ReadNode(object(), accessLocation(), stamp(), getGuard(), getBarrierType(), isCompressible()));
+        return graph().add(new ReadNode(object(), accessLocation(), stamp(), getGuard(), getBarrierType()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Node for a {@linkplain ForeignCallDescriptor foreign} call.
@@ -95,7 +94,7 @@
     public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor);
         Value[] operands = operands(gen);
-        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, operands);
+        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), operands);
         if (result != null) {
             gen.setResult(this, result);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * A node that may be guarded by a {@linkplain GuardingNode guarding node}.
  */
-public interface GuardedNode {
+public interface GuardedNode extends NodeInterface {
 
     GuardingNode getGuard();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,12 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that has a displacement and a scaled index. Can represent locations in the form of
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,10 +25,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Read a raw memory location according to Java field or array read semantics. It will perform read
@@ -32,8 +32,11 @@
  */
 public final class JavaReadNode extends FixedAccessNode implements Lowerable, GuardingNode {
 
+    private final boolean compressible;
+
     public JavaReadNode(ValueNode object, LocationNode location, BarrierType barrierType, boolean compressible) {
-        super(object, location, StampFactory.forKind(location.getValueKind()), barrierType, compressible);
+        super(object, location, StampFactory.forKind(location.getValueKind()), barrierType);
+        this.compressible = compressible;
     }
 
     public void lower(LoweringTool tool) {
@@ -43,4 +46,8 @@
     public boolean canNullCheck() {
         return true;
     }
+
+    public boolean isCompressible() {
+        return compressible;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Fri May 30 15:09:09 2014 +0200
@@ -31,8 +31,11 @@
  */
 public final class JavaWriteNode extends AbstractWriteNode implements Lowerable, StateSplit, MemoryAccess, MemoryCheckpoint.Single {
 
+    private final boolean compressible;
+
     public JavaWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible, boolean initialization) {
-        super(object, value, location, barrierType, compressible, initialization);
+        super(object, value, location, barrierType, initialization);
+        this.compressible = compressible;
     }
 
     public void lower(LoweringTool tool) {
@@ -42,4 +45,8 @@
     public boolean canNullCheck() {
         return true;
     }
+
+    public boolean isCompressible() {
+        return compressible;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Loads an object's {@linkplain Representation#ObjectHub hub}. The object is not null-checked by
@@ -51,7 +50,6 @@
     public LoadHubNode(ValueNode object, Kind kind, ValueNode guard) {
         super(getKind(kind), (GuardingNode) guard);
         assert object != guard;
-        assert guard != null;
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,10 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Loads a method from the virtual method table of a given hub.
@@ -36,18 +34,20 @@
 
     @Input private ValueNode hub;
     private final ResolvedJavaMethod method;
+    private final ResolvedJavaType receiverType;
 
     public ValueNode getHub() {
         return hub;
     }
 
-    public LoadMethodNode(ResolvedJavaMethod method, ValueNode hub, Kind kind) {
+    public LoadMethodNode(ResolvedJavaMethod method, ResolvedJavaType receiverType, ValueNode hub, Kind kind) {
         super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind));
+        this.receiverType = receiverType;
         this.hub = hub;
         this.method = method;
-        assert !Modifier.isAbstract(method.getModifiers()) : "Cannot load abstract method from a hub";
-        assert !Modifier.isStatic(method.getModifiers()) : "Cannot load a static method from a hub";
-        assert method.isInVirtualMethodTable();
+        assert !method.isAbstract() : "Cannot load abstract method from a hub";
+        assert !method.isStatic() : "Cannot load a static method from a hub";
+        assert method.isInVirtualMethodTable(receiverType);
     }
 
     @Override
@@ -58,4 +58,8 @@
     public ResolvedJavaMethod getMethod() {
         return method;
     }
+
+    public ResolvedJavaType getReceiverType() {
+        return receiverType;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 
@@ -31,10 +31,10 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Creates a memory barrier.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Fri May 30 15:09:09 2014 +0200
@@ -40,7 +40,7 @@
         /**
          * This method is used to determine which memory location is killed by this node. Returning
          * the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory locations.
-         * 
+         *
          * @return the identity of the location killed by this node.
          */
         LocationIdentity getLocationIdentity();
@@ -53,7 +53,7 @@
          * This method is used to determine which set of memory locations is killed by this node.
          * Returning the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory
          * locations.
-         * 
+         *
          * @return the identities of all locations killed by this node.
          */
         LocationIdentity[] getLocationIdentities();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * This interface marks nodes that are part of the memory graph.
  */
-public interface MemoryNode {
+public interface MemoryNode extends NodeInterface {
 
     ValueNode asNode();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
-public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
+@NodeInfo(allowedUsageTypes = {InputType.Guard})
+public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, GuardingNode {
 
     @Input private ValueNode object;
 
@@ -41,7 +43,7 @@
 
     @Override
     public void generate(NodeLIRBuilderTool generator) {
-        generator.emitNullCheck(object, this);
+        generator.getLIRGeneratorTool().emitNullCheck(generator.operand(object), generator.state(this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri May 30 15:09:09 2014 +0200
@@ -36,44 +36,44 @@
  */
 public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode {
 
-    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) {
-        super(object, location, stamp, barrierType, compressible);
+    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
+        super(object, location, stamp, barrierType);
     }
 
-    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
-        super(object, location, stamp, guard, barrierType, compressible);
+    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(object, location, stamp, guard, barrierType);
     }
 
-    private ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType, boolean compressible) {
+    private ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) {
         /*
          * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
          * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
          * type LocationNode.
          */
-        super(object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType, compressible);
+        super(object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
         PlatformKind readKind = gen.getLIRGeneratorTool().getPlatformKind(stamp());
-        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, this));
+        gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, gen.state(this)));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) {
-            ReadNode readNode = graph().add(new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType(), isCompressible()));
+            ReadNode readNode = graph().add(new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType()));
             readNode.setNullCheck(getNullCheck());
             readNode.setStateBefore(stateBefore());
             return readNode;
         }
-        return canonicalizeRead(this, location(), object(), tool, isCompressible());
+        return canonicalizeRead(this, location(), object(), tool);
     }
 
     @Override
     public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
-        return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType(), isCompressible()));
+        return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType()));
     }
 
     @Override
@@ -81,7 +81,7 @@
         return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type);
     }
 
-    public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool, boolean compressible) {
+    public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) {
         MetaAccessProvider metaAccess = tool.getMetaAccess();
         if (read.usages().isEmpty()) {
             GuardingNode guard = ((Access) read).getGuard();
@@ -94,7 +94,7 @@
             }
         }
         if (tool.canonicalizeReads()) {
-            if (metaAccess != null && object != null && object.isConstant() && !compressible) {
+            if (metaAccess != null && object != null && object.isConstant()) {
                 if ((location.getLocationIdentity() == LocationIdentity.FINAL_LOCATION || location.getLocationIdentity() == LocationIdentity.ARRAY_LENGTH_LOCATION) &&
                                 location instanceof ConstantLocationNode) {
                     long displacement = ((ConstantLocationNode) location).getDisplacement();
@@ -144,7 +144,7 @@
         }
 
         ObjectStamp valueStamp = (ObjectStamp) parent.object().stamp();
-        ResolvedJavaType valueType = ObjectStamp.typeOrNull(valueStamp);
+        ResolvedJavaType valueType = StampTool.typeOrNull(valueStamp);
         if (valueType != null && field.getDeclaringClass().isAssignableFrom(valueType)) {
             if (piStamp.nonNull() == valueStamp.nonNull() && piStamp.alwaysNull() == valueStamp.alwaysNull()) {
                 replaceFirstInput(parent, parent.object());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public final class StoreHubNode extends FixedWithNextNode implements Lowerable {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,9 +26,9 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code SwitchNode} class is the base of both lookup and table switches.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,12 +23,12 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public class UnboxNode extends FloatingNode implements Virtualizable, Lowerable, Canonicalizable {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Fri May 30 15:09:09 2014 +0200
@@ -67,7 +67,7 @@
             long constantOffset = offset().asConstant().asLong();
 
             // Try to canonicalize to a field access.
-            ResolvedJavaType receiverType = ObjectStamp.typeOrNull(object());
+            ResolvedJavaType receiverType = StampTool.typeOrNull(object());
             if (receiverType != null) {
                 ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantOffset);
                 // No need for checking that the receiver is non-null. The field access includes
@@ -79,15 +79,15 @@
                 }
             }
         }
-        // Temporarily disable this as it appears to break truffle.
-        // ResolvedJavaType receiverType = ObjectStamp.typeOrNull(object());
-        // if (receiverType != null && receiverType.isArray()) {
-        // LocationIdentity identity =
-        // NamedLocationIdentity.getArrayLocation(receiverType.getComponentType().getKind());
-        // // Try to build a better location node
-        // ValueNode location = offset();
-        // return cloneAsArrayAccess(location, identity);
-        // }
+        if (this.getLocationIdentity() == LocationIdentity.ANY_LOCATION) {
+            ResolvedJavaType receiverType = StampTool.typeOrNull(object());
+            // Try to build a better location identity.
+            if (receiverType != null && receiverType.isArray()) {
+                LocationIdentity identity = NamedLocationIdentity.getArrayLocation(receiverType.getComponentType().getKind());
+                assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase";
+                return cloneAsArrayAccess(offset(), identity);
+            }
+        }
 
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri May 30 15:09:09 2014 +0200
@@ -51,7 +51,7 @@
     }
 
     public UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
-        this(object, toType.getKind() == Kind.Object ? StampFactory.object(toType, exactType, nonNull || ObjectStamp.isObjectNonNull(object.stamp())) : StampFactory.forKind(toType.getKind()));
+        this(object, toType.getKind() == Kind.Object ? StampFactory.object(toType, exactType, nonNull || StampTool.isObjectNonNull(object.stamp())) : StampFactory.forKind(toType.getKind()));
     }
 
     @Override
@@ -60,27 +60,36 @@
     }
 
     @Override
-    public boolean inferStamp() {
-        if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
-            return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp()));
-        }
-        return updateStamp(object.stamp().join(stamp()));
-    }
-
-    @Override
     public Node canonical(CanonicalizerTool tool) {
         assert getKind() == Kind.Object && object.getKind() == Kind.Object;
-        if (stamp().equals(object.stamp())) {
-            return object;
-        } else {
+
+        ObjectStamp my = (ObjectStamp) stamp();
+        ObjectStamp other = (ObjectStamp) object.stamp();
+
+        if (my.type() == null || other.type() == null) {
+            return this;
+        }
+        if (my.isExactType() && !other.isExactType()) {
             return this;
         }
+        if (my.nonNull() && !other.nonNull()) {
+            return this;
+        }
+        if (!my.type().isAssignableFrom(other.type())) {
+            return this;
+        }
+        /*
+         * The unsafe cast does not add any new type information, so it can be removed. Note that
+         * this means that the unsafe cast cannot be used to "drop" type information (in which case
+         * it must not be canonicalized in any case).
+         */
+        return object;
     }
 
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this) != null && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
+        if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,14 +22,14 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 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.nodes.type.*;
 
 /**
  * Load of a value from a location specified as an offset relative to an object. No null check is
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,14 +22,14 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 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.nodes.type.*;
 
 /**
  * Store of a value at a location specified as an offset relative to an object. No null check is
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Fri May 30 15:09:09 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
@@ -22,19 +22,19 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.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.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Anchor, InputType.Guard})
-public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, GuardingNode {
+public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, AnchoringNode, GuardingNode {
 
     @Input(InputType.Guard) private ValueNode anchored;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri May 30 15:09:09 2014 +0200
@@ -34,12 +34,12 @@
  */
 public final class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable {
 
-    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible) {
-        super(object, value, location, barrierType, compressible);
+    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
+        super(object, value, location, barrierType);
     }
 
-    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible, boolean initialization) {
-        super(object, value, location, barrierType, compressible, initialization);
+    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
+        super(object, value, location, barrierType, initialization);
     }
 
     @Override
@@ -48,13 +48,13 @@
         // 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.getLIRGeneratorTool().canStoreConstant(value().asConstant(), isCompressible())) {
+        if (value().isConstant() && gen.getLIRGeneratorTool().canStoreConstant(value().asConstant())) {
             v = value().asConstant();
         } else {
             v = gen.operand(value());
         }
         PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(value().stamp());
-        gen.getLIRGeneratorTool().emitStore(writeKind, address, v, this);
+        gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(this));
     }
 
     @Override
@@ -65,7 +65,7 @@
     }
 
     @NodeIntrinsic
-    public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter BarrierType barrierType, @ConstantNodeParameter boolean compressible);
+    public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter BarrierType barrierType);
 
     @Override
     public void virtualize(VirtualizerTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code AbstractNewArrayNode} is used for all 1-dimensional array allocations.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
@@ -70,7 +68,7 @@
      * @return {@code true} if this field access is to a static field
      */
     public boolean isStatic() {
-        return Modifier.isStatic(field.getModifiers());
+        return field.isStatic();
     }
 
     /**
@@ -79,7 +77,7 @@
      * @return {@code true} if the field is resolved and declared volatile
      */
     public boolean isVolatile() {
-        return Modifier.isVolatile(field.getModifiers());
+        return field.isVolatile();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+
+import sun.misc.*;
+
+/**
+ * Represents an atomic read-and-add operation like {@link Unsafe#getAndAddInt(Object, long, int)}.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements LIRLowerable, MemoryCheckpoint.Single {
+
+    @Input private ValueNode object;
+    @Input private ValueNode offset;
+    @Input private ValueNode delta;
+
+    private final LocationIdentity locationIdentity;
+
+    public AtomicReadAndAddNode(ValueNode object, ValueNode offset, ValueNode delta, LocationIdentity locationIdentity) {
+        super(StampFactory.forKind(delta.getKind()));
+        this.object = object;
+        this.offset = offset;
+        this.delta = delta;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode offset() {
+        return offset;
+    }
+
+    public ValueNode delta() {
+        return delta;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    public void generate(NodeLIRBuilderTool gen) {
+        LocationNode location = IndexedLocationNode.create(getLocationIdentity(), delta.getKind(), 0, offset, graph(), 1);
+        Value address = location.generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
+        Value result = gen.getLIRGeneratorTool().emitAtomicReadAndAdd(address, gen.operand(delta));
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static int getAndAddInt(Object object, long offset, int delta, @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
+        return unsafe.getAndAddInt(object, offset, delta);
+    }
+
+    @NodeIntrinsic
+    public static long getAndAddLong(Object object, long offset, long delta, @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
+        return unsafe.getAndAddLong(object, offset, delta);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+
+import sun.misc.*;
+
+/**
+ * Represents an atomic read-and-write operation like {@link Unsafe#getAndSetInt(Object, long, int)}
+ * .
+ */
+public class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+
+    @Input private ValueNode object;
+    @Input private ValueNode offset;
+    @Input private ValueNode newValue;
+
+    private final Kind valueKind;
+    private final LocationIdentity locationIdentity;
+
+    public AtomicReadAndWriteNode(ValueNode object, ValueNode offset, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
+        super(StampFactory.forKind(newValue.getKind()));
+        this.object = object;
+        this.offset = offset;
+        this.newValue = newValue;
+        this.valueKind = valueKind;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode offset() {
+        return offset;
+    }
+
+    public ValueNode newValue() {
+        return newValue;
+    }
+
+    public Kind getValueKind() {
+        return valueKind;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @NodeIntrinsic
+    public static int getAndSetInt(Object object, long offset, int newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
+                    @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
+        return unsafe.getAndSetInt(object, offset, newValue);
+    }
+
+    @NodeIntrinsic
+    public static long getAndSetLong(Object object, long offset, long newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
+                    @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
+        return unsafe.getAndSetLong(object, offset, newValue);
+    }
+
+    @NodeIntrinsic
+    public static Object getAndSetObject(Object object, long offset, Object newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
+                    @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
+        return unsafe.getAndSetObject(object, offset, newValue);
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Fri May 30 15:09:09 2014 +0200
@@ -73,7 +73,7 @@
     public Node canonical(CanonicalizerTool tool) {
         assert object() != null : this;
 
-        if (ObjectStamp.isObjectAlwaysNull(object())) {
+        if (StampTool.isObjectAlwaysNull(object())) {
             return object();
         }
         if (hub.isConstant()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri May 30 15:09:09 2014 +0200
@@ -39,7 +39,7 @@
 /**
  * Implements a type check against a compile-time known type.
  */
-public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Virtualizable, ValueProxy {
+public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Virtualizable, ValueProxy {
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
@@ -107,7 +107,7 @@
             // This is a check cast that will always fail
             condition = LogicConstantNode.contradiction(graph());
             stamp = StampFactory.declared(type);
-        } else if (ObjectStamp.isObjectNonNull(object)) {
+        } else if (StampTool.isObjectNonNull(object)) {
             condition = graph().addWithoutUnique(new InstanceOfNode(type, object, profile));
         } else {
             if (profile != null && profile.getNullSeen() == TriState.FALSE) {
@@ -132,8 +132,9 @@
 
     @Override
     public boolean inferStamp() {
-        if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
-            return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp()));
+        if (object().stamp() instanceof ObjectStamp) {
+            ObjectStamp castStamp = (ObjectStamp) StampFactory.declared(type);
+            return updateStamp(((ObjectStamp) object().stamp()).castTo(castStamp));
         }
         return false;
     }
@@ -142,7 +143,7 @@
     public Node canonical(CanonicalizerTool tool) {
         assert object() != null : this;
 
-        ResolvedJavaType objectType = ObjectStamp.typeOrNull(object());
+        ResolvedJavaType objectType = StampTool.typeOrNull(object());
         if (objectType != null && type.isAssignableFrom(objectType)) {
             // we don't have to check for null types here because they will also pass the
             // checkcast.
@@ -161,7 +162,7 @@
             }
         }
 
-        if (ObjectStamp.isObjectAlwaysNull(object())) {
+        if (StampTool.isObjectAlwaysNull(object())) {
             return object();
         }
         if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,14 +22,14 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
@@ -44,17 +44,15 @@
     @Input private ValueNode newValue;
 
     private final Kind valueKind;
-    private final int displacement;
     private final LocationIdentity locationIdentity;
 
-    public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
+    public CompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
         super(StampFactory.forKind(Kind.Boolean.getStackKind()));
         assert expected.stamp().isCompatible(newValue.stamp());
         this.object = object;
         this.offset = offset;
         this.expected = expected;
         this.newValue = newValue;
-        this.displacement = displacement;
         this.valueKind = valueKind;
         this.locationIdentity = locationIdentity;
     }
@@ -75,10 +73,6 @@
         return newValue;
     }
 
-    public int displacement() {
-        return displacement;
-    }
-
     public Kind getValueKind() {
         return valueKind;
     }
@@ -95,20 +89,20 @@
 
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
     @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, Object expected, Object newValue,
-                    @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind, @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
-        return unsafe.compareAndSwapObject(object, displacement + offset, expected, newValue);
+    public static boolean compareAndSwap(Object object, long offset, Object expected, Object newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
+                    @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
+        return unsafe.compareAndSwapObject(object, offset, expected, newValue);
     }
 
     @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, long expected, long newValue,
-                    @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind, @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
-        return unsafe.compareAndSwapLong(object, displacement + offset, expected, newValue);
+    public static boolean compareAndSwap(Object object, long offset, long expected, long newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
+                    @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
+        return unsafe.compareAndSwapLong(object, offset, expected, newValue);
     }
 
     @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, int expected, int newValue,
-                    @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind, @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
-        return unsafe.compareAndSwapInt(object, displacement + offset, expected, newValue);
+    public static boolean compareAndSwap(Object object, long offset, int expected, int newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
+                    @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
+        return unsafe.compareAndSwapInt(object, offset, expected, newValue);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,10 +26,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code DynamicNewArrayNode} is used for allocation of arrays when the type is not a
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 
 public class DynamicNewInstanceNode extends AbstractNewObjectNode implements Canonicalizable {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,21 +22,18 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The entry to an exception handler with the exception coming from a call (as opposed to a local
  * throw instruction or implicit exception).
  */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, MemoryCheckpoint.Single {
 
     public ExceptionObjectNode(MetaAccessProvider metaAccess) {
@@ -49,56 +46,28 @@
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        //
-    }
-
-    private boolean isLowered() {
-        return (stamp() == StampFactory.forVoid());
-    }
+    public void lower(LoweringTool tool) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            /*
+             * Now the lowering to BeginNode+LoadExceptionNode can be performed, since no more
+             * deopts can float in between the begin node and the load exception node.
+             */
+            LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) predecessor()).getLocationIdentity();
+            BeginNode entry = graph().add(new KillingBeginNode(locationsKilledByInvoke));
+            LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(StampFactory.declaredNonNull(tool.getMetaAccess().lookupJavaType(Throwable.class))));
 
-    /**
-     * The frame state upon entry to an exception handler is such that it is a
-     * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly
-     * the exception object (per the JVM spec) to rethrow. This means that the code creating this
-     * state (i.e. the {@link LoadExceptionObjectNode}) cannot cause a deoptimization as the
-     * runtime/interpreter would not have a valid location for the exception object to be rethrown.
-     */
-    @Override
-    public void lower(LoweringTool tool) {
-        if (isLowered()) {
-            return;
+            loadException.setStateAfter(stateAfter());
+            replaceAtUsages(InputType.Value, loadException);
+            graph().replaceFixedWithFixed(this, entry);
+            entry.graph().addAfterFixed(entry, loadException);
+
+            loadException.lower(tool);
         }
-        LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp()));
-        loadException.setStateAfter(stateAfter());
-        List<GuardedNode> guardedNodes = new ArrayList<>();
-        for (Node usage : usages().snapshot()) {
-            if (usage instanceof GuardedNode) {
-                // can't replace the guard with LoadExceptionObjectNode as it is not a GuardingNode
-                // so temporarily change it to remove the GuardedNode from usages
-                GuardedNode guardedNode = (GuardedNode) usage;
-                guardedNode.setGuard(graph().add(new BeginNode()));
-                guardedNodes.add(guardedNode);
-            }
-        }
-        replaceAtUsages(loadException);
-        for (GuardedNode guardedNode : guardedNodes) {
-            BeginNode dummyGuard = (BeginNode) guardedNode.getGuard();
-            guardedNode.setGuard(this);
-            graph().removeFixed(dummyGuard);
-        }
-        graph().addAfterFixed(this, loadException);
-        setStateAfter(null);
-        setStamp(StampFactory.forVoid());
-        loadException.lower(tool);
     }
 
     @Override
     public boolean verify() {
-        if (isLowered()) {
-            return true;
-        }
-        assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state");
+        assertTrue(stateAfter() != null, "an exception handler needs a frame state");
         return super.verify();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ForeignCallDescriptors.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * The foreign call descriptors used by nodes in this package.
+ * <p>
+ * Using a separate class for such descriptors prevents an access from triggering unwanted class
+ * initialization during runtime initialization.
+ */
+public class ForeignCallDescriptors {
+
+    /**
+     * @see RegisterFinalizerNode
+     */
+    public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
+
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Fri May 30 15:09:09 2014 +0200
@@ -47,8 +47,8 @@
         this.mirror = mirror;
         this.object = object;
         assert mirror.getKind() == Kind.Object : mirror.getKind();
-        assert ObjectStamp.isExactType(mirror);
-        assert ObjectStamp.typeOrNull(mirror).getName().equals("Ljava/lang/Class;");
+        assert StampTool.isExactType(mirror);
+        assert StampTool.typeOrNull(mirror).getName().equals("Ljava/lang/Class;");
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,32 +23,31 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-public final class InstanceOfNode extends LogicNode implements Canonicalizable, Lowerable, Virtualizable {
+public class InstanceOfNode extends UnaryOpLogicNode implements Canonicalizable, Lowerable, Virtualizable {
 
-    @Input private ValueNode object;
     private final ResolvedJavaType type;
     private JavaTypeProfile profile;
 
     /**
      * Constructs a new InstanceOfNode.
-     * 
+     *
      * @param type the target type of the instanceof check
      * @param object the object being tested by the instanceof
      */
     public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+        super(object);
         this.type = type;
-        this.object = object;
         this.profile = profile;
         assert type != null;
     }
@@ -60,13 +59,39 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        Stamp stamp = object().stamp();
+        switch (evaluate(object())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
+            case UNKNOWN:
+                Stamp stamp = object().stamp();
+                if (stamp instanceof ObjectStamp) {
+                    ObjectStamp objectStamp = (ObjectStamp) stamp;
+                    ResolvedJavaType stampType = objectStamp.type();
+                    if (stampType != null && type().isAssignableFrom(stampType)) {
+                        if (!objectStamp.nonNull()) {
+                            // the instanceof matches if the object is non-null, so return true
+                            // depending on the null-ness.
+                            IsNullNode isNull = graph().unique(new IsNullNode(object()));
+                            return graph().unique(new LogicNegationNode(isNull));
+                        }
+                    }
+                }
+                return this;
+        }
+        return this;
+    }
+
+    @Override
+    public TriState evaluate(ValueNode forObject) {
+        Stamp stamp = forObject.stamp();
         if (!(stamp instanceof ObjectStamp)) {
-            return this;
+            return TriState.UNKNOWN;
         }
         ObjectStamp objectStamp = (ObjectStamp) stamp;
         if (objectStamp.alwaysNull()) {
-            return LogicConstantNode.contradiction(graph());
+            return TriState.FALSE;
         }
 
         ResolvedJavaType stampType = objectStamp.type();
@@ -75,34 +100,25 @@
             if (subType) {
                 if (objectStamp.nonNull()) {
                     // the instanceOf matches, so return true
-                    return LogicConstantNode.tautology(graph());
-                } else {
-                    // the instanceof matches if the object is non-null, so return true depending on
-                    // the null-ness.
-                    IsNullNode isNull = graph().unique(new IsNullNode(object()));
-                    return graph().unique(new LogicNegationNode(isNull));
+                    return TriState.TRUE;
                 }
             } else {
                 if (objectStamp.isExactType()) {
                     // since this type check failed for an exact type we know that it can never
                     // succeed at run time. we also don't care about null values, since they will
                     // also make the check fail.
-                    return LogicConstantNode.contradiction(graph());
+                    return TriState.FALSE;
                 } else {
                     boolean superType = stampType.isAssignableFrom(type());
                     if (!superType && !stampType.isInterface() && !type().isInterface()) {
-                        return LogicConstantNode.contradiction(graph());
+                        return TriState.FALSE;
                     }
                     // since the subtype comparison was only performed on a declared type we don't
                     // really know if it might be true at run time...
                 }
             }
         }
-        return this;
-    }
-
-    public ValueNode object() {
-        return object;
+        return TriState.UNKNOWN;
     }
 
     /**
@@ -122,7 +138,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
+        State state = tool.getObjectState(object());
         if (state != null) {
             tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph()));
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,21 +22,10 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
-/**
- * Loads an exception object passed by the runtime from a callee to an exception handler in a
- * caller. The node is only produced when lowering an {@link ExceptionObjectNode}.
- * <p>
- * The frame state upon entry to an exception handler is such that it is a
- * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
- * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
- * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
- * find the exception object to be rethrown.
- */
 public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
 
     public LoadExceptionObjectNode(Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,8 +24,6 @@
 
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -62,7 +60,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (usages().isEmpty() && !isVolatile() && (isStatic() || ObjectStamp.isObjectNonNull(object().stamp()))) {
+        if (usages().isEmpty() && !isVolatile() && (isStatic() || StampTool.isObjectNonNull(object().stamp()))) {
             return null;
         }
         MetaAccessProvider metaAccess = tool.getMetaAccess();
@@ -99,7 +97,7 @@
     }
 
     private PhiNode asPhi(MetaAccessProvider metaAccess) {
-        if (!isStatic() && Modifier.isFinal(field.getModifiers()) && object() instanceof ValuePhiNode && ((ValuePhiNode) object()).values().filter(isNotA(ConstantNode.class)).isEmpty()) {
+        if (!isStatic() && field.isFinal() && object() instanceof ValuePhiNode && ((ValuePhiNode) object()).values().filter(isNotA(ConstantNode.class)).isEmpty()) {
             PhiNode phi = (PhiNode) object();
             Constant[] constants = new Constant[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri May 30 15:09:09 2014 +0200
@@ -45,7 +45,7 @@
     }
 
     private static Stamp createStamp(ValueNode array, Kind kind) {
-        ResolvedJavaType type = ObjectStamp.typeOrNull(array);
+        ResolvedJavaType type = StampTool.typeOrNull(array);
         if (kind == Kind.Object && type != null) {
             return StampFactory.declared(type.getComponentType());
         } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+
+import sun.misc.*;
+
+/**
+ * Represents the lowered version of an atomic read-and-write operation like
+ * {@link Unsafe#getAndSetInt(Object, long, int)} .
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public class LoweredAtomicReadAndWriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
+
+    @Input private ValueNode newValue;
+    @Input(InputType.State) private FrameState stateAfter;
+
+    public LoweredAtomicReadAndWriteNode(ValueNode object, LocationNode location, ValueNode newValue, BarrierType barrierType) {
+        super(object, location, newValue.stamp().unrestricted(), barrierType);
+        this.newValue = newValue;
+    }
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return location().getLocationIdentity();
+    }
+
+    public void generate(NodeLIRBuilderTool gen) {
+        Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
+        Value result = gen.getLIRGeneratorTool().emitAtomicReadAndWrite(address, gen.operand(getNewValue()));
+        gen.setResult(this, result);
+    }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+
+    public boolean canNullCheck() {
+        return false;
+    }
+
+    public final ValueNode getNewValue() {
+        return newValue;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}.
@@ -61,8 +61,8 @@
         return newValue;
     }
 
-    public LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType, boolean compressible) {
-        super(object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType, compressible);
+    public LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType) {
+        super(object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType);
         assert expectedValue.getKind() == newValue.getKind();
         this.expectedValue = expectedValue;
         this.newValue = newValue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -44,6 +42,8 @@
     private ResolvedJavaMethod targetMethod;
     private InvokeKind invokeKind;
 
+    private transient Stamp lastCanonicalizedReceiverStamp;
+
     /**
      * @param arguments
      */
@@ -109,12 +109,12 @@
             assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n);
         }
         if (invokeKind == InvokeKind.Special || invokeKind == InvokeKind.Static) {
-            assertFalse(Modifier.isAbstract(targetMethod.getModifiers()), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod);
+            assertFalse(targetMethod.isAbstract(), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod);
         }
         if (invokeKind == InvokeKind.Static) {
-            assertTrue(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for static methods (%s)", targetMethod);
+            assertTrue(targetMethod.isStatic(), "static calls are only allowed for static methods (%s)", targetMethod);
         } else {
-            assertFalse(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for non-static methods (%s)", targetMethod);
+            assertFalse(targetMethod.isStatic(), "static calls are only allowed for non-static methods (%s)", targetMethod);
         }
         return super.verify();
     }
@@ -139,19 +139,42 @@
                 return this;
             }
 
-            assert targetMethod.getDeclaringClass().asExactType() == null : "should have been handled by canBeStaticallyBound";
+            // check if the type of the receiver can narrow the result
+            Stamp receiverStamp = receiver().stamp();
+            if (receiverStamp.equals(lastCanonicalizedReceiverStamp)) {
+                return this;
+            }
+            lastCanonicalizedReceiverStamp = receiverStamp;
 
-            // check if the type of the receiver can narrow the result
-            ValueNode receiver = receiver();
-            ResolvedJavaType type = ObjectStamp.typeOrNull(receiver);
-            if (type != null) {
+            ResolvedJavaType type = StampTool.typeOrNull(receiverStamp);
+            if (type != null && (invoke().stateAfter() != null || invoke().stateDuring() != null)) {
                 // either the holder class is exact, or the receiver object has an exact type
-                ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod);
-                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || ObjectStamp.isExactType(receiver))) {
+                ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod, invoke().getContextType());
+                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiverStamp))) {
                     invokeKind = InvokeKind.Special;
                     targetMethod = resolvedMethod;
                     return this;
                 }
+                if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
+                    ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
+                    if (uniqueConcreteType != null) {
+                        ResolvedJavaMethod methodFromUniqueType = uniqueConcreteType.resolveMethod(targetMethod, invoke().getContextType());
+                        if (methodFromUniqueType != null) {
+                            tool.assumptions().recordConcreteSubtype(type, uniqueConcreteType);
+                            invokeKind = InvokeKind.Special;
+                            targetMethod = methodFromUniqueType;
+                            return this;
+                        }
+                    }
+
+                    ResolvedJavaMethod uniqueConcreteMethod = type.findUniqueConcreteMethod(targetMethod);
+                    if (uniqueConcreteMethod != null) {
+                        tool.assumptions().recordConcreteMethod(targetMethod, type, uniqueConcreteMethod);
+                        invokeKind = InvokeKind.Special;
+                        targetMethod = uniqueConcreteMethod;
+                        return this;
+                    }
+                }
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -58,7 +59,7 @@
 
     @Override
     public void simplify(SimplifierTool tool) {
-        if (escapedReturnValue != null && stateAfter() != null && stateAfter().bci != FrameState.AFTER_BCI) {
+        if (escapedReturnValue != null && stateAfter() != null && stateAfter().bci != BytecodeFrame.AFTER_BCI) {
             ValueNode returnValue = escapedReturnValue;
             setEscapedReturnValue(null);
             tool.removeIfUnused(returnValue);
@@ -74,7 +75,7 @@
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object());
         // the monitor exit for a synchronized method should never be virtualized
-        assert stateAfter().bci != FrameState.AFTER_BCI || state == null;
+        assert stateAfter().bci != BytecodeFrame.AFTER_BCI || state == null;
         if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
             MonitorIdNode removedLock = state.removeLock();
             assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This node describes one locking scope; it ties the monitor enter, monitor exit and the frame
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -54,7 +55,7 @@
      * @return the element type of the array
      */
     public ResolvedJavaType elementType() {
-        return ObjectStamp.typeOrNull(this).getComponentType();
+        return StampTool.typeOrNull(this).getComponentType();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,10 +26,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.nodes.java;
 
+import static com.oracle.graal.nodes.java.ForeignCallDescriptors.*;
+
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This node is used to perform the finalizer registration at the end of the java.lang.Object
@@ -36,8 +37,6 @@
  */
 public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
 
-    public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class);
-
     @Input(InputType.State) private FrameState deoptState;
     @Input private ValueNode object;
 
@@ -53,7 +52,7 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(REGISTER_FINALIZER);
-        gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(object()));
+        gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(object()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
@@ -66,7 +64,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        InvokeKind invokeKind = Modifier.isStatic(replacementTargetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special;
+        InvokeKind invokeKind = replacementTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
         MethodCallTargetNode replacement = graph().add(
                         new MethodCallTargetNode(invokeKind, replacementTargetMethod, replacementArguments.toArray(new ValueNode[replacementArguments.size()]), replacementReturnType));
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -75,8 +76,8 @@
             int index = indexValue.isConstant() ? indexValue.asConstant().asInt() : -1;
             if (index >= 0 && index < arrayState.getVirtualObject().entryCount()) {
                 ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType();
-                if (componentType.isPrimitive() || ObjectStamp.isObjectAlwaysNull(value) || componentType.getSuperclass() == null ||
-                                (ObjectStamp.typeOrNull(value) != null && componentType.isAssignableFrom(ObjectStamp.typeOrNull(value)))) {
+                if (componentType.isPrimitive() || StampTool.isObjectAlwaysNull(value) || componentType.getSuperclass() == null ||
+                                (StampTool.typeOrNull(value) != null && componentType.isAssignableFrom(StampTool.typeOrNull(value)))) {
                     tool.setVirtualEntry(arrayState, index, value(), false);
                     tool.delete();
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Fri May 30 15:09:09 2014 +0200
@@ -26,11 +26,11 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
+import com.oracle.graal.compiler.common.type.*;
 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.*;
 import com.oracle.graal.nodes.util.*;
 
 /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-
-/**
- * This interface can be used to generate LIR for arithmetic operations.
- */
-public interface ArithmeticLIRGenerator {
-    /**
-     * TODO remove reference to {@link Stamp}.
-     */
-    PlatformKind getPlatformKind(Stamp stamp);
-
-    Value emitNegate(Value input);
-
-    Value emitAdd(Value a, Value b);
-
-    Value emitSub(Value a, Value b);
-
-    Value emitMul(Value a, Value b);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitDiv(Value a, Value b, DeoptimizingNode deopting);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitRem(Value a, Value b, DeoptimizingNode deopting);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitUDiv(Value a, Value b, DeoptimizingNode deopting);
-
-    /**
-     * TODO remove {@link DeoptimizeNode}.
-     */
-    Value emitURem(Value a, Value b, DeoptimizingNode deopting);
-
-    Value emitNot(Value input);
-
-    Value emitAnd(Value a, Value b);
-
-    Value emitOr(Value a, Value b);
-
-    Value emitXor(Value a, Value b);
-
-    Value emitShl(Value a, Value b);
-
-    Value emitShr(Value a, Value b);
-
-    Value emitUShr(Value a, Value b);
-
-    Value emitFloatConvert(FloatConvert op, Value inputVal);
-
-    Value emitReinterpret(PlatformKind to, Value inputVal);
-
-    Value emitNarrow(Value inputVal, int bits);
-
-    Value emitSignExtend(Value inputVal, int fromBits, int toBits);
-
-    Value emitZeroExtend(Value inputVal, int fromBits, int toBits);
-
-    Value emitMathAbs(Value input);
-
-    Value emitMathSqrt(Value input);
-
-    Value emitMathLog(Value input, boolean base10);
-
-    Value emitMathCos(Value input);
-
-    Value emitMathSin(Value input);
-
-    Value emitMathTan(Value input);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.spi;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.lir.gen.*;
 
 public interface ArithmeticLIRLowerable extends ArithmeticOperation {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
-
-    TargetDescription target();
-
-    MetaAccessProvider getMetaAccess();
-
-    CodeCacheProvider getCodeCache();
-
-    ForeignCallsProvider getForeignCalls();
-
-    Value emitLoad(PlatformKind kind, Value address, Access access);
-
-    void emitStore(PlatformKind kind, Value address, Value input, Access access);
-
-    Value emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
-
-    void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting);
-
-    Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args);
-
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for most
-     * operations, i.e., for commonly used arithmetic, logical, and comparison operations.
-     *
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    boolean canInlineConstant(Constant c);
-
-    boolean canStoreConstant(Constant c, boolean isCompressed);
-
-    RegisterAttributes attributes(Register register);
-
-    AllocatableValue newVariable(PlatformKind kind);
-
-    AllocatableValue emitMove(Value input);
-
-    void emitMove(AllocatableValue dst, Value src);
-
-    /**
-     * Emits an op that loads the address of some raw data.
-     *
-     * @param dst the variable into which the address is loaded
-     * @param data the data to be installed with the generated code
-     */
-    void emitData(AllocatableValue dst, byte[] data);
-
-    Value emitAddress(Value base, long displacement, Value index, int scale);
-
-    Value emitAddress(StackSlot slot);
-
-    void emitMembar(int barriers);
-
-    void emitUnwind(Value operand);
-
-    /**
-     * Called just before register allocation is performed on the LIR owned by this generator.
-     * Overriding implementations of this method must call the overridden method.
-     */
-    void beforeRegisterAllocation();
-
-    void emitIncomingValues(Value[] params);
-
-    /**
-     * Emits a return instruction. Implementations need to insert a move if the input is not in the
-     * correct location.
-     */
-    void emitReturn(Value input);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * Interface implemented by nodes that can replace themselves with lower level nodes during a phase
  * that transforms a graph to replace higher level nodes with lower level nodes.
  */
-public interface Lowerable {
+public interface Lowerable extends NodeInterface {
 
     /**
      * Expand this node into lower level nodes expressing the same semantics. If the introduced
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Marks nodes which may be lowered in combination with a memory operation.
- */
-public interface MemoryArithmeticLIRLowerable {
-
-    /**
-     * Attempt to generate a memory form of a node operation. On platforms that support it this will
-     * be called when the merging is safe.
-     * 
-     * @param gen
-     * @param access the memory input which can potentially merge into this operation.
-     * @return null if it's not possible to emit a memory form of this operation. A non-null value
-     *         will be set as the operand of this node.
-     */
-    boolean generate(MemoryArithmeticLIRLowerer gen, Access access);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * This interface can be used to generate LIR for arithmetic operations where one of the operations
- * is load (@see ArithmeticLIRLowerable).
- */
-public interface MemoryArithmeticLIRLowerer {
-
-    Value setResult(ValueNode x, Value operand);
-
-    Value emitAddMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitMulMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitSubMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitDivMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitRemMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitXorMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitOrMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitAndMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitReinterpretMemory(Stamp stamp, Access access);
-
-    Value emitSignExtendMemory(Access access, int fromBits, int toBits);
-
-    Value emitNarrowMemory(int resultBits, Access access);
-
-    Value emitZeroExtendMemory(int inputBits, int resultBits, Access access);
-
-    Value emitFloatConvertMemory(FloatConvert op, Access access);
-
-    boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred);
-
-    boolean emitIfMemory(IfNode ifNode, Access access);
-
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Fri May 30 15:09:09 2014 +0200
@@ -26,13 +26,18 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 
 public interface NodeLIRBuilderTool extends NodeMappableLIRBuilder {
 
-    void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
+    // TODO (je) remove and move into the Node
+    LIRFrameState state(DeoptimizingNode deopt);
 
     void emitIf(IfNode i);
 
@@ -63,5 +68,13 @@
 
     Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments);
 
-    MemoryArithmeticLIRLowerer getMemoryLowerer();
+    Variable newVariable(Kind kind);
+
+    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+    void emitBitCount(Variable result, Value operand);
+
+    void emitBitScanForward(Variable result, Value operand);
+
+    void doBlock(Block block, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Fri May 30 15:09:09 2014 +0200
@@ -29,9 +29,7 @@
 /**
  * Interface for nodes which have {@link FrameState} nodes as input.
  */
-public interface NodeWithState {
-
-    Node asNode();
+public interface NodeWithState extends NodeInterface {
 
     default NodeIterable<FrameState> states() {
         return asNode().inputs().filter(FrameState.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -36,14 +37,14 @@
 
     /**
      * Gets the snippet graph derived from a given method.
-     * 
+     *
      * @return the snippet graph, if any, that is derived from {@code method}
      */
     StructuredGraph getSnippet(ResolvedJavaMethod method);
 
     /**
      * Gets the snippet graph derived from a given method.
-     * 
+     *
      * @param recursiveEntry if the snippet contains a call to this method, it's considered as
      *            recursive call and won't be processed for {@linkplain MethodSubstitution
      *            substitutions} or {@linkplain MacroSubstitution macro nodes}.
@@ -59,7 +60,7 @@
     /**
      * Notifies this object during snippet specialization once the specialized snippet's constant
      * parameters have been replaced with constant values.
-     * 
+     *
      * @param specializedSnippet the snippet in the process of being specialized. This is a copy of
      *            the unspecialized snippet graph created during snippet preparation.
      */
@@ -67,14 +68,14 @@
 
     /**
      * Gets the graph that is a substitution for a given method.
-     * 
+     *
      * @return the graph, if any, that is a substitution for {@code method}
      */
     StructuredGraph getMethodSubstitution(ResolvedJavaMethod method);
 
     /**
      * Gets the node class with which a method invocation should be replaced.
-     * 
+     *
      * @param method target of an invocation
      * @return the {@linkplain MacroSubstitution#macro() macro node class} associated with
      *         {@code method} or null if there is no such association
@@ -89,8 +90,15 @@
     /**
      * Registers all the {@linkplain MethodSubstitution method} and {@linkplain MacroSubstitution
      * macro} substitutions defined by a given class.
+     *
+     * @param original the original class for which substitutions are being registered. This must be
+     *            the same type denoted by the {@link ClassSubstitution} annotation on
+     *            {@code substitutions}. It is required here so that an implementation is not forced
+     *            to read annotations during registration.
+     * @param substitutions the class defining substitutions for {@code original}. This class must
+     *            be annotated with {@link ClassSubstitution}.
      */
-    void registerSubstitutions(Class<?> substitutions);
+    void registerSubstitutions(Type original, Class<?> substitutions);
 
     /**
      * Returns all methods that are currently registered as method/macro substitution or as a
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -24,11 +24,13 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.api.runtime.*;
 
 /**
  * Interface for service providers that register replacements with the compiler.
  */
-public interface ReplacementsProvider {
+public interface ReplacementsProvider extends Service {
 
-    void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target);
+    void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/FloatStamp.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,235 +0,0 @@
-/*
- * 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.nodes.type;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.type.*;
-
-public class FloatStamp extends PrimitiveStamp {
-
-    private final double lowerBound;
-    private final double upperBound;
-    private final boolean nonNaN;
-
-    protected FloatStamp(int bits) {
-        this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false);
-    }
-
-    protected FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) {
-        super(bits);
-        this.lowerBound = lowerBound;
-        this.upperBound = upperBound;
-        this.nonNaN = nonNaN;
-    }
-
-    @Override
-    public Stamp unrestricted() {
-        return new FloatStamp(getBits());
-    }
-
-    @Override
-    public Stamp illegal() {
-        return new FloatStamp(getBits(), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, true);
-    }
-
-    @Override
-    public boolean isLegal() {
-        return lowerBound <= upperBound || !nonNaN;
-    }
-
-    @Override
-    public Kind getStackKind() {
-        if (getBits() > 32) {
-            return Kind.Double;
-        } else {
-            return Kind.Float;
-        }
-    }
-
-    @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
-        return tool.getFloatingKind(getBits());
-    }
-
-    @Override
-    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
-        switch (getBits()) {
-            case 32:
-                return metaAccess.lookupJavaType(Float.TYPE);
-            case 64:
-                return metaAccess.lookupJavaType(Double.TYPE);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    /**
-     * The (inclusive) lower bound on the value described by this stamp.
-     */
-    public double lowerBound() {
-        return lowerBound;
-    }
-
-    /**
-     * The (inclusive) upper bound on the value described by this stamp.
-     */
-    public double upperBound() {
-        return upperBound;
-    }
-
-    public boolean isNonNaN() {
-        return nonNaN;
-    }
-
-    public boolean isUnrestricted() {
-        return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN;
-    }
-
-    public boolean contains(double value) {
-        if (Double.isNaN(value)) {
-            return !nonNaN;
-        } else {
-            return value >= lowerBound && value <= upperBound;
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder str = new StringBuilder();
-        str.append('f');
-        str.append(getBits());
-        str.append(nonNaN ? "!" : "");
-        if (lowerBound == upperBound) {
-            str.append(" [").append(lowerBound).append(']');
-        } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
-            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
-        }
-        return str.toString();
-    }
-
-    @Override
-    public Stamp meet(Stamp otherStamp) {
-        if (otherStamp == this) {
-            return this;
-        }
-        if (!(otherStamp instanceof FloatStamp)) {
-            return StampFactory.illegal(Kind.Illegal);
-        }
-        FloatStamp other = (FloatStamp) otherStamp;
-        assert getBits() == other.getBits();
-        double meetUpperBound = Math.max(upperBound, other.upperBound);
-        double meetLowerBound = Math.min(lowerBound, other.lowerBound);
-        boolean meetNonNaN = nonNaN && other.nonNaN;
-        if (meetLowerBound == lowerBound && meetUpperBound == upperBound && meetNonNaN == nonNaN) {
-            return this;
-        } else if (meetLowerBound == other.lowerBound && meetUpperBound == other.upperBound && meetNonNaN == other.nonNaN) {
-            return other;
-        } else {
-            return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN);
-        }
-    }
-
-    @Override
-    public Stamp join(Stamp otherStamp) {
-        if (otherStamp == this) {
-            return this;
-        }
-        if (!(otherStamp instanceof FloatStamp)) {
-            return StampFactory.illegal(Kind.Illegal);
-        }
-        FloatStamp other = (FloatStamp) otherStamp;
-        assert getBits() == other.getBits();
-        double joinUpperBound = Math.min(upperBound, other.upperBound);
-        double joinLowerBound = Math.max(lowerBound, other.lowerBound);
-        boolean joinNonNaN = nonNaN || other.nonNaN;
-        if (joinLowerBound == lowerBound && joinUpperBound == upperBound && joinNonNaN == nonNaN) {
-            return this;
-        } else if (joinLowerBound == other.lowerBound && joinUpperBound == other.upperBound && joinNonNaN == other.nonNaN) {
-            return other;
-        } else {
-            return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN);
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        long temp;
-        result = prime * result + super.hashCode();
-        temp = Double.doubleToLongBits(lowerBound);
-        result = prime * result + (int) (temp ^ (temp >>> 32));
-        result = prime * result + (nonNaN ? 1231 : 1237);
-        temp = Double.doubleToLongBits(upperBound);
-        result = prime * result + (int) (temp ^ (temp >>> 32));
-        return result;
-    }
-
-    @Override
-    public boolean isCompatible(Stamp stamp) {
-        if (this == stamp) {
-            return true;
-        }
-        if (stamp instanceof FloatStamp) {
-            FloatStamp other = (FloatStamp) stamp;
-            return getBits() == other.getBits();
-        }
-        return false;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
-            return false;
-        }
-        FloatStamp other = (FloatStamp) obj;
-        if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) {
-            return false;
-        }
-        if (Double.doubleToLongBits(upperBound) != Double.doubleToLongBits(other.upperBound)) {
-            return false;
-        }
-        if (nonNaN != other.nonNaN) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public Constant asConstant() {
-        if (nonNaN && lowerBound == upperBound) {
-            switch (getBits()) {
-                case 32:
-                    return Constant.forFloat((float) lowerBound);
-                case 64:
-                    return Constant.forDouble(lowerBound);
-            }
-        }
-        return null;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IllegalStamp.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * 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.nodes.type;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.type.*;
-
-/**
- * This stamp represents the illegal type. Values with this type can not exist at run time.
- */
-public final class IllegalStamp extends Stamp {
-
-    private IllegalStamp() {
-    }
-
-    @Override
-    public Kind getStackKind() {
-        return Kind.Illegal;
-    }
-
-    @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
-        throw GraalInternalError.shouldNotReachHere("illegal stamp should not reach backend");
-    }
-
-    @Override
-    public Stamp unrestricted() {
-        return this;
-    }
-
-    @Override
-    public Stamp illegal() {
-        return this;
-    }
-
-    @Override
-    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
-        throw GraalInternalError.shouldNotReachHere("illegal stamp has no Java type");
-    }
-
-    @Override
-    public Stamp meet(Stamp other) {
-        return this;
-    }
-
-    @Override
-    public Stamp join(Stamp other) {
-        return this;
-    }
-
-    @Override
-    public boolean isCompatible(Stamp stamp) {
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return "ILLEGAL";
-    }
-
-    @Override
-    public boolean isLegal() {
-        return false;
-    }
-
-    private static IllegalStamp instance = new IllegalStamp();
-
-    static IllegalStamp getInstance() {
-        return instance;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,319 +0,0 @@
-/*
- * 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.nodes.type;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Describes the possible values of a {@link ValueNode} that produces an int or long result.
- *
- * The description consists of (inclusive) lower and upper bounds and up (may be set) and down
- * (always set) bit-masks.
- */
-public class IntegerStamp extends PrimitiveStamp {
-
-    private final long lowerBound;
-    private final long upperBound;
-    private final long downMask;
-    private final long upMask;
-
-    public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
-        super(bits);
-        this.lowerBound = lowerBound;
-        this.upperBound = upperBound;
-        this.downMask = downMask;
-        this.upMask = upMask;
-        assert lowerBound >= defaultMinValue(bits) : this;
-        assert upperBound <= defaultMaxValue(bits) : this;
-        assert (downMask & defaultMask(bits)) == downMask : this;
-        assert (upMask & defaultMask(bits)) == upMask : this;
-    }
-
-    @Override
-    public Stamp unrestricted() {
-        return new IntegerStamp(getBits(), defaultMinValue(getBits()), defaultMaxValue(getBits()), 0, defaultMask(getBits()));
-    }
-
-    @Override
-    public Stamp illegal() {
-        return new IntegerStamp(getBits(), defaultMaxValue(getBits()), defaultMinValue(getBits()), defaultMask(getBits()), 0);
-    }
-
-    @Override
-    public boolean isLegal() {
-        return lowerBound <= upperBound;
-    }
-
-    @Override
-    public Kind getStackKind() {
-        if (getBits() > 32) {
-            return Kind.Long;
-        } else {
-            return Kind.Int;
-        }
-    }
-
-    @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
-        return tool.getIntegerKind(getBits());
-    }
-
-    @Override
-    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
-        switch (getBits()) {
-            case 1:
-                return metaAccess.lookupJavaType(Boolean.TYPE);
-            case 8:
-                return metaAccess.lookupJavaType(Byte.TYPE);
-            case 16:
-                return metaAccess.lookupJavaType(Short.TYPE);
-            case 32:
-                return metaAccess.lookupJavaType(Integer.TYPE);
-            case 64:
-                return metaAccess.lookupJavaType(Long.TYPE);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    /**
-     * The signed inclusive lower bound on the value described by this stamp.
-     */
-    public long lowerBound() {
-        return lowerBound;
-    }
-
-    /**
-     * The signed inclusive upper bound on the value described by this stamp.
-     */
-    public long upperBound() {
-        return upperBound;
-    }
-
-    /**
-     * This bit-mask describes the bits that are always set in the value described by this stamp.
-     */
-    public long downMask() {
-        return downMask;
-    }
-
-    /**
-     * This bit-mask describes the bits that can be set in the value described by this stamp.
-     */
-    public long upMask() {
-        return upMask;
-    }
-
-    public boolean isUnrestricted() {
-        return lowerBound == defaultMinValue(getBits()) && upperBound == defaultMaxValue(getBits()) && downMask == 0 && upMask == defaultMask(getBits());
-    }
-
-    public boolean contains(long value) {
-        return value >= lowerBound && value <= upperBound && (value & downMask) == downMask && (value & upMask) == (value & defaultMask(getBits()));
-    }
-
-    public boolean isPositive() {
-        return lowerBound() >= 0;
-    }
-
-    public boolean isNegative() {
-        return upperBound() <= 0;
-    }
-
-    public boolean isStrictlyPositive() {
-        return lowerBound() > 0;
-    }
-
-    public boolean isStrictlyNegative() {
-        return upperBound() < 0;
-    }
-
-    public boolean canBePositive() {
-        return upperBound() > 0;
-    }
-
-    public boolean canBeNegative() {
-        return lowerBound() < 0;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder str = new StringBuilder();
-        str.append('i');
-        str.append(getBits());
-        if (lowerBound == upperBound) {
-            str.append(" [").append(lowerBound).append(']');
-        } else if (lowerBound != defaultMinValue(getBits()) || upperBound != defaultMaxValue(getBits())) {
-            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
-        }
-        if (downMask != 0) {
-            str.append(" \u21ca");
-            new Formatter(str).format("%016x", downMask);
-        }
-        if (upMask != defaultMask(getBits())) {
-            str.append(" \u21c8");
-            new Formatter(str).format("%016x", upMask);
-        }
-        return str.toString();
-    }
-
-    private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
-        assert getBits() == other.getBits();
-        if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0) {
-            return illegal();
-        } else if (newLowerBound == lowerBound && newUpperBound == upperBound && newDownMask == downMask && newUpMask == upMask) {
-            return this;
-        } else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) {
-            return other;
-        } else {
-            return new IntegerStamp(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
-        }
-    }
-
-    @Override
-    public Stamp meet(Stamp otherStamp) {
-        if (otherStamp == this) {
-            return this;
-        }
-        if (!(otherStamp instanceof IntegerStamp)) {
-            return StampFactory.illegal(Kind.Illegal);
-        }
-        IntegerStamp other = (IntegerStamp) otherStamp;
-        return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
-    }
-
-    @Override
-    public Stamp join(Stamp otherStamp) {
-        if (otherStamp == this) {
-            return this;
-        }
-        if (!(otherStamp instanceof IntegerStamp)) {
-            return StampFactory.illegal(Kind.Illegal);
-        }
-        IntegerStamp other = (IntegerStamp) otherStamp;
-        long newDownMask = downMask | other.downMask;
-        long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask;
-        return createStamp(other, Math.min(upperBound, other.upperBound), newLowerBound, newDownMask, upMask & other.upMask);
-    }
-
-    @Override
-    public boolean isCompatible(Stamp stamp) {
-        if (this == stamp) {
-            return true;
-        }
-        if (stamp instanceof IntegerStamp) {
-            IntegerStamp other = (IntegerStamp) stamp;
-            return getBits() == other.getBits();
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + super.hashCode();
-        result = prime * result + (int) (lowerBound ^ (lowerBound >>> 32));
-        result = prime * result + (int) (upperBound ^ (upperBound >>> 32));
-        result = prime * result + (int) (downMask ^ (downMask >>> 32));
-        result = prime * result + (int) (upMask ^ (upMask >>> 32));
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
-            return false;
-        }
-        IntegerStamp other = (IntegerStamp) obj;
-        if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask) {
-            return false;
-        }
-        return true;
-    }
-
-    public static long defaultMask(int bits) {
-        assert 0 <= bits && bits <= 64;
-        if (bits == 64) {
-            return 0xffffffffffffffffL;
-        } else {
-            return (1L << bits) - 1;
-        }
-    }
-
-    public static long defaultMinValue(int bits) {
-        return -1L << (bits - 1);
-    }
-
-    public static long defaultMaxValue(int bits) {
-        return defaultMask(bits - 1);
-    }
-
-    public static long upMaskFor(int bits, long lowerBound, long upperBound) {
-        long mask = lowerBound | upperBound;
-        if (mask == 0) {
-            return 0;
-        } else {
-            return ((-1L) >>> Long.numberOfLeadingZeros(mask)) & defaultMask(bits);
-        }
-    }
-
-    /**
-     * Checks if the 2 stamps represent values of the same sign. Returns true if the two stamps are
-     * both positive of null or if they are both strictly negative
-     *
-     * @return true if the two stamps are both positive of null or if they are both strictly
-     *         negative
-     */
-    public static boolean sameSign(IntegerStamp s1, IntegerStamp s2) {
-        return s1.isPositive() && s2.isPositive() || s1.isStrictlyNegative() && s2.isStrictlyNegative();
-    }
-
-    @Override
-    public Constant asConstant() {
-        if (lowerBound == upperBound) {
-            switch (getBits()) {
-                case 1:
-                    return Constant.forBoolean(lowerBound != 0);
-                case 8:
-                    return Constant.forByte((byte) lowerBound);
-                case 16:
-                    return Constant.forShort((short) lowerBound);
-                case 32:
-                    return Constant.forInt((int) lowerBound);
-                case 64:
-                    return Constant.forLong(lowerBound);
-            }
-        }
-        return null;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,337 +0,0 @@
-/*
- * 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.nodes.type;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-
-public class ObjectStamp extends Stamp {
-
-    private final ResolvedJavaType type;
-    private final boolean exactType;
-    private final boolean nonNull;
-    private final boolean alwaysNull;
-
-    public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
-        this.type = type;
-        this.exactType = exactType;
-        this.nonNull = nonNull;
-        this.alwaysNull = alwaysNull;
-    }
-
-    @Override
-    public Stamp unrestricted() {
-        return StampFactory.object();
-    }
-
-    @Override
-    public Stamp illegal() {
-        return new ObjectStamp(null, true, true, false);
-    }
-
-    @Override
-    public boolean isLegal() {
-        return !exactType || (type != null && (isConcreteType(type)));
-    }
-
-    @Override
-    public Kind getStackKind() {
-        return Kind.Object;
-    }
-
-    @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
-        return tool.getObjectKind();
-    }
-
-    @Override
-    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
-        if (type != null) {
-            return type;
-        }
-        return metaAccess.lookupJavaType(Object.class);
-    }
-
-    public boolean nonNull() {
-        return nonNull;
-    }
-
-    public boolean alwaysNull() {
-        return alwaysNull;
-    }
-
-    public ResolvedJavaType type() {
-        return type;
-    }
-
-    public boolean isExactType() {
-        return exactType;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder str = new StringBuilder();
-        str.append('a');
-        str.append(nonNull ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.getName()).append(alwaysNull ? " NULL" : "");
-        return str.toString();
-    }
-
-    @Override
-    public Stamp meet(Stamp otherStamp) {
-        if (this == otherStamp) {
-            return this;
-        }
-        if (!(otherStamp instanceof ObjectStamp)) {
-            return StampFactory.illegal(Kind.Illegal);
-        }
-        ObjectStamp other = (ObjectStamp) otherStamp;
-        ResolvedJavaType meetType;
-        boolean meetExactType;
-        boolean meetNonNull;
-        boolean meetAlwaysNull;
-        if (other.alwaysNull) {
-            meetType = type();
-            meetExactType = exactType;
-            meetNonNull = false;
-            meetAlwaysNull = alwaysNull;
-        } else if (alwaysNull) {
-            meetType = other.type();
-            meetExactType = other.exactType;
-            meetNonNull = false;
-            meetAlwaysNull = other.alwaysNull;
-        } else {
-            meetType = meetTypes(type(), other.type());
-            meetExactType = exactType && other.exactType;
-            if (meetExactType && type != null && other.type != null) {
-                // meeting two valid exact types may result in a non-exact type
-                meetExactType = Objects.equals(meetType, type) && Objects.equals(meetType, other.type);
-            }
-            meetNonNull = nonNull && other.nonNull;
-            meetAlwaysNull = false;
-        }
-
-        if (Objects.equals(meetType, type) && meetExactType == exactType && meetNonNull == nonNull && meetAlwaysNull == alwaysNull) {
-            return this;
-        } else if (Objects.equals(meetType, other.type) && meetExactType == other.exactType && meetNonNull == other.nonNull && meetAlwaysNull == other.alwaysNull) {
-            return other;
-        } else {
-            return new ObjectStamp(meetType, meetExactType, meetNonNull, meetAlwaysNull);
-        }
-    }
-
-    @Override
-    public Stamp join(Stamp otherStamp) {
-        return join0(otherStamp, false);
-    }
-
-    @Override
-    public boolean isCompatible(Stamp other) {
-        if (this == other) {
-            return true;
-        }
-        if (other instanceof ObjectStamp) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns the stamp representing the type of this stamp after a cast to the type represented by
-     * the {@code to} stamp. While this is very similar to a {@link #join} operation, in the case
-     * where both types are not obviously related, the cast operation will prefer the type of the
-     * {@code to} stamp. This is necessary as long as ObjectStamps are not able to accurately
-     * represent intersection types.
-     *
-     * For example when joining the {@link RandomAccess} type with the {@link AbstractList} type,
-     * without intersection types, this would result in the most generic type ({@link Object} ). For
-     * this reason, in some cases a {@code castTo} operation is preferable in order to keep at least
-     * the {@link AbstractList} type.
-     *
-     * @param to the stamp this stamp should be casted to
-     * @return This stamp casted to the {@code to} stamp
-     */
-    public Stamp castTo(ObjectStamp to) {
-        return join0(to, true);
-    }
-
-    private Stamp join0(Stamp otherStamp, boolean castToOther) {
-        if (this == otherStamp) {
-            return this;
-        }
-        if (!(otherStamp instanceof ObjectStamp)) {
-            return StampFactory.illegal(Kind.Illegal);
-        }
-        ObjectStamp other = (ObjectStamp) otherStamp;
-        if (!isLegal()) {
-            return this;
-        } else if (!other.isLegal()) {
-            return other;
-        }
-
-        ResolvedJavaType joinType;
-        boolean joinAlwaysNull = alwaysNull || other.alwaysNull;
-        boolean joinNonNull = nonNull || other.nonNull;
-        boolean joinExactType = exactType || other.exactType;
-        if (Objects.equals(type, other.type)) {
-            joinType = type;
-        } else if (type == null && other.type == null) {
-            joinType = null;
-        } else if (type == null) {
-            joinType = other.type;
-        } else if (other.type == null) {
-            joinType = type;
-        } else {
-            // both types are != null and different
-            if (type.isAssignableFrom(other.type)) {
-                joinType = other.type;
-                if (exactType) {
-                    joinAlwaysNull = true;
-                }
-            } else if (other.type.isAssignableFrom(type)) {
-                joinType = type;
-                if (other.exactType) {
-                    joinAlwaysNull = true;
-                }
-            } else {
-                if (castToOther) {
-                    joinType = other.type;
-                    joinExactType = other.exactType;
-                } else {
-                    joinType = null;
-                }
-                if (joinExactType || (!type.isInterface() && !other.type.isInterface())) {
-                    joinAlwaysNull = true;
-                }
-            }
-        }
-        if (joinAlwaysNull) {
-            joinType = null;
-            joinExactType = false;
-        }
-        if (joinExactType && joinType == null) {
-            return StampFactory.illegal(Kind.Object);
-        }
-        if (joinAlwaysNull && joinNonNull) {
-            return StampFactory.illegal(Kind.Object);
-        } else if (joinExactType && !isConcreteType(joinType)) {
-            return StampFactory.illegal(Kind.Object);
-        }
-        if (Objects.equals(joinType, type) && joinExactType == exactType && joinNonNull == nonNull && joinAlwaysNull == alwaysNull) {
-            return this;
-        } else if (Objects.equals(joinType, other.type) && joinExactType == other.exactType && joinNonNull == other.nonNull && joinAlwaysNull == other.alwaysNull) {
-            return other;
-        } else {
-            return new ObjectStamp(joinType, joinExactType, joinNonNull, joinAlwaysNull);
-        }
-    }
-
-    public static boolean isConcreteType(ResolvedJavaType type) {
-        return !(Modifier.isAbstract(type.getModifiers()) && !type.isArray());
-    }
-
-    private static ResolvedJavaType meetTypes(ResolvedJavaType a, ResolvedJavaType b) {
-        if (Objects.equals(a, b)) {
-            return a;
-        } else if (a == null || b == null) {
-            return null;
-        } else {
-            return a.findLeastCommonAncestor(b);
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + (exactType ? 1231 : 1237);
-        result = prime * result + (nonNull ? 1231 : 1237);
-        result = prime * result + (alwaysNull ? 1231 : 1237);
-        result = prime * result + ((type == null) ? 0 : type.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        }
-        ObjectStamp other = (ObjectStamp) obj;
-        if (exactType != other.exactType || nonNull != other.nonNull || alwaysNull != other.alwaysNull) {
-            return false;
-        }
-        if (type == null) {
-            if (other.type != null) {
-                return false;
-            }
-        } else if (!type.equals(other.type)) {
-            return false;
-        }
-        return true;
-    }
-
-    public static boolean isObjectAlwaysNull(ValueNode node) {
-        return isObjectAlwaysNull(node.stamp());
-    }
-
-    public static boolean isObjectAlwaysNull(Stamp stamp) {
-        return (stamp instanceof ObjectStamp && ((ObjectStamp) stamp).isLegal() && ((ObjectStamp) stamp).alwaysNull());
-    }
-
-    public static boolean isObjectNonNull(ValueNode node) {
-        return isObjectNonNull(node.stamp());
-    }
-
-    public static boolean isObjectNonNull(Stamp stamp) {
-        return stamp instanceof ObjectStamp && ((ObjectStamp) stamp).isLegal() && ((ObjectStamp) stamp).nonNull();
-    }
-
-    public static ResolvedJavaType typeOrNull(ValueNode node) {
-        return typeOrNull(node.stamp());
-    }
-
-    public static ResolvedJavaType typeOrNull(Stamp stamp) {
-        if (stamp instanceof ObjectStamp) {
-            return ((ObjectStamp) stamp).type();
-        }
-        return null;
-    }
-
-    public static boolean isExactType(ValueNode node) {
-        return isExactType(node.stamp());
-    }
-
-    public static boolean isExactType(Stamp stamp) {
-        if (stamp instanceof ObjectStamp) {
-            return ((ObjectStamp) stamp).isExactType();
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/PrimitiveStamp.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.type;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Describes the possible values of a {@link ValueNode} that produces a primitive value as result.
- */
-public abstract class PrimitiveStamp extends Stamp {
-
-    private final int bits;
-
-    protected PrimitiveStamp(int bits) {
-        this.bits = bits;
-    }
-
-    /**
-     * The width in bits of the value described by this stamp.
-     */
-    public int getBits() {
-        return bits;
-    }
-
-    public static int getBits(Stamp stamp) {
-        if (stamp instanceof PrimitiveStamp) {
-            return ((PrimitiveStamp) stamp).getBits();
-        } else {
-            return 0;
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + bits;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof PrimitiveStamp) {
-            PrimitiveStamp other = (PrimitiveStamp) obj;
-            return bits == other.bits;
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.type;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-
-public class StampFactory {
-
-    // JaCoCo Exclude
-
-    private static final Stamp[] stampCache = new Stamp[Kind.values().length];
-    private static final Stamp[] illegalStampCache = new Stamp[Kind.values().length];
-    private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
-    private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
-    private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
-    private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false);
-    private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
-
-    private static void setCache(Kind kind, Stamp stamp) {
-        stampCache[kind.ordinal()] = stamp;
-    }
-
-    private static void setIntCache(Kind kind) {
-        int bits = kind.getStackKind().getBitCount();
-        long mask;
-        if (kind.isUnsigned()) {
-            mask = IntegerStamp.defaultMask(kind.getBitCount());
-        } else {
-            mask = IntegerStamp.defaultMask(bits);
-        }
-        setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
-    }
-
-    private static void setFloatCache(Kind kind) {
-        setCache(kind, new FloatStamp(kind.getBitCount()));
-    }
-
-    static {
-        setIntCache(Kind.Boolean);
-        setIntCache(Kind.Byte);
-        setIntCache(Kind.Short);
-        setIntCache(Kind.Char);
-        setIntCache(Kind.Int);
-        setIntCache(Kind.Long);
-
-        setFloatCache(Kind.Float);
-        setFloatCache(Kind.Double);
-
-        setCache(Kind.Object, objectStamp);
-        setCache(Kind.Void, VoidStamp.getInstance());
-
-        for (Kind k : Kind.values()) {
-            if (stampCache[k.ordinal()] != null) {
-                illegalStampCache[k.ordinal()] = stampCache[k.ordinal()].illegal();
-            } else {
-                illegalStampCache[k.ordinal()] = IllegalStamp.getInstance();
-            }
-        }
-    }
-
-    /**
-     * Return a stamp for a Java kind, as it would be represented on the bytecode stack.
-     */
-    public static Stamp forKind(Kind kind) {
-        assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")";
-        return stampCache[kind.ordinal()];
-    }
-
-    /**
-     * Return the stamp for the {@code void} type. This will return a singleton instance than can be
-     * compared using {@code ==}.
-     */
-    public static Stamp forVoid() {
-        return VoidStamp.getInstance();
-    }
-
-    /**
-     * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an
-     * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated.
-     */
-    public static Stamp forNodeIntrinsic() {
-        return nodeIntrinsicStamp;
-    }
-
-    public static Stamp intValue() {
-        return forKind(Kind.Int);
-    }
-
-    public static Stamp positiveInt() {
-        return positiveInt;
-    }
-
-    public static Stamp illegal() {
-        return illegal(Kind.Illegal);
-    }
-
-    public static Stamp illegal(Kind kind) {
-        return illegalStampCache[kind.ordinal()];
-    }
-
-    public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound, long downMask, long upMask) {
-        return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
-    }
-
-    public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound) {
-        return forInteger(kind.getBitCount(), lowerBound, upperBound);
-    }
-
-    public static IntegerStamp forInteger(int bits) {
-        return new IntegerStamp(bits, IntegerStamp.defaultMinValue(bits), IntegerStamp.defaultMaxValue(bits), 0, IntegerStamp.defaultMask(bits));
-    }
-
-    public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
-        long defaultMask = IntegerStamp.defaultMask(bits);
-        if (lowerBound == upperBound) {
-            return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask);
-        }
-        final long downMask;
-        final long upMask;
-        if (lowerBound >= 0) {
-            int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound);
-            long differentBits = lowerBound ^ upperBound;
-            int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
-
-            upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount);
-            downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
-        } else {
-            if (upperBound >= 0) {
-                upMask = defaultMask;
-                downMask = 0;
-            } else {
-                int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound);
-                long differentBits = lowerBound ^ upperBound;
-                int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
-
-                upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
-                downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
-            }
-        }
-        return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask);
-    }
-
-    public static FloatStamp forFloat(Kind kind, double lowerBound, double upperBound, boolean nonNaN) {
-        assert kind.isNumericFloat();
-        return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN);
-    }
-
-    public static Stamp forConstant(Constant value) {
-        Kind kind = value.getKind();
-        switch (kind) {
-            case Boolean:
-            case Byte:
-            case Char:
-            case Short:
-            case Int:
-            case Long:
-                long mask = value.asLong() & IntegerStamp.defaultMask(kind.getBitCount());
-                return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask);
-            case Float:
-                return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
-            case Double:
-                return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
-            case Illegal:
-                return illegal(Kind.Illegal);
-            case Object:
-                if (value.isNull()) {
-                    return alwaysNull();
-                } else {
-                    return objectNonNull();
-                }
-            default:
-                throw new GraalInternalError("unexpected kind: %s", kind);
-        }
-    }
-
-    public static Stamp forConstant(Constant value, MetaAccessProvider metaAccess) {
-        assert value.getKind() == Kind.Object;
-        if (value.getKind() == Kind.Object) {
-            ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value);
-            return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
-        } else {
-            throw new GraalInternalError(Kind.Object + " expected, actual kind: %s", value.getKind());
-        }
-    }
-
-    public static Stamp object() {
-        return objectStamp;
-    }
-
-    public static Stamp objectNonNull() {
-        return objectNonNullStamp;
-    }
-
-    public static Stamp alwaysNull() {
-        return objectAlwaysNullStamp;
-    }
-
-    public static Stamp declared(ResolvedJavaType type) {
-        return declared(type, false);
-    }
-
-    public static Stamp declaredNonNull(ResolvedJavaType type) {
-        return declared(type, true);
-    }
-
-    public static Stamp declared(ResolvedJavaType type, boolean nonNull) {
-        return object(type, false, nonNull);
-    }
-
-    public static Stamp object(ResolvedJavaType type, boolean exactType, boolean nonNull) {
-        assert type != null;
-        assert type.getKind() == Kind.Object;
-        ResolvedJavaType exact = type.asExactType();
-        if (exact != null) {
-            assert !exactType || type.equals(exact);
-            return new ObjectStamp(exact, true, nonNull, false);
-        } else {
-            return new ObjectStamp(type, exactType, nonNull, false);
-        }
-    }
-
-    public static Stamp exactNonNull(ResolvedJavaType type) {
-        if (ObjectStamp.isConcreteType(type)) {
-            return new ObjectStamp(type, true, true, false);
-        } else {
-            return illegal(Kind.Object);
-        }
-    }
-
-    public static Stamp exact(ResolvedJavaType type) {
-        return new ObjectStamp(type, true, false, false);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampProvider.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.type;
-
-import com.oracle.graal.compiler.common.type.*;
-
-public interface StampProvider {
-
-    Stamp stamp();
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 
 /**
@@ -104,6 +105,37 @@
         return stamp1.unrestricted();
     }
 
+    public static Stamp rem(Stamp stamp1, Stamp stamp2) {
+        if (stamp1 instanceof IntegerStamp && stamp2 instanceof IntegerStamp) {
+            return rem((IntegerStamp) stamp1, (IntegerStamp) stamp2);
+        }
+        return StampFactory.illegal();
+    }
+
+    public static Stamp rem(IntegerStamp stamp1, IntegerStamp stamp2) {
+        assert stamp1.getBits() == stamp2.getBits();
+        long magnitude; // the maximum absolute value of the result
+        if (stamp2.lowerBound() == IntegerStamp.defaultMinValue(stamp2.getBits())) {
+            // Math.abs(...) - 1 does not work in this case
+            magnitude = IntegerStamp.defaultMaxValue(stamp2.getBits());
+        } else {
+            magnitude = Math.max(Math.abs(stamp2.lowerBound()), Math.abs(stamp2.upperBound())) - 1;
+        }
+        long lowerBound = Math.max(stamp1.lowerBound(), -magnitude);
+        if (stamp1.upperBound() > magnitude) {
+            // if the result can wrap around at the upper bound, it can reach any value between 0
+            // and magnitude
+            lowerBound = Math.min(lowerBound, 0);
+        }
+        long upperBound = Math.min(stamp1.upperBound(), magnitude);
+        if (stamp1.lowerBound() < -magnitude) {
+            // if the result can wrap around at the lower bound, it can reach any value between
+            // -magnitude and 0
+            upperBound = Math.max(upperBound, 0);
+        }
+        return StampFactory.forInteger(stamp1.getBits(), lowerBound, upperBound);
+    }
+
     private static boolean addOverflowsPositively(long x, long y, int bits) {
         long result = x + y;
         if (bits == 64) {
@@ -451,4 +483,110 @@
         }
         return null;
     }
+
+    /**
+     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#isLegal() legal} Object
+     * value which is known to be always null.
+     *
+     * @param node the node to check
+     * @return true if this node represents a legal object value which is known to be always null
+     */
+    public static boolean isObjectAlwaysNull(ValueNode node) {
+        return isObjectAlwaysNull(node.stamp());
+    }
+
+    /**
+     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} Object
+     * stamp whose values are known to be always null.
+     *
+     * @param stamp the stamp to check
+     * @return true if this stamp represents a legal object stamp whose values are known to be
+     *         always null
+     */
+    public static boolean isObjectAlwaysNull(Stamp stamp) {
+        if (stamp instanceof ObjectStamp && stamp.isLegal()) {
+            return ((ObjectStamp) stamp).alwaysNull();
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#isLegal() legal} Object
+     * value which is known to never be null.
+     *
+     * @param node the node to check
+     * @return true if this node represents a legal object value which is known to never be null
+     */
+    public static boolean isObjectNonNull(ValueNode node) {
+        return isObjectNonNull(node.stamp());
+    }
+
+    /**
+     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} Object
+     * stamp whose values known to be always null.
+     *
+     * @param stamp the stamp to check
+     * @return true if this stamp represents a legal object stamp whose values are known to be
+     *         always null
+     */
+    public static boolean isObjectNonNull(Stamp stamp) {
+        if (stamp instanceof ObjectStamp && stamp.isLegal()) {
+            return ((ObjectStamp) stamp).nonNull();
+        }
+        return false;
+    }
+
+    /**
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is
+     * a {@linkplain Stamp#isLegal() legal} Object value.
+     *
+     * @param node the node to check
+     * @return the Java type this value has if it is a legal Object type, null otherwise
+     */
+    public static ResolvedJavaType typeOrNull(ValueNode node) {
+        return typeOrNull(node.stamp());
+    }
+
+    /**
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a
+     * {@linkplain Stamp#isLegal() legal} Object stamp.
+     *
+     * @param stamp the stamp to check
+     * @return the Java type this stamp has if it is a legal Object stamp, null otherwise
+     */
+    public static ResolvedJavaType typeOrNull(Stamp stamp) {
+        if (stamp instanceof ObjectStamp && stamp.isLegal()) {
+            return ((ObjectStamp) stamp).type();
+        }
+        return null;
+    }
+
+    /**
+     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#isLegal() legal} Object
+     * value whose Java type is known exactly. If this method returns true then the
+     * {@linkplain ResolvedJavaType Java type} returned by {@link #typeOrNull(ValueNode)} is the
+     * concrete dynamic/runtime Java type of this value.
+     *
+     * @param node the node to check
+     * @return true if this node represents a legal object value whose Java type is known exactly
+     */
+    public static boolean isExactType(ValueNode node) {
+        return isExactType(node.stamp());
+    }
+
+    /**
+     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} Object
+     * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns
+     * true then the Java type returned by {@link #typeOrNull(Stamp)} is the only concrete
+     * dynamic/runtime Java type possible for values of this stamp.
+     *
+     * @param stamp the stamp to check
+     * @return true if this node represents a legal object stamp whose Java type is known exactly
+     */
+    public static boolean isExactType(Stamp stamp) {
+        if (stamp instanceof ObjectStamp && stamp.isLegal()) {
+            return ((ObjectStamp) stamp).isExactType();
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/VoidStamp.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.type;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.type.*;
-
-/**
- * Singleton stamp representing the value of type {@code void}.
- */
-public final class VoidStamp extends Stamp {
-
-    private VoidStamp() {
-    }
-
-    @Override
-    public Stamp unrestricted() {
-        return this;
-    }
-
-    @Override
-    public Kind getStackKind() {
-        return Kind.Void;
-    }
-
-    @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
-        throw GraalInternalError.shouldNotReachHere("void stamp has no value");
-    }
-
-    @Override
-    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
-        return metaAccess.lookupJavaType(Void.TYPE);
-    }
-
-    @Override
-    public String toString() {
-        return "void";
-    }
-
-    @Override
-    public boolean alwaysDistinct(Stamp other) {
-        return this != other;
-    }
-
-    @Override
-    public Stamp meet(Stamp other) {
-        if (other instanceof IllegalStamp) {
-            return other.join(this);
-        }
-        if (this == other) {
-            return this;
-        }
-        return StampFactory.illegal(Kind.Illegal);
-    }
-
-    @Override
-    public Stamp join(Stamp other) {
-        if (other instanceof IllegalStamp) {
-            return other.join(this);
-        }
-        if (this == other) {
-            return this;
-        }
-        return StampFactory.illegal(Kind.Illegal);
-    }
-
-    @Override
-    public boolean isCompatible(Stamp stamp) {
-        return this == stamp;
-    }
-
-    @Override
-    public Stamp illegal() {
-        // there is no illegal void stamp
-        return this;
-    }
-
-    @Override
-    public boolean isLegal() {
-        return true;
-    }
-
-    private static VoidStamp instance = new VoidStamp();
-
-    static VoidStamp getInstance() {
-        return instance;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
@@ -42,12 +43,12 @@
         }
     };
 
-    public static void killCFG(Node node) {
+    public static void killCFG(Node node, SimplifierTool tool) {
         assert node.isAlive();
         if (node instanceof AbstractEndNode) {
             // We reached a control flow end.
             AbstractEndNode end = (AbstractEndNode) node;
-            killEnd(end);
+            killEnd(end, tool);
         } else {
             // Normal control flow node.
             /*
@@ -57,18 +58,23 @@
              * while processing one branch.
              */
             for (Node successor : node.successors()) {
-                killCFG(successor);
+                killCFG(successor, tool);
             }
         }
         propagateKill(node);
     }
 
-    private static void killEnd(AbstractEndNode end) {
+    public static void killCFG(Node node) {
+        killCFG(node, null);
+    }
+
+    private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
         MergeNode merge = end.merge();
         if (merge != null) {
             merge.removeEnd(end);
             StructuredGraph graph = end.graph();
-            if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { // dead loop
+            if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) {
+                // dead loop
                 for (PhiNode phi : merge.phis().snapshot()) {
                     propagateKill(phi);
                 }
@@ -85,12 +91,17 @@
                     killCFG(loopBody);
                 }
                 begin.safeDelete();
-            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not
-                                                                                                         // a
-                                                                                                         // loop
-                                                                                                         // anymore
+            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
+                // not a loop anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
+                }
                 graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
-            } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore
+            } else if (merge.phiPredecessorCount() == 1) {
+                // not a merge anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
+                }
                 graph.reduceTrivialMerge(merge);
             }
         }
@@ -137,6 +148,13 @@
     }
 
     public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) {
+        if (fixed instanceof StateSplit) {
+            FrameState stateAfter = ((StateSplit) fixed).stateAfter();
+            ((StateSplit) fixed).setStateAfter(null);
+            if (stateAfter.usages().isEmpty()) {
+                killWithUnusedFloatingInputs(stateAfter);
+            }
+        }
         FixedNode next = fixed.next();
         fixed.setNext(null);
         fixed.replaceAtPredecessor(next);
@@ -326,6 +344,14 @@
         return v;
     }
 
+    public static boolean tryKillUnused(Node node) {
+        if (node.isAlive() && isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
+            killWithUnusedFloatingInputs(node);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Exhaustive search for {@link GraphUtil#originalValue(ValueNode)} when a simple search fails.
      * This can happen in the presence of complicated phi/proxy/phi constructs.
@@ -383,4 +409,32 @@
             return true;
         }
     }
+
+    /**
+     * Returns an iterator that will return the given node followed by all its predecessors, up
+     * until the point where {@link Node#predecessor()} returns null;
+     *
+     * @param start the node at which to start iterating
+     */
+    public static NodeIterable<FixedNode> predecessorIterable(final FixedNode start) {
+        return new NodeIterable<FixedNode>() {
+            public Iterator<FixedNode> iterator() {
+                return new Iterator<FixedNode>() {
+                    public FixedNode current = start;
+
+                    public boolean hasNext() {
+                        return current != null;
+                    }
+
+                    public FixedNode next() {
+                        try {
+                            return current;
+                        } finally {
+                            current = (FixedNode) current.predecessor();
+                        }
+                    }
+                };
+            }
+        };
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.util;
-
-import java.util.*;
-
-import com.oracle.graal.nodes.*;
-
-public class NodesToDoubles {
-
-    private final IdentityHashMap<FixedNode, Double> nodeProbabilities;
-
-    public NodesToDoubles(int numberOfNodes) {
-        this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes);
-    }
-
-    public void put(FixedNode n, double value) {
-        assert value >= 0.0 : value;
-        nodeProbabilities.put(n, value);
-    }
-
-    public boolean contains(FixedNode n) {
-        return nodeProbabilities.containsKey(n);
-    }
-
-    public double get(FixedNode n) {
-        Double value = nodeProbabilities.get(n);
-        assert value != null;
-        return value;
-    }
-
-    public int getCount() {
-        return nodeProbabilities.size();
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.nodes.virtual;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Selects one object from a {@link CommitAllocationNode}. The object is identified by its
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,12 +25,12 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(nameTemplate = "Alloc {i#virtualObjects}", allowedUsageTypes = {InputType.Extension})
 public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,10 @@
 package com.oracle.graal.nodes.virtual;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable, IterableNodeType {
 
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Fri May 30 15:09:09 2014 +0200
@@ -40,8 +40,10 @@
  *
  * <pre>
  * ServiceLoader&lt;Options&gt; sl = ServiceLoader.loadInstalled(Options.class);
- * for (OptionDescriptor desc : sl) {
- *     // use desc
+ * for (Options opts : sl) {
+ *     for (OptionDescriptor desc : sl) {
+ *         // use desc
+ *     }
  * }
  * </pre>
  */
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -137,9 +137,9 @@
         protected void run(StructuredGraph graph) {
             boolean wholeGraph = newNodesMark == null || newNodesMark.isStart();
             if (initWorkingSet == null) {
-                workList = graph.createNodeWorkList(wholeGraph, MAX_ITERATION_PER_NODE);
+                workList = graph.createIterativeNodeWorkList(wholeGraph, MAX_ITERATION_PER_NODE);
             } else {
-                workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE);
+                workList = graph.createIterativeNodeWorkList(false, MAX_ITERATION_PER_NODE);
                 workList.addAll(initWorkingSet);
             }
             if (!wholeGraph) {
@@ -154,7 +154,7 @@
 
                 @Override
                 public void nodeChanged(Node node) {
-                    workList.addAgain(node);
+                    workList.add(node);
                 }
             };
             graph.trackInputChange(nodeChangedListener);
@@ -178,17 +178,20 @@
                 }
                 StructuredGraph graph = (StructuredGraph) node.graph();
                 Mark mark = graph.getMark();
-                if (!tryKillUnused(node)) {
+                if (!GraphUtil.tryKillUnused(node)) {
                     if (!tryCanonicalize(node, nodeClass)) {
                         if (node instanceof ValueNode) {
                             ValueNode valueNode = (ValueNode) node;
                             boolean improvedStamp = tryInferStamp(valueNode);
                             Constant constant = valueNode.stamp().asConstant();
                             if (constant != null && !(node instanceof ConstantNode)) {
-                                performReplacement(valueNode, ConstantNode.forConstant(valueNode.stamp(), constant, context.getMetaAccess(), valueNode.graph()));
+                                valueNode.replaceAtUsages(InputType.Value, ConstantNode.forConstant(valueNode.stamp(), constant, context.getMetaAccess(), graph));
+                                GraphUtil.tryKillUnused(valueNode);
                             } else if (improvedStamp) {
                                 // the improved stamp may enable additional canonicalization
-                                tryCanonicalize(valueNode, nodeClass);
+                                if (!tryCanonicalize(valueNode, nodeClass)) {
+                                    valueNode.usages().forEach(workList::add);
+                                }
                             }
                         }
                     }
@@ -200,14 +203,6 @@
             }
         }
 
-        private static boolean tryKillUnused(Node node) {
-            if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
-                GraphUtil.killWithUnusedFloatingInputs(node);
-                return true;
-            }
-            return false;
-        }
-
         public static boolean tryGlobalValueNumbering(Node node, NodeClass nodeClass) {
             if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) {
                 Node newNode = node.graph().findDuplicate(node);
@@ -341,7 +336,7 @@
                 if (node.inferStamp()) {
                     METRIC_STAMP_CHANGED.increment();
                     for (Node usage : node.usages()) {
-                        workList.addAgain(usage);
+                        workList.add(usage);
                     }
                     return true;
                 }
@@ -354,7 +349,7 @@
             @Override
             public void deleteBranch(Node branch) {
                 branch.predecessor().replaceFirstSuccessor(branch, null);
-                GraphUtil.killCFG(branch);
+                GraphUtil.killCFG(branch, this);
             }
 
             /**
@@ -378,12 +373,12 @@
 
             @Override
             public void addToWorkList(Node node) {
-                workList.addAgain(node);
+                workList.add(node);
             }
 
             @Override
             public void removeIfUnused(Node node) {
-                tryKillUnused(node);
+                GraphUtil.tryKillUnused(node);
             }
 
             @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,8 @@
  */
 package com.oracle.graal.phases.common;
 
-import java.lang.reflect.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -102,37 +103,37 @@
 
     public static class State extends MergeableState<State> implements Cloneable {
 
-        private IdentityHashMap<ValueNode, ResolvedJavaType> knownTypes;
+        private Map<ValueNode, ResolvedJavaType> knownTypes;
         private HashSet<ValueNode> knownNonNull;
         private HashSet<ValueNode> knownNull;
-        private IdentityHashMap<LogicNode, ValueNode> trueConditions;
-        private IdentityHashMap<LogicNode, ValueNode> falseConditions;
-        private IdentityHashMap<ValueNode, GuardedStamp> valueConstraints;
+        private Map<LogicNode, ValueNode> trueConditions;
+        private Map<LogicNode, ValueNode> falseConditions;
+        private Map<ValueNode, GuardedStamp> valueConstraints;
 
         public State() {
-            this.knownTypes = new IdentityHashMap<>();
+            this.knownTypes = newNodeIdentityMap();
             this.knownNonNull = new HashSet<>();
             this.knownNull = new HashSet<>();
-            this.trueConditions = new IdentityHashMap<>();
-            this.falseConditions = new IdentityHashMap<>();
-            this.valueConstraints = new IdentityHashMap<>();
+            this.trueConditions = newNodeIdentityMap();
+            this.falseConditions = newNodeIdentityMap();
+            this.valueConstraints = newNodeIdentityMap();
         }
 
         public State(State other) {
-            this.knownTypes = new IdentityHashMap<>(other.knownTypes);
+            this.knownTypes = newNodeIdentityMap(other.knownTypes);
             this.knownNonNull = new HashSet<>(other.knownNonNull);
             this.knownNull = new HashSet<>(other.knownNull);
-            this.trueConditions = new IdentityHashMap<>(other.trueConditions);
-            this.falseConditions = new IdentityHashMap<>(other.falseConditions);
-            this.valueConstraints = new IdentityHashMap<>(other.valueConstraints);
+            this.trueConditions = newNodeIdentityMap(other.trueConditions);
+            this.falseConditions = newNodeIdentityMap(other.falseConditions);
+            this.valueConstraints = newNodeIdentityMap(other.valueConstraints);
         }
 
         @Override
         public boolean merge(MergeNode merge, List<State> withStates) {
-            IdentityHashMap<ValueNode, ResolvedJavaType> newKnownTypes = new IdentityHashMap<>();
-            IdentityHashMap<LogicNode, ValueNode> newTrueConditions = new IdentityHashMap<>();
-            IdentityHashMap<LogicNode, ValueNode> newFalseConditions = new IdentityHashMap<>();
-            IdentityHashMap<ValueNode, GuardedStamp> newValueConstraints = new IdentityHashMap<>();
+            Map<ValueNode, ResolvedJavaType> newKnownTypes = newNodeIdentityMap();
+            Map<LogicNode, ValueNode> newTrueConditions = newNodeIdentityMap();
+            Map<LogicNode, ValueNode> newFalseConditions = newNodeIdentityMap();
+            Map<ValueNode, GuardedStamp> newValueConstraints = newNodeIdentityMap();
 
             HashSet<ValueNode> newKnownNull = new HashSet<>(knownNull);
             HashSet<ValueNode> newKnownNonNull = new HashSet<>(knownNonNull);
@@ -152,7 +153,7 @@
                         break;
                     }
                 }
-                if (type != null && type != ObjectStamp.typeOrNull(node)) {
+                if (type != null && type != StampTool.typeOrNull(node)) {
                     newKnownTypes.put(node, type);
                 }
             }
@@ -235,15 +236,15 @@
 
         public ResolvedJavaType getNodeType(ValueNode node) {
             ResolvedJavaType result = knownTypes.get(GraphUtil.unproxify(node));
-            return result == null ? ObjectStamp.typeOrNull(node) : result;
+            return result == null ? StampTool.typeOrNull(node) : result;
         }
 
         public boolean isNull(ValueNode value) {
-            return ObjectStamp.isObjectAlwaysNull(value) || knownNull.contains(GraphUtil.unproxify(value));
+            return StampTool.isObjectAlwaysNull(value) || knownNull.contains(GraphUtil.unproxify(value));
         }
 
         public boolean isNonNull(ValueNode value) {
-            return ObjectStamp.isObjectNonNull(value) || knownNonNull.contains(GraphUtil.unproxify(value));
+            return StampTool.isObjectNonNull(value) || knownNonNull.contains(GraphUtil.unproxify(value));
         }
 
         @Override
@@ -331,12 +332,12 @@
         }
     }
 
-    public class ConditionalElimination extends PostOrderNodeIterator<State> {
+    public class ConditionalElimination extends SinglePassNodeIterator<State> {
 
         private final LogicNode trueConstant;
         private final LogicNode falseConstant;
 
-        public ConditionalElimination(FixedNode start, State initialState) {
+        public ConditionalElimination(StartNode start, State initialState) {
             super(start, initialState);
             trueConstant = LogicConstantNode.tautology(graph);
             falseConstant = LogicConstantNode.contradiction(graph);
@@ -350,6 +351,7 @@
             if (falseConstant.usages().isEmpty()) {
                 graph.removeFloating(falseConstant);
             }
+            super.finished();
         }
 
         private void registerCondition(boolean isTrue, LogicNode condition, ValueNode anchor) {
@@ -708,7 +710,9 @@
                     if (nonNull) {
                         replacementAnchor = searchAnchor(GraphUtil.unproxify(object), type);
                     }
-                    replacementAnchor = BeginNode.prevBegin(checkCast);
+                    if (replacementAnchor == null) {
+                        replacementAnchor = BeginNode.prevBegin(checkCast);
+                    }
                     PiNode piNode;
                     if (isNull) {
                         ConstantNode nullObject = ConstantNode.defaultForKind(Kind.Object, graph);
@@ -812,10 +816,10 @@
                     ValueNode receiver = callTarget.receiver();
                     if (receiver != null && (callTarget.invokeKind() == InvokeKind.Interface || callTarget.invokeKind() == InvokeKind.Virtual)) {
                         ResolvedJavaType type = state.getNodeType(receiver);
-                        if (!Objects.equals(type, ObjectStamp.typeOrNull(receiver))) {
-                            ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
+                        if (!Objects.equals(type, StampTool.typeOrNull(receiver))) {
+                            ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod(), invoke.getContextType());
                             if (method != null) {
-                                if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
+                                if (method.canBeStaticallyBound() || type.isFinal()) {
                                     callTarget.setInvokeKind(InvokeKind.Special);
                                     callTarget.setTargetMethod(method);
                                 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -35,27 +35,20 @@
 /**
  * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
  * {@link ControlSplitNode ControlSplitNodes} with {@link FixedGuardNode FixedGuardNodes}.
- * 
+ *
  * This is useful because {@link FixedGuardNode FixedGuardNodes} will be lowered to
  * {@link GuardNode GuardNodes} which can later be optimized more aggressively than control-flow
  * constructs.
- * 
+ *
  * This is currently only done for branches that start from a {@link IfNode}. If it encounters a
  * branch starting at an other kind of {@link ControlSplitNode}, it will only bring the
  * {@link DeoptimizeNode} as close to the {@link ControlSplitNode} as possible.
- * 
+ *
  */
 public class ConvertDeoptimizeToGuardPhase extends Phase {
 
     private static BeginNode findBeginNode(FixedNode startNode) {
-        Node n = startNode;
-        while (true) {
-            if (n instanceof BeginNode) {
-                return (BeginNode) n;
-            } else {
-                n = n.predecessor();
-            }
-        }
+        return GraphUtil.predecessorIterable(startNode).filter(BeginNode.class).first();
     }
 
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -26,9 +26,9 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -62,7 +62,7 @@
                         merge.addForwardEnd(firstEnd);
                         reasonActionPhi.addInput(((AbstractDeoptimizeNode) target).getActionAndReason(context.getMetaAccess()));
                         speculationPhi.addInput(((AbstractDeoptimizeNode) target).getSpeculation(context.getMetaAccess()));
-                        target.predecessor().replaceFirstSuccessor(target, firstEnd);
+                        target.replaceAtPredecessor(firstEnd);
 
                         exitLoops((AbstractDeoptimizeNode) target, firstEnd, cfg);
 
@@ -77,7 +77,7 @@
                     merge.addForwardEnd(newEnd);
                     reasonActionPhi.addInput(deopt.getActionAndReason(context.getMetaAccess()));
                     speculationPhi.addInput(deopt.getSpeculation(context.getMetaAccess()));
-                    deopt.predecessor().replaceFirstSuccessor(deopt, newEnd);
+                    deopt.replaceAtPredecessor(newEnd);
                     exitLoops(deopt, newEnd, cfg);
                     obsoletes.add(deopt);
                 }
@@ -95,8 +95,8 @@
         Block block = cfg.blockFor(deopt);
         Loop<Block> loop = block.getLoop();
         while (loop != null) {
-            end.graph().addBeforeFixed(end, end.graph().add(new LoopExitNode((LoopBeginNode) loop.header.getBeginNode())));
-            loop = loop.parent;
+            end.graph().addBeforeFixed(end, end.graph().add(new LoopExitNode((LoopBeginNode) loop.getHeader().getBeginNode())));
+            loop = loop.getParent();
         }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.phases.common;
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
 
 import java.util.*;
 
@@ -43,19 +44,19 @@
 
     public static class MemoryMapImpl extends MemoryMapNode {
 
-        private IdentityHashMap<LocationIdentity, MemoryNode> lastMemorySnapshot;
+        private final Map<LocationIdentity, MemoryNode> lastMemorySnapshot;
 
         public MemoryMapImpl(MemoryMapImpl memoryMap) {
-            lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
+            lastMemorySnapshot = newIdentityMap(memoryMap.lastMemorySnapshot);
         }
 
         public MemoryMapImpl(StartNode start) {
-            this();
+            lastMemorySnapshot = newIdentityMap();
             lastMemorySnapshot.put(ANY_LOCATION, start);
         }
 
         public MemoryMapImpl() {
-            lastMemorySnapshot = new IdentityHashMap<>();
+            lastMemorySnapshot = newIdentityMap();
         }
 
         @Override
@@ -91,12 +92,15 @@
         }
 
         @Override
-        public void replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
+        public boolean replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
+            boolean replaced = false;
             for (Map.Entry<LocationIdentity, MemoryNode> entry : lastMemorySnapshot.entrySet()) {
                 if (entry.getValue() == oldNode) {
                     entry.setValue(newNode);
+                    replaced = true;
                 }
             }
+            return replaced;
         }
     }
 
@@ -112,9 +116,9 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = new IdentityHashMap<>();
-        ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet<LocationIdentity>(), null);
-        ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, execmode), graph.start(), new MemoryMapImpl(graph.start()), null);
+        Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = newNodeIdentityMap();
+        ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet<LocationIdentity>());
+        ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, execmode), graph.start(), new MemoryMapImpl(graph.start()));
         if (execmode == ExecutionMode.CREATE_FLOATING_READS) {
             assert !graph.isAfterFloatingReadPhase();
             graph.setAfterFloatingReadPhase(true);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -107,8 +107,9 @@
     protected void run(StructuredGraph graph) {
         assert graph.getGuardsStage().ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal() && checkFixedDeopts(graph);
         if (graph.getGuardsStage().ordinal() < GuardsStage.AFTER_FSA.ordinal()) {
-            ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null);
+            ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null);
             graph.setGuardsStage(GuardsStage.AFTER_FSA);
+            graph.getNodes(FrameState.class).filter(state -> state.usages().isEmpty()).forEach(GraphUtil::killWithUnusedFloatingInputs);
         }
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,8 @@
  */
 package com.oracle.graal.phases.common;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
 
 import java.util.*;
 import java.util.Map.Entry;
@@ -61,7 +62,7 @@
 
     private static class UseImplicitNullChecks extends ScheduledNodeIterator {
 
-        private final IdentityHashMap<ValueNode, GuardNode> nullGuarded = new IdentityHashMap<>();
+        private final Map<ValueNode, GuardNode> nullGuarded = newIdentityMap();
         private final int implicitNullCheckLimit;
 
         UseImplicitNullChecks(int implicitNullCheckLimit) {
@@ -178,9 +179,9 @@
             Loop<Block> loop = block.getLoop();
             StructuredGraph graph = deopt.graph();
             while (loop != null) {
-                LoopExitNode exit = graph.add(new LoopExitNode((LoopBeginNode) loop.header.getBeginNode()));
+                LoopExitNode exit = graph.add(new LoopExitNode((LoopBeginNode) loop.getHeader().getBeginNode()));
                 graph.addBeforeFixed(deopt, exit);
-                loop = loop.parent;
+                loop = loop.getParent();
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -40,6 +40,11 @@
         this.canonicalizer = canonicalizer;
     }
 
+    public IncrementalCanonicalizerPhase(CanonicalizerPhase canonicalizer, BasePhase<? super C> phase) {
+        this.canonicalizer = canonicalizer;
+        appendPhase(phase);
+    }
+
     @Override
     protected void run(StructuredGraph graph, C context) {
         Mark newNodesMark = graph.getMark();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,856 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.common;
-
-import static com.oracle.graal.phases.GraalOptions.*;
-import static com.oracle.graal.phases.common.InliningPhase.Options.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.InliningUtil.InlineInfo;
-import com.oracle.graal.phases.common.InliningUtil.Inlineable;
-import com.oracle.graal.phases.common.InliningUtil.InlineableGraph;
-import com.oracle.graal.phases.common.InliningUtil.InlineableMacroNode;
-import com.oracle.graal.phases.common.InliningUtil.InliningPolicy;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-
-public class InliningPhase extends AbstractInliningPhase {
-
-    static class Options {
-
-        // @formatter:off
-        @Option(help = "Unconditionally inline intrinsics")
-        public static final OptionValue<Boolean> AlwaysInlineIntrinsics = new OptionValue<>(false);
-        // @formatter:on
-    }
-
-    private final InliningPolicy inliningPolicy;
-    private final CanonicalizerPhase canonicalizer;
-
-    private int inliningCount;
-    private int maxMethodPerInlining = Integer.MAX_VALUE;
-
-    // Metrics
-    private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
-    private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
-    private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
-    private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
-
-    public InliningPhase(CanonicalizerPhase canonicalizer) {
-        this(new GreedyInliningPolicy(null), canonicalizer);
-    }
-
-    public InliningPhase(Map<Invoke, Double> hints, CanonicalizerPhase canonicalizer) {
-        this(new GreedyInliningPolicy(hints), canonicalizer);
-    }
-
-    public InliningPhase(InliningPolicy policy, CanonicalizerPhase canonicalizer) {
-        this.inliningPolicy = policy;
-        this.canonicalizer = canonicalizer;
-    }
-
-    public void setMaxMethodsPerInlining(int max) {
-        maxMethodPerInlining = max;
-    }
-
-    public int getInliningCount() {
-        return inliningCount;
-    }
-
-    @Override
-    protected void run(final StructuredGraph graph, final HighTierContext context) {
-        final InliningData data = new InliningData(graph, context.getAssumptions());
-
-        while (data.hasUnprocessedGraphs()) {
-            final MethodInvocation currentInvocation = data.currentInvocation();
-            GraphInfo graphInfo = data.currentGraph();
-            if (!currentInvocation.isRoot() &&
-                            !inliningPolicy.isWorthInlining(context.getReplacements(), currentInvocation.callee(), data.inliningDepth(), currentInvocation.probability(),
-                                            currentInvocation.relevance(), false)) {
-                int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
-                assert remainingGraphs > 0;
-                data.popGraphs(remainingGraphs);
-                data.popInvocation();
-            } else if (graphInfo.hasRemainingInvokes() && inliningPolicy.continueInlining(graphInfo.graph())) {
-                processNextInvoke(data, graphInfo, context);
-            } else {
-                data.popGraph();
-                if (!currentInvocation.isRoot()) {
-                    assert currentInvocation.callee().invoke().asNode().isAlive();
-                    currentInvocation.incrementProcessedGraphs();
-                    if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
-                        data.popInvocation();
-                        final MethodInvocation parentInvoke = data.currentInvocation();
-                        try (Scope s = Debug.scope("Inlining", data.inliningContext())) {
-                            tryToInline(data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1, context);
-                        } catch (Throwable e) {
-                            throw Debug.handle(e);
-                        }
-                    }
-                }
-            }
-        }
-
-        assert data.inliningDepth() == 0;
-        assert data.graphCount() == 0;
-    }
-
-    /**
-     * Process the next invoke and enqueue all its graphs for processing.
-     */
-    private void processNextInvoke(InliningData data, GraphInfo graphInfo, HighTierContext context) {
-        Invoke invoke = graphInfo.popInvoke();
-        MethodInvocation callerInvocation = data.currentInvocation();
-        Assumptions parentAssumptions = callerInvocation.assumptions();
-        InlineInfo info = InliningUtil.getInlineInfo(data, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations());
-
-        if (info != null) {
-            double invokeProbability = graphInfo.invokeProbability(invoke);
-            double invokeRelevance = graphInfo.invokeRelevance(invoke);
-            MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
-
-            for (int i = 0; i < info.numberOfMethods(); i++) {
-                Inlineable elem = getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()));
-                info.setInlinableElement(i, elem);
-                if (elem instanceof InlineableGraph) {
-                    data.pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
-                } else {
-                    assert elem instanceof InlineableMacroNode;
-                    data.pushDummyGraph();
-                }
-            }
-        }
-    }
-
-    private void tryToInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth, HighTierContext context) {
-        InlineInfo callee = calleeInfo.callee();
-        Assumptions callerAssumptions = parentInvocation.assumptions();
-
-        if (inliningPolicy.isWorthInlining(context.getReplacements(), callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) {
-            doInline(callerGraphInfo, calleeInfo, callerAssumptions, context);
-        } else if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
-            callee.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
-        }
-        metricInliningConsidered.increment();
-    }
-
-    private void doInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, Assumptions callerAssumptions, HighTierContext context) {
-        StructuredGraph callerGraph = callerGraphInfo.graph();
-        Mark markBeforeInlining = callerGraph.getMark();
-        InlineInfo callee = calleeInfo.callee();
-        try {
-            List<Node> invokeUsages = callee.invoke().asNode().usages().snapshot();
-            callee.inline(new Providers(context), callerAssumptions);
-            callerAssumptions.record(calleeInfo.assumptions());
-            metricInliningRuns.increment();
-            Debug.dump(callerGraph, "after %s", callee);
-
-            if (OptCanonicalizer.getValue()) {
-                Mark markBeforeCanonicalization = callerGraph.getMark();
-                canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
-
-                // process invokes that are possibly created during canonicalization
-                for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
-                    if (newNode instanceof Invoke) {
-                        callerGraphInfo.pushInvoke((Invoke) newNode);
-                    }
-                }
-            }
-
-            callerGraphInfo.computeProbabilities();
-
-            inliningCount++;
-            metricInliningPerformed.increment();
-        } catch (BailoutException bailout) {
-            throw bailout;
-        } catch (AssertionError | RuntimeException e) {
-            throw new GraalInternalError(e).addContext(callee.toString());
-        } catch (GraalInternalError e) {
-            throw e.addContext(callee.toString());
-        }
-    }
-
-    private Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context) {
-        Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
-        if (macroNodeClass != null) {
-            return new InlineableMacroNode(macroNodeClass);
-        } else {
-            return new InlineableGraph(buildGraph(method, invoke, context));
-        }
-    }
-
-    private StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context) {
-        final StructuredGraph newGraph;
-        final boolean parseBytecodes;
-
-        // TODO (chaeubl): copying the graph is only necessary if it is modified or if it contains
-        // any invokes
-        StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
-        if (intrinsicGraph != null) {
-            newGraph = intrinsicGraph.copy();
-            parseBytecodes = false;
-        } else {
-            StructuredGraph cachedGraph = getCachedGraph(method, context);
-            if (cachedGraph != null) {
-                newGraph = cachedGraph.copy();
-                parseBytecodes = false;
-            } else {
-                newGraph = new StructuredGraph(method);
-                parseBytecodes = true;
-            }
-        }
-
-        try (Scope s = Debug.scope("InlineGraph", newGraph)) {
-            if (parseBytecodes) {
-                parseBytecodes(newGraph, context);
-            }
-
-            boolean callerHasMoreInformationAboutArguments = false;
-            NodeInputList<ValueNode> args = invoke.callTarget().arguments();
-            for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) {
-                ValueNode arg = args.get(param.index());
-                if (arg.isConstant()) {
-                    Constant constant = arg.asConstant();
-                    newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
-                    callerHasMoreInformationAboutArguments = true;
-                } else {
-                    Stamp joinedStamp = param.stamp().join(arg.stamp());
-                    if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
-                        param.setStamp(joinedStamp);
-                        callerHasMoreInformationAboutArguments = true;
-                    }
-                }
-            }
-
-            if (!callerHasMoreInformationAboutArguments) {
-                // TODO (chaeubl): if args are not more concrete, inlining should be avoided
-                // in most cases or we could at least use the previous graph size + invoke
-                // probability to check the inlining
-            }
-
-            if (OptCanonicalizer.getValue()) {
-                canonicalizer.apply(newGraph, context);
-            }
-
-            return newGraph;
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-    }
-
-    private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) {
-        if (context.getGraphCache() != null) {
-            StructuredGraph cachedGraph = context.getGraphCache().get(method);
-            if (cachedGraph != null) {
-                return cachedGraph;
-            }
-        }
-        return null;
-    }
-
-    private StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context) {
-        boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature();
-
-        if (context.getGraphBuilderSuite() != null) {
-            context.getGraphBuilderSuite().apply(newGraph, context);
-        }
-        assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
-
-        new DeadCodeEliminationPhase().apply(newGraph);
-
-        if (OptCanonicalizer.getValue()) {
-            canonicalizer.apply(newGraph, context);
-        }
-
-        if (hasMatureProfilingInfo && context.getGraphCache() != null) {
-            context.getGraphCache().put(newGraph.method(), newGraph.copy());
-        }
-        return newGraph;
-    }
-
-    private abstract static class AbstractInliningPolicy implements InliningPolicy {
-
-        protected final Map<Invoke, Double> hints;
-
-        public AbstractInliningPolicy(Map<Invoke, Double> hints) {
-            this.hints = hints;
-        }
-
-        protected double computeMaximumSize(double relevance, int configuredMaximum) {
-            double inlineRatio = Math.min(RelevanceCapForInlining.getValue(), relevance);
-            return configuredMaximum * inlineRatio;
-        }
-
-        protected double getInliningBonus(InlineInfo info) {
-            if (hints != null && hints.containsKey(info.invoke())) {
-                return hints.get(info.invoke());
-            }
-            return 1;
-        }
-
-        protected boolean isIntrinsic(Replacements replacements, InlineInfo info) {
-            if (AlwaysInlineIntrinsics.getValue()) {
-                return onlyIntrinsics(replacements, info);
-            } else {
-                return onlyForcedIntrinsics(replacements, info);
-            }
-        }
-
-        private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
-            for (int i = 0; i < info.numberOfMethods(); i++) {
-                if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
-            for (int i = 0; i < info.numberOfMethods(); i++) {
-                if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
-                    return false;
-                }
-                if (!replacements.isForcedSubstitution(info.methodAt(i))) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        protected static int previousLowLevelGraphSize(InlineInfo info) {
-            int size = 0;
-            for (int i = 0; i < info.numberOfMethods(); i++) {
-                ResolvedJavaMethod m = info.methodAt(i);
-                ProfilingInfo profile = m.getProfilingInfo();
-                int compiledGraphSize = profile.getCompilerIRSize(StructuredGraph.class);
-                if (compiledGraphSize > 0) {
-                    size += compiledGraphSize;
-                }
-            }
-            return size;
-        }
-
-        protected static int determineNodeCount(InlineInfo info) {
-            int nodes = 0;
-            for (int i = 0; i < info.numberOfMethods(); i++) {
-                Inlineable elem = info.inlineableElementAt(i);
-                if (elem != null) {
-                    nodes += elem.getNodeCount();
-                }
-            }
-            return nodes;
-        }
-
-        protected static double determineInvokeProbability(InlineInfo info) {
-            double invokeProbability = 0;
-            for (int i = 0; i < info.numberOfMethods(); i++) {
-                Inlineable callee = info.inlineableElementAt(i);
-                Iterable<Invoke> invokes = callee.getInvokes();
-                if (invokes.iterator().hasNext()) {
-                    NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(((InlineableGraph) callee).getGraph()).apply();
-                    for (Invoke invoke : invokes) {
-                        invokeProbability += nodeProbabilities.get(invoke.asNode());
-                    }
-                }
-            }
-            return invokeProbability;
-        }
-    }
-
-    public static class GreedyInliningPolicy extends AbstractInliningPolicy {
-
-        public GreedyInliningPolicy(Map<Invoke, Double> hints) {
-            super(hints);
-        }
-
-        public boolean continueInlining(StructuredGraph currentGraph) {
-            if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) {
-                InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
-                metricInliningStoppedByMaxDesiredSize.increment();
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public boolean isWorthInlining(Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed) {
-            if (InlineEverything.getValue()) {
-                return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
-            }
-
-            if (isIntrinsic(replacements, info)) {
-                return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
-            }
-
-            if (info.shouldInline()) {
-                return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
-            }
-
-            double inliningBonus = getInliningBonus(info);
-            int nodes = determineNodeCount(info);
-            int lowLevelGraphSize = previousLowLevelGraphSize(info);
-
-            if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
-                return InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)",
-                                lowLevelGraphSize, relevance, probability, inliningBonus, nodes);
-            }
-
-            if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
-                return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
-            }
-
-            /*
-             * TODO (chaeubl): invoked methods that are on important paths but not yet compiled ->
-             * will be compiled anyways and it is likely that we are the only caller... might be
-             * useful to inline those methods but increases bootstrap time (maybe those methods are
-             * also getting queued in the compilation queue concurrently)
-             */
-            double invokes = determineInvokeProbability(info);
-            if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) {
-                return InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes,
-                                relevance, probability, inliningBonus, nodes);
-            }
-
-            double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus));
-            if (nodes <= maximumNodes) {
-                return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability,
-                                inliningBonus, nodes, maximumNodes);
-            }
-
-            return InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes,
-                            maximumNodes);
-        }
-    }
-
-    public static final class InlineEverythingPolicy implements InliningPolicy {
-
-        public boolean continueInlining(StructuredGraph graph) {
-            if (graph.getNodeCount() >= MaximumDesiredSize.getValue()) {
-                throw new BailoutException("Inline all calls failed. The resulting graph is too large.");
-            }
-            return true;
-        }
-
-        public boolean isWorthInlining(Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed) {
-            return true;
-        }
-    }
-
-    private static class InliningIterator {
-
-        private final FixedNode start;
-        private final Deque<FixedNode> nodeQueue;
-        private final NodeBitMap queuedNodes;
-
-        public InliningIterator(FixedNode start, NodeBitMap visitedFixedNodes) {
-            this.start = start;
-            this.nodeQueue = new ArrayDeque<>();
-            this.queuedNodes = visitedFixedNodes;
-            assert start.isAlive();
-        }
-
-        public LinkedList<Invoke> apply() {
-            LinkedList<Invoke> invokes = new LinkedList<>();
-            FixedNode current;
-            forcedQueue(start);
-
-            while ((current = nextQueuedNode()) != null) {
-                assert current.isAlive();
-
-                if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
-                    if (current != start) {
-                        invokes.addLast((Invoke) current);
-                    }
-                    queueSuccessors(current);
-                } else if (current instanceof LoopBeginNode) {
-                    queueSuccessors(current);
-                } else if (current instanceof LoopEndNode) {
-                    // nothing todo
-                } else if (current instanceof MergeNode) {
-                    queueSuccessors(current);
-                } else if (current instanceof FixedWithNextNode) {
-                    queueSuccessors(current);
-                } else if (current instanceof EndNode) {
-                    queueMerge((EndNode) current);
-                } else if (current instanceof ControlSinkNode) {
-                    // nothing todo
-                } else if (current instanceof ControlSplitNode) {
-                    queueSuccessors(current);
-                } else {
-                    assert false : current;
-                }
-            }
-
-            return invokes;
-        }
-
-        private void queueSuccessors(FixedNode x) {
-            for (Node node : x.successors()) {
-                queue(node);
-            }
-        }
-
-        private void queue(Node node) {
-            if (node != null && !queuedNodes.isMarked(node)) {
-                forcedQueue(node);
-            }
-        }
-
-        private void forcedQueue(Node node) {
-            queuedNodes.mark(node);
-            nodeQueue.addFirst((FixedNode) node);
-        }
-
-        private FixedNode nextQueuedNode() {
-            if (nodeQueue.isEmpty()) {
-                return null;
-            }
-
-            FixedNode result = nodeQueue.removeFirst();
-            assert queuedNodes.isMarked(result);
-            return result;
-        }
-
-        private void queueMerge(AbstractEndNode end) {
-            MergeNode merge = end.merge();
-            if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
-                queuedNodes.mark(merge);
-                nodeQueue.add(merge);
-            }
-        }
-
-        private boolean visitedAllEnds(MergeNode merge) {
-            for (int i = 0; i < merge.forwardEndCount(); i++) {
-                if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-
-    /**
-     * Holds the data for building the callee graphs recursively: graphs and invocations (each
-     * invocation can have multiple graphs).
-     */
-    static class InliningData {
-
-        private static final GraphInfo DummyGraphInfo = new GraphInfo(null, new LinkedList<Invoke>(), 1.0, 1.0);
-
-        /**
-         * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
-         */
-        private final ArrayDeque<GraphInfo> graphQueue;
-        private final ArrayDeque<MethodInvocation> invocationQueue;
-
-        private int maxGraphs;
-
-        public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions) {
-            this.graphQueue = new ArrayDeque<>();
-            this.invocationQueue = new ArrayDeque<>();
-            this.maxGraphs = 1;
-
-            invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
-            pushGraph(rootGraph, 1.0, 1.0);
-        }
-
-        public int graphCount() {
-            return graphQueue.size();
-        }
-
-        public void pushGraph(StructuredGraph graph, double probability, double relevance) {
-            assert !contains(graph);
-            NodeBitMap visitedFixedNodes = graph.createNodeBitMap();
-            LinkedList<Invoke> invokes = new InliningIterator(graph.start(), visitedFixedNodes).apply();
-            assert invokes.size() == count(graph.getInvokes());
-            graphQueue.push(new GraphInfo(graph, invokes, probability, relevance));
-            assert graphQueue.size() <= maxGraphs;
-        }
-
-        public void pushDummyGraph() {
-            graphQueue.push(DummyGraphInfo);
-        }
-
-        public boolean hasUnprocessedGraphs() {
-            return !graphQueue.isEmpty();
-        }
-
-        public GraphInfo currentGraph() {
-            return graphQueue.peek();
-        }
-
-        public void popGraph() {
-            graphQueue.pop();
-            assert graphQueue.size() <= maxGraphs;
-        }
-
-        public void popGraphs(int count) {
-            assert count >= 0;
-            for (int i = 0; i < count; i++) {
-                graphQueue.pop();
-            }
-        }
-
-        private static final Object[] NO_CONTEXT = {};
-
-        /**
-         * Gets the call hierarchy of this inlining from outer most call to inner most callee.
-         */
-        public Object[] inliningContext() {
-            if (!Debug.isDumpEnabled()) {
-                return NO_CONTEXT;
-            }
-            Object[] result = new Object[graphQueue.size()];
-            int i = 0;
-            for (GraphInfo g : graphQueue) {
-                result[i++] = g.graph.method();
-            }
-            return result;
-        }
-
-        public MethodInvocation currentInvocation() {
-            return invocationQueue.peekFirst();
-        }
-
-        public MethodInvocation pushInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
-            MethodInvocation methodInvocation = new MethodInvocation(info, new Assumptions(assumptions.useOptimisticAssumptions()), probability, relevance);
-            invocationQueue.addFirst(methodInvocation);
-            maxGraphs += info.numberOfMethods();
-            assert graphQueue.size() <= maxGraphs;
-            return methodInvocation;
-        }
-
-        public void popInvocation() {
-            maxGraphs -= invocationQueue.peekFirst().callee.numberOfMethods();
-            assert graphQueue.size() <= maxGraphs;
-            invocationQueue.removeFirst();
-        }
-
-        public int countRecursiveInlining(ResolvedJavaMethod method) {
-            int count = 0;
-            for (GraphInfo graphInfo : graphQueue) {
-                if (method.equals(graphInfo.method())) {
-                    count++;
-                }
-            }
-            return count;
-        }
-
-        public int inliningDepth() {
-            assert invocationQueue.size() > 0;
-            return invocationQueue.size() - 1;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder result = new StringBuilder("Invocations: ");
-
-            for (MethodInvocation invocation : invocationQueue) {
-                if (invocation.callee() != null) {
-                    result.append(invocation.callee().numberOfMethods());
-                    result.append("x ");
-                    result.append(invocation.callee().invoke());
-                    result.append("; ");
-                }
-            }
-
-            result.append("\nGraphs: ");
-            for (GraphInfo graph : graphQueue) {
-                result.append(graph.graph());
-                result.append("; ");
-            }
-
-            return result.toString();
-        }
-
-        private boolean contains(StructuredGraph graph) {
-            for (GraphInfo info : graphQueue) {
-                if (info.graph() == graph) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        private static int count(Iterable<Invoke> invokes) {
-            int count = 0;
-            Iterator<Invoke> iterator = invokes.iterator();
-            while (iterator.hasNext()) {
-                iterator.next();
-                count++;
-            }
-            return count;
-        }
-    }
-
-    private static class MethodInvocation {
-
-        private final InlineInfo callee;
-        private final Assumptions assumptions;
-        private final double probability;
-        private final double relevance;
-
-        private int processedGraphs;
-
-        public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
-            this.callee = info;
-            this.assumptions = assumptions;
-            this.probability = probability;
-            this.relevance = relevance;
-        }
-
-        public void incrementProcessedGraphs() {
-            processedGraphs++;
-            assert processedGraphs <= callee.numberOfMethods();
-        }
-
-        public int processedGraphs() {
-            assert processedGraphs <= callee.numberOfMethods();
-            return processedGraphs;
-        }
-
-        public int totalGraphs() {
-            return callee.numberOfMethods();
-        }
-
-        public InlineInfo callee() {
-            return callee;
-        }
-
-        public Assumptions assumptions() {
-            return assumptions;
-        }
-
-        public double probability() {
-            return probability;
-        }
-
-        public double relevance() {
-            return relevance;
-        }
-
-        public boolean isRoot() {
-            return callee == null;
-        }
-
-        @Override
-        public String toString() {
-            if (isRoot()) {
-                return "<root>";
-            }
-            CallTargetNode callTarget = callee.invoke().callTarget();
-            if (callTarget instanceof MethodCallTargetNode) {
-                ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
-                return MetaUtil.format("Invoke#%H.%n(%p)", calleeMethod);
-            } else {
-                return "Invoke#" + callTarget.targetName();
-            }
-        }
-    }
-
-    /**
-     * Information about a graph that will potentially be inlined. This includes tracking the
-     * invocations in graph that will subject to inlining themselves.
-     */
-    private static class GraphInfo {
-
-        private final StructuredGraph graph;
-        private final LinkedList<Invoke> remainingInvokes;
-        private final double probability;
-        private final double relevance;
-
-        private NodesToDoubles nodeProbabilities;
-        private NodesToDoubles nodeRelevance;
-
-        public GraphInfo(StructuredGraph graph, LinkedList<Invoke> invokes, double probability, double relevance) {
-            this.graph = graph;
-            this.remainingInvokes = invokes;
-            this.probability = probability;
-            this.relevance = relevance;
-
-            if (graph != null) {
-                computeProbabilities();
-            }
-        }
-
-        /**
-         * Gets the method associated with the {@linkplain #graph() graph} represented by this
-         * object.
-         */
-        public ResolvedJavaMethod method() {
-            return graph.method();
-        }
-
-        public boolean hasRemainingInvokes() {
-            return !remainingInvokes.isEmpty();
-        }
-
-        /**
-         * The graph about which this object contains inlining information.
-         */
-        public StructuredGraph graph() {
-            return graph;
-        }
-
-        public Invoke popInvoke() {
-            return remainingInvokes.removeFirst();
-        }
-
-        public void pushInvoke(Invoke invoke) {
-            remainingInvokes.push(invoke);
-        }
-
-        public void computeProbabilities() {
-            nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
-            nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).apply();
-        }
-
-        public double invokeProbability(Invoke invoke) {
-            return probability * nodeProbabilities.get(invoke.asNode());
-        }
-
-        public double invokeRelevance(Invoke invoke) {
-            return Math.min(CapInheritedRelevance.getValue(), relevance) * nodeRelevance.get(invoke.asNode());
-        }
-
-        @Override
-        public String toString() {
-            return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "<null method>") + remainingInvokes;
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1575 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.common;
-
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.nodes.type.StampFactory.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-import static java.lang.reflect.Modifier.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.Assumption;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
-import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.Node.Verbosity;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.InliningPhase.InliningData;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-
-public class InliningUtil {
-
-    private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
-    private static final String inliningDecisionsScopeString = "InliningDecisions";
-    /**
-     * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level
-     * and all inlined methods), irrespective of how many bytecodes in each method are actually
-     * parsed (which may be none for methods whose IR is retrieved from a cache).
-     */
-    public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes");
-
-    public interface InliningPolicy {
-
-        boolean continueInlining(StructuredGraph graph);
-
-        boolean isWorthInlining(Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
-    }
-
-    public interface Inlineable {
-
-        int getNodeCount();
-
-        Iterable<Invoke> getInvokes();
-    }
-
-    public static class InlineableGraph implements Inlineable {
-
-        private final StructuredGraph graph;
-
-        public InlineableGraph(StructuredGraph graph) {
-            this.graph = graph;
-        }
-
-        @Override
-        public int getNodeCount() {
-            return graph.getNodeCount();
-        }
-
-        @Override
-        public Iterable<Invoke> getInvokes() {
-            return graph.getInvokes();
-        }
-
-        public StructuredGraph getGraph() {
-            return graph;
-        }
-    }
-
-    public static class InlineableMacroNode implements Inlineable {
-
-        private final Class<? extends FixedWithNextNode> macroNodeClass;
-
-        public InlineableMacroNode(Class<? extends FixedWithNextNode> macroNodeClass) {
-            this.macroNodeClass = macroNodeClass;
-        }
-
-        @Override
-        public int getNodeCount() {
-            return 1;
-        }
-
-        @Override
-        public Iterable<Invoke> getInvokes() {
-            return Collections.emptyList();
-        }
-
-        public Class<? extends FixedWithNextNode> getMacroNodeClass() {
-            return macroNodeClass;
-        }
-    }
-
-    /**
-     * Print a HotSpot-style inlining message to the console.
-     */
-    private static void printInlining(final InlineInfo info, final int inliningDepth, final boolean success, final String msg, final Object... args) {
-        printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args);
-    }
-
-    /**
-     * Print a HotSpot-style inlining message to the console.
-     */
-    private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) {
-        if (HotSpotPrintInlining.getValue()) {
-            final int mod = method.getModifiers();
-            // 1234567
-            TTY.print("        ");     // print timestamp
-            // 1234
-            TTY.print("     ");        // print compilation number
-            // % s ! b n
-            TTY.print("%c%c%c%c%c ", ' ', Modifier.isSynchronized(mod) ? 's' : ' ', ' ', ' ', Modifier.isNative(mod) ? 'n' : ' ');
-            TTY.print("     ");        // more indent
-            TTY.print("    ");         // initial inlining indent
-            for (int i = 0; i < inliningDepth; i++) {
-                TTY.print("  ");
-            }
-            TTY.println(String.format("@ %d  %s   %s%s", invoke.bci(), methodName(method, null), success ? "" : "not inlining ", String.format(msg, args)));
-        }
-    }
-
-    public static boolean logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
-        return logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
-    }
-
-    public static boolean logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
-        return logInliningDecision(info, inliningDepth, true, false, msg, args);
-    }
-
-    public static boolean logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
-        if (allowLogging) {
-            printInlining(info, inliningDepth, success, msg, args);
-            if (shouldLogInliningDecision()) {
-                logInliningDecision(methodName(info), success, msg, args);
-            }
-        }
-        return success;
-    }
-
-    public static void logInliningDecision(final String msg, final Object... args) {
-        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
-            // Can't use log here since we are varargs
-            if (Debug.isLogEnabled()) {
-                Debug.logv(msg, args);
-            }
-        }
-    }
-
-    private static boolean logNotInlinedMethod(Invoke invoke, String msg) {
-        if (shouldLogInliningDecision()) {
-            String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName());
-            logInliningDecision(methodString, false, msg, new Object[0]);
-        }
-        return false;
-    }
-
-    private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
-        return logNotInlinedMethodAndReturnNull(invoke, inliningDepth, method, msg, new Object[0]);
-    }
-
-    private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
-        printInlining(method, invoke, inliningDepth, false, msg, args);
-        if (shouldLogInliningDecision()) {
-            String methodString = methodName(method, invoke);
-            logInliningDecision(methodString, false, msg, args);
-        }
-        return null;
-    }
-
-    private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
-        printInlining(method, invoke, inliningDepth, false, msg, new Object[0]);
-        if (shouldLogInliningDecision()) {
-            String methodString = methodName(method, invoke);
-            logInliningDecision(methodString, false, msg, new Object[0]);
-        }
-        return false;
-    }
-
-    private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
-        String inliningMsg = "inlining " + methodString + ": " + msg;
-        if (!success) {
-            inliningMsg = "not " + inliningMsg;
-        }
-        logInliningDecision(inliningMsg, args);
-    }
-
-    public static boolean shouldLogInliningDecision() {
-        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
-            return Debug.isLogEnabled();
-        }
-    }
-
-    private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
-        if (invoke != null && invoke.stateAfter() != null) {
-            return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
-        } else {
-            return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
-        }
-    }
-
-    private static String methodName(InlineInfo info) {
-        if (info == null) {
-            return "null";
-        } else if (info.invoke() != null && info.invoke().stateAfter() != null) {
-            return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString();
-        } else {
-            return info.toString();
-        }
-    }
-
-    private static String methodName(FrameState frameState, int bci) {
-        StringBuilder sb = new StringBuilder();
-        if (frameState.outerFrameState() != null) {
-            sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
-            sb.append("->");
-        }
-        sb.append(MetaUtil.format("%h.%n", frameState.method()));
-        sb.append("@").append(bci);
-        return sb.toString();
-    }
-
-    /**
-     * Represents an opportunity for inlining at a given invoke, with the given weight and level.
-     * The weight is the amortized weight of the additional code - so smaller is better. The level
-     * is the number of nested inlinings that lead to this invoke.
-     */
-    public interface InlineInfo {
-
-        /**
-         * The graph containing the {@link #invoke() invocation} that may be inlined.
-         */
-        StructuredGraph graph();
-
-        /**
-         * The invocation that may be inlined.
-         */
-        Invoke invoke();
-
-        /**
-         * Returns the number of methods that may be inlined by the {@link #invoke() invocation}.
-         * This may be more than one in the case of a invocation profile showing a number of "hot"
-         * concrete methods dispatched to by the invocation.
-         */
-        int numberOfMethods();
-
-        ResolvedJavaMethod methodAt(int index);
-
-        Inlineable inlineableElementAt(int index);
-
-        double probabilityAt(int index);
-
-        double relevanceAt(int index);
-
-        void setInlinableElement(int index, Inlineable inlineableElement);
-
-        /**
-         * Performs the inlining described by this object and returns the node that represents the
-         * return value of the inlined method (or null for void methods and methods that have no
-         * non-exceptional exit).
-         */
-        void inline(Providers providers, Assumptions assumptions);
-
-        /**
-         * Try to make the call static bindable to avoid interface and virtual method calls.
-         */
-        void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions);
-
-        boolean shouldInline();
-    }
-
-    public abstract static class AbstractInlineInfo implements InlineInfo {
-
-        protected final Invoke invoke;
-
-        public AbstractInlineInfo(Invoke invoke) {
-            this.invoke = invoke;
-        }
-
-        @Override
-        public StructuredGraph graph() {
-            return invoke.asNode().graph();
-        }
-
-        @Override
-        public Invoke invoke() {
-            return invoke;
-        }
-
-        protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
-            if (inlineable instanceof InlineableGraph) {
-                StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
-                InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
-            } else {
-                assert inlineable instanceof InlineableMacroNode;
-
-                Class<? extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
-                inlineMacroNode(invoke, concrete, macroNodeClass);
-            }
-
-            InlinedBytecodes.add(concrete.getCodeSize());
-            assumptions.recordMethodContents(concrete);
-        }
-    }
-
-    public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
-        MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
-        MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType()));
-        invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
-    }
-
-    /**
-     * Represents an inlining opportunity where the compiler can statically determine a monomorphic
-     * target method and therefore is able to determine the called method exactly.
-     */
-    public static class ExactInlineInfo extends AbstractInlineInfo {
-
-        protected final ResolvedJavaMethod concrete;
-        private Inlineable inlineableElement;
-        private boolean suppressNullCheck;
-
-        public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
-            super(invoke);
-            this.concrete = concrete;
-            assert concrete != null;
-        }
-
-        public void suppressNullCheck() {
-            suppressNullCheck = true;
-        }
-
-        @Override
-        public void inline(Providers providers, Assumptions assumptions) {
-            inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
-        }
-
-        @Override
-        public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
-            // nothing todo, can already be bound statically
-        }
-
-        @Override
-        public int numberOfMethods() {
-            return 1;
-        }
-
-        @Override
-        public ResolvedJavaMethod methodAt(int index) {
-            assert index == 0;
-            return concrete;
-        }
-
-        @Override
-        public double probabilityAt(int index) {
-            assert index == 0;
-            return 1.0;
-        }
-
-        @Override
-        public double relevanceAt(int index) {
-            assert index == 0;
-            return 1.0;
-        }
-
-        @Override
-        public String toString() {
-            return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-
-        @Override
-        public Inlineable inlineableElementAt(int index) {
-            assert index == 0;
-            return inlineableElement;
-        }
-
-        @Override
-        public void setInlinableElement(int index, Inlineable inlineableElement) {
-            assert index == 0;
-            this.inlineableElement = inlineableElement;
-        }
-
-        public boolean shouldInline() {
-            return concrete.shouldBeInlined();
-        }
-    }
-
-    /**
-     * Represents an inlining opportunity for which profiling information suggests a monomorphic
-     * receiver, but for which the receiver type cannot be proven. A type check guard will be
-     * generated if this inlining is performed.
-     */
-    private static class TypeGuardInlineInfo extends AbstractInlineInfo {
-
-        private final ResolvedJavaMethod concrete;
-        private final ResolvedJavaType type;
-        private Inlineable inlineableElement;
-
-        public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
-            super(invoke);
-            this.concrete = concrete;
-            this.type = type;
-            assert type.isArray() || !isAbstract(type.getModifiers()) : type;
-        }
-
-        @Override
-        public int numberOfMethods() {
-            return 1;
-        }
-
-        @Override
-        public ResolvedJavaMethod methodAt(int index) {
-            assert index == 0;
-            return concrete;
-        }
-
-        @Override
-        public Inlineable inlineableElementAt(int index) {
-            assert index == 0;
-            return inlineableElement;
-        }
-
-        @Override
-        public double probabilityAt(int index) {
-            assert index == 0;
-            return 1.0;
-        }
-
-        @Override
-        public double relevanceAt(int index) {
-            assert index == 0;
-            return 1.0;
-        }
-
-        @Override
-        public void setInlinableElement(int index, Inlineable inlineableElement) {
-            assert index == 0;
-            this.inlineableElement = inlineableElement;
-        }
-
-        @Override
-        public void inline(Providers providers, Assumptions assumptions) {
-            createGuard(graph(), providers.getMetaAccess());
-            inline(invoke, concrete, inlineableElement, assumptions, false);
-        }
-
-        @Override
-        public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
-            createGuard(graph(), metaAccess);
-            replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
-        }
-
-        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.getKind()));
-
-            CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
-            FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
-            assert invoke.predecessor() != null;
-
-            ValueNode anchoredReceiver = createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
-            invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
-
-            graph.addBeforeFixed(invoke.asNode(), guard);
-        }
-
-        @Override
-        public String toString() {
-            return "type-checked with type " + type.getName() + " and method " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-
-        public boolean shouldInline() {
-            return concrete.shouldBeInlined();
-        }
-    }
-
-    /**
-     * Polymorphic inlining of m methods with n type checks (n &ge; m) in case that the profiling
-     * information suggests a reasonable amount of different receiver types and different methods.
-     * If an unknown type is encountered a deoptimization is triggered.
-     */
-    private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
-
-        private final List<ResolvedJavaMethod> concretes;
-        private final double[] methodProbabilities;
-        private final double maximumMethodProbability;
-        private final ArrayList<Integer> typesToConcretes;
-        private final ArrayList<ProfiledType> ptypes;
-        private final ArrayList<Double> concretesProbabilities;
-        private final double notRecordedTypeProbability;
-        private final Inlineable[] inlineableElements;
-
-        public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<Double> concretesProbabilities, ArrayList<ProfiledType> ptypes,
-                        ArrayList<Integer> typesToConcretes, double notRecordedTypeProbability) {
-            super(invoke);
-            assert concretes.size() > 0 : "must have at least one method";
-            assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
-
-            this.concretesProbabilities = concretesProbabilities;
-            this.concretes = concretes;
-            this.ptypes = ptypes;
-            this.typesToConcretes = typesToConcretes;
-            this.notRecordedTypeProbability = notRecordedTypeProbability;
-            this.inlineableElements = new Inlineable[concretes.size()];
-            this.methodProbabilities = computeMethodProbabilities();
-            this.maximumMethodProbability = maximumMethodProbability();
-            assert maximumMethodProbability > 0;
-        }
-
-        private double[] computeMethodProbabilities() {
-            double[] result = new double[concretes.size()];
-            for (int i = 0; i < typesToConcretes.size(); i++) {
-                int concrete = typesToConcretes.get(i);
-                double probability = ptypes.get(i).getProbability();
-                result[concrete] += probability;
-            }
-            return result;
-        }
-
-        private double maximumMethodProbability() {
-            double max = 0;
-            for (int i = 0; i < methodProbabilities.length; i++) {
-                max = Math.max(max, methodProbabilities[i]);
-            }
-            return max;
-        }
-
-        @Override
-        public int numberOfMethods() {
-            return concretes.size();
-        }
-
-        @Override
-        public ResolvedJavaMethod methodAt(int index) {
-            assert index >= 0 && index < concretes.size();
-            return concretes.get(index);
-        }
-
-        @Override
-        public Inlineable inlineableElementAt(int index) {
-            assert index >= 0 && index < concretes.size();
-            return inlineableElements[index];
-        }
-
-        @Override
-        public double probabilityAt(int index) {
-            return methodProbabilities[index];
-        }
-
-        @Override
-        public double relevanceAt(int index) {
-            return probabilityAt(index) / maximumMethodProbability;
-        }
-
-        @Override
-        public void setInlinableElement(int index, Inlineable inlineableElement) {
-            assert index >= 0 && index < concretes.size();
-            inlineableElements[index] = inlineableElement;
-        }
-
-        @Override
-        public void inline(Providers providers, Assumptions assumptions) {
-            if (hasSingleMethod()) {
-                inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
-            } else {
-                inlineMultipleMethods(graph(), providers, assumptions);
-            }
-        }
-
-        public boolean shouldInline() {
-            for (ResolvedJavaMethod method : concretes) {
-                if (method.shouldBeInlined()) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        private boolean hasSingleMethod() {
-            return concretes.size() == 1 && !shouldFallbackToInvoke();
-        }
-
-        private boolean shouldFallbackToInvoke() {
-            return notRecordedTypeProbability > 0;
-        }
-
-        private void inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
-            int numberOfMethods = concretes.size();
-            FixedNode continuation = invoke.next();
-
-            ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
-            // setup merge and phi nodes for results and exceptions
-            MergeNode returnMerge = graph.add(new MergeNode());
-            returnMerge.setStateAfter(invoke.stateAfter());
-
-            PhiNode returnValuePhi = null;
-            if (invoke.asNode().getKind() != Kind.Void) {
-                returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
-            }
-
-            MergeNode exceptionMerge = null;
-            PhiNode exceptionObjectPhi = null;
-            if (invoke instanceof InvokeWithExceptionNode) {
-                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
-
-                exceptionMerge = graph.add(new MergeNode());
-
-                FixedNode exceptionSux = exceptionEdge.next();
-                graph.addBeforeFixed(exceptionSux, exceptionMerge);
-                exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(Kind.Object), exceptionMerge));
-                exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
-            }
-
-            // create one separate block for each invoked method
-            BeginNode[] successors = new BeginNode[numberOfMethods + 1];
-            for (int i = 0; i < numberOfMethods; i++) {
-                successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
-            }
-
-            // create the successor for an unknown type
-            FixedNode unknownTypeSux;
-            if (shouldFallbackToInvoke()) {
-                unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
-            } else {
-                unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
-            }
-            successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
-
-            // replace the invoke exception edge
-            if (invoke instanceof InvokeWithExceptionNode) {
-                InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
-                ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
-                exceptionEdge.replaceAtUsages(exceptionObjectPhi);
-                exceptionEdge.setNext(null);
-                GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
-            }
-
-            assert invoke.asNode().isAlive();
-
-            // replace the invoke with a switch on the type of the actual receiver
-            boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getMetaAccess());
-
-            assert invoke.next() == continuation;
-            invoke.setNext(null);
-            returnMerge.setNext(continuation);
-            invoke.asNode().replaceAtUsages(returnValuePhi);
-            invoke.asNode().replaceAndDelete(null);
-
-            ArrayList<GuardedValueNode> replacementNodes = new ArrayList<>();
-
-            // do the actual inlining for every invoke
-            for (int i = 0; i < numberOfMethods; i++) {
-                BeginNode node = successors[i];
-                Invoke invokeForInlining = (Invoke) node.next();
-
-                ResolvedJavaType commonType;
-                if (methodDispatch) {
-                    commonType = concretes.get(i).getDeclaringClass();
-                } else {
-                    commonType = getLeastCommonType(i);
-                }
-
-                ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
-                boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
-                GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
-                invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-
-                inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false);
-
-                replacementNodes.add(anchoredReceiver);
-            }
-            if (shouldFallbackToInvoke()) {
-                replacementNodes.add(null);
-            }
-
-            if (OptTailDuplication.getValue()) {
-                /*
-                 * We might want to perform tail duplication at the merge after a type switch, if
-                 * there are invokes that would benefit from the improvement in type information.
-                 */
-                FixedNode current = returnMerge;
-                int opportunities = 0;
-                do {
-                    if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode &&
-                                    ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) {
-                        opportunities++;
-                    } else if (current.inputs().contains(originalReceiver)) {
-                        opportunities++;
-                    }
-                    current = ((FixedWithNextNode) current).next();
-                } while (current instanceof FixedWithNextNode);
-
-                if (opportunities > 0) {
-                    metricInliningTailDuplication.increment();
-                    Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                    PhaseContext phaseContext = new PhaseContext(providers, assumptions);
-                    CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
-                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
-                }
-            }
-        }
-
-        private int getTypeCount(int concreteMethodIndex) {
-            int count = 0;
-            for (int i = 0; i < typesToConcretes.size(); i++) {
-                if (typesToConcretes.get(i) == concreteMethodIndex) {
-                    count++;
-                }
-            }
-            return count;
-        }
-
-        private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
-            ResolvedJavaType commonType = null;
-            for (int i = 0; i < typesToConcretes.size(); i++) {
-                if (typesToConcretes.get(i) == concreteMethodIndex) {
-                    if (commonType == null) {
-                        commonType = ptypes.get(i).getType();
-                    } else {
-                        commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
-                    }
-                }
-            }
-            assert commonType != null;
-            return commonType;
-        }
-
-        private ResolvedJavaType getLeastCommonType() {
-            ResolvedJavaType result = getLeastCommonType(0);
-            for (int i = 1; i < concretes.size(); i++) {
-                result = result.findLeastCommonAncestor(getLeastCommonType(i));
-            }
-            return result;
-        }
-
-        private void inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
-            assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
-
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
-
-            BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
-            BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
-            createDispatchOnTypeBeforeInvoke(graph, successors, false, metaAccess);
-
-            calleeEntryNode.setNext(invoke.asNode());
-
-            inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
-        }
-
-        private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess) {
-            assert ptypes.size() >= 1;
-            ValueNode nonNullReceiver = nonNullReceiver(invoke);
-            Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
-            LoadHubNode hub = graph.unique(new LoadHubNode(nonNullReceiver, hubKind));
-
-            if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
-                assert successors.length == concretes.size() + 1;
-                assert concretes.size() > 0;
-                Debug.log("Method check cascade with %d methods", concretes.size());
-
-                ValueNode[] constantMethods = new ValueNode[concretes.size()];
-                double[] probability = new double[concretes.size()];
-                for (int i = 0; i < concretes.size(); ++i) {
-                    ResolvedJavaMethod firstMethod = concretes.get(i);
-                    Constant firstMethodConstant = firstMethod.getEncoding();
-
-                    ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
-                    constantMethods[i] = firstMethodConstantNode;
-                    double concretesProbability = concretesProbabilities.get(i);
-                    assert concretesProbability >= 0.0;
-                    probability[i] = concretesProbability;
-                    if (i > 0) {
-                        double prevProbability = probability[i - 1];
-                        if (prevProbability == 1.0) {
-                            probability[i] = 1.0;
-                        } else {
-                            probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
-                        }
-                    }
-                }
-
-                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].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);
-                    lastSucc = method;
-                }
-
-                FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
-                pred.setNext(lastSucc);
-                return true;
-            } else {
-                Debug.log("Type switch with %d types", concretes.size());
-            }
-
-            ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
-            double[] keyProbabilities = new double[ptypes.size() + 1];
-            int[] keySuccessors = new int[ptypes.size() + 1];
-            for (int i = 0; i < ptypes.size(); i++) {
-                keys[i] = ptypes.get(i).getType();
-                keyProbabilities[i] = ptypes.get(i).getProbability();
-                keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
-                assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
-            }
-            keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
-            keySuccessors[keySuccessors.length - 1] = successors.length - 1;
-
-            TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
-            FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
-            pred.setNext(typeSwitch);
-            return false;
-        }
-
-        private boolean chooseMethodDispatch() {
-            for (ResolvedJavaMethod concrete : concretes) {
-                if (!concrete.isInVirtualMethodTable()) {
-                    return false;
-                }
-            }
-
-            if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
-                // Always chose method dispatch if there is a single concrete method and the call
-                // site is megamorphic.
-                return true;
-            }
-
-            if (concretes.size() == ptypes.size()) {
-                // Always prefer types over methods if the number of types is smaller than the
-                // number of methods.
-                return false;
-            }
-
-            return chooseMethodDispatchCostBased();
-        }
-
-        private boolean chooseMethodDispatchCostBased() {
-            double remainder = 1.0 - this.notRecordedTypeProbability;
-            double costEstimateMethodDispatch = remainder;
-            for (int i = 0; i < concretes.size(); ++i) {
-                if (i != 0) {
-                    costEstimateMethodDispatch += remainder;
-                }
-                remainder -= concretesProbabilities.get(i);
-            }
-
-            double costEstimateTypeDispatch = 0.0;
-            remainder = 1.0;
-            for (int i = 0; i < ptypes.size(); ++i) {
-                if (i != 0) {
-                    costEstimateTypeDispatch += remainder;
-                }
-                remainder -= ptypes.get(i).getProbability();
-            }
-            costEstimateTypeDispatch += notRecordedTypeProbability;
-            return costEstimateMethodDispatch < costEstimateTypeDispatch;
-        }
-
-        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
-                        boolean useForInlining) {
-            Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
-            calleeEntryNode.setNext(duplicatedInvoke.asNode());
-
-            AbstractEndNode endNode = graph.add(new EndNode());
-            duplicatedInvoke.setNext(endNode);
-            returnMerge.addForwardEnd(endNode);
-
-            if (returnValuePhi != null) {
-                returnValuePhi.addInput(duplicatedInvoke.asNode());
-            }
-            return calleeEntryNode;
-        }
-
-        private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
-            Invoke result = (Invoke) invoke.asNode().copyWithInputs();
-            Node callTarget = result.callTarget().copyWithInputs();
-            result.asNode().replaceFirstInput(result.callTarget(), callTarget);
-            result.setUseForInlining(useForInlining);
-
-            Kind kind = invoke.asNode().getKind();
-            if (kind != Kind.Void) {
-                FrameState stateAfter = invoke.stateAfter();
-                stateAfter = stateAfter.duplicate(stateAfter.bci);
-                stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
-                result.setStateAfter(stateAfter);
-            }
-
-            if (invoke instanceof InvokeWithExceptionNode) {
-                assert exceptionMerge != null && exceptionObjectPhi != null;
-
-                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
-                FrameState stateAfterException = exceptionEdge.stateAfter();
-
-                ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
-                // set new state (pop old exception object, push new one)
-                newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
-
-                AbstractEndNode endNode = graph.add(new EndNode());
-                newExceptionEdge.setNext(endNode);
-                exceptionMerge.addForwardEnd(endNode);
-                exceptionObjectPhi.addInput(newExceptionEdge);
-
-                ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
-            }
-            return result;
-        }
-
-        @Override
-        public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
-            if (hasSingleMethod()) {
-                devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), metaAccess);
-            } else {
-                tryToDevirtualizeMultipleMethods(graph(), metaAccess);
-            }
-        }
-
-        private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider metaAccess) {
-            MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
-            if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
-                ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
-                ResolvedJavaType leastCommonType = getLeastCommonType();
-                // check if we have a common base type that implements the interface -> in that case
-                // we have a vtable entry for the interface method and can use a less expensive
-                // virtual call
-                if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
-                    ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod);
-                    if (baseClassTargetMethod != null) {
-                        devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), metaAccess);
-                    }
-                }
-            }
-        }
-
-        private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider metaAccess) {
-            BeginNode invocationEntry = graph.add(new BeginNode());
-            BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
-            BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
-            createDispatchOnTypeBeforeInvoke(graph, successors, true, metaAccess);
-
-            invocationEntry.setNext(invoke.asNode());
-            ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
-            GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
-            invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-            replaceInvokeCallTarget(invoke, graph, kind, target);
-        }
-
-        private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
-            return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
-            builder.append(", ");
-            builder.append(concretes.size());
-            builder.append(" methods [ ");
-            for (int i = 0; i < concretes.size(); i++) {
-                builder.append(MetaUtil.format("  %H.%n(%p):%r", concretes.get(i)));
-            }
-            builder.append(" ], ");
-            builder.append(ptypes.size());
-            builder.append(" type checks [ ");
-            for (int i = 0; i < ptypes.size(); i++) {
-                builder.append("  ");
-                builder.append(ptypes.get(i).getType().getName());
-                builder.append(ptypes.get(i).getProbability());
-            }
-            builder.append(" ]");
-            return builder.toString();
-        }
-    }
-
-    /**
-     * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
-     * target method, but for which an assumption has to be registered because of non-final classes.
-     */
-    private static class AssumptionInlineInfo extends ExactInlineInfo {
-
-        private final Assumption takenAssumption;
-
-        public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumption takenAssumption) {
-            super(invoke, concrete);
-            this.takenAssumption = takenAssumption;
-        }
-
-        @Override
-        public void inline(Providers providers, Assumptions assumptions) {
-            assumptions.record(takenAssumption);
-            super.inline(providers, assumptions);
-        }
-
-        @Override
-        public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
-            assumptions.record(takenAssumption);
-            replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
-        }
-
-        @Override
-        public String toString() {
-            return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-    }
-
-    /**
-     * Determines if inlining is possible at the given invoke node.
-     *
-     * @param invoke the invoke that should be inlined
-     * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
-     */
-    public static InlineInfo getInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts) {
-        if (!checkInvokeConditions(invoke)) {
-            return null;
-        }
-        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-
-        if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
-            return getExactInlineInfo(data, invoke, replacements, optimisticOpts, targetMethod);
-        }
-
-        assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
-
-        ResolvedJavaType holder = targetMethod.getDeclaringClass();
-        if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
-            return null;
-        }
-        ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp();
-        if (receiverStamp.alwaysNull()) {
-            // Don't inline if receiver is known to be null
-            return null;
-        }
-        if (receiverStamp.type() != null) {
-            // the invoke target might be more specific than the holder (happens after inlining:
-            // parameters lose their declared type...)
-            ResolvedJavaType receiverType = receiverStamp.type();
-            if (receiverType != null && holder.isAssignableFrom(receiverType)) {
-                holder = receiverType;
-                if (receiverStamp.isExactType()) {
-                    assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
-                    ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
-                    if (resolvedMethod != null) {
-                        return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
-                    }
-                }
-            }
-        }
-
-        if (holder.isArray()) {
-            // arrays can be treated as Objects
-            ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
-            if (resolvedMethod != null) {
-                return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
-            }
-        }
-
-        if (assumptions.useOptimisticAssumptions()) {
-            ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
-            if (uniqueSubtype != null) {
-                ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod);
-                if (resolvedMethod != null) {
-                    return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
-                }
-            }
-
-            ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
-            if (concrete != null) {
-                return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
-            }
-        }
-
-        // type check based inlining
-        return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, targetMethod, optimisticOpts);
-    }
-
-    private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete,
-                    Assumption takenAssumption) {
-        assert !Modifier.isAbstract(concrete.getModifiers());
-        if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
-            return null;
-        }
-        return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
-    }
-
-    private static InlineInfo getExactInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) {
-        assert !Modifier.isAbstract(targetMethod.getModifiers());
-        if (!checkTargetConditions(data, replacements, invoke, targetMethod, optimisticOpts)) {
-            return null;
-        }
-        return new ExactInlineInfo(invoke, targetMethod);
-    }
-
-    private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod targetMethod,
-                    OptimisticOptimizations optimisticOpts) {
-        JavaTypeProfile typeProfile;
-        ValueNode receiver = invoke.callTarget().arguments().get(0);
-        if (receiver instanceof TypeProfileProxyNode) {
-            TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
-            typeProfile = typeProfileProxyNode.getProfile();
-        } else {
-            return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no type profile exists");
-        }
-
-        ProfiledType[] ptypes = typeProfile.getTypes();
-        if (ptypes == null || ptypes.length <= 0) {
-            return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types in profile");
-        }
-
-        double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
-        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
-            if (!optimisticOpts.inlineMonomorphicCalls()) {
-                return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
-            }
-
-            ResolvedJavaType type = ptypes[0].getType();
-            assert type.isArray() || !isAbstract(type.getModifiers());
-            ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
-            if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
-                return null;
-            }
-            return new TypeGuardInlineInfo(invoke, concrete, type);
-        } else {
-            invoke.setPolymorphic(true);
-
-            if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
-                return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
-            }
-            if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
-                // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
-                // the number of types is lower than what can be recorded in a type profile
-                return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
-                                notRecordedTypeProbability * 100);
-            }
-
-            // Find unique methods and their probabilities.
-            ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
-            ArrayList<Double> concreteMethodsProbabilities = new ArrayList<>();
-            for (int i = 0; i < ptypes.length; i++) {
-                ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
-                if (concrete == null) {
-                    return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "could not resolve method");
-                }
-                int index = concreteMethods.indexOf(concrete);
-                double curProbability = ptypes[i].getProbability();
-                if (index < 0) {
-                    index = concreteMethods.size();
-                    concreteMethods.add(concrete);
-                    concreteMethodsProbabilities.add(curProbability);
-                } else {
-                    concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
-                }
-            }
-
-            if (concreteMethods.size() > maxNumberOfMethods) {
-                return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods);
-            }
-
-            // Clear methods that fall below the threshold.
-            if (notRecordedTypeProbability > 0) {
-                ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
-                ArrayList<Double> newConcreteMethodsProbabilities = new ArrayList<>();
-                for (int i = 0; i < concreteMethods.size(); ++i) {
-                    if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) {
-                        newConcreteMethods.add(concreteMethods.get(i));
-                        newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
-                    }
-                }
-
-                if (newConcreteMethods.size() == 0) {
-                    // No method left that is worth inlining.
-                    return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
-                                    concreteMethods.size());
-                }
-
-                concreteMethods = newConcreteMethods;
-                concreteMethodsProbabilities = newConcreteMethodsProbabilities;
-            }
-
-            // Clean out types whose methods are no longer available.
-            ArrayList<ProfiledType> usedTypes = new ArrayList<>();
-            ArrayList<Integer> typesToConcretes = new ArrayList<>();
-            for (ProfiledType type : ptypes) {
-                ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod);
-                int index = concreteMethods.indexOf(concrete);
-                if (index == -1) {
-                    notRecordedTypeProbability += type.getProbability();
-                } else {
-                    assert type.getType().isArray() || !isAbstract(type.getType().getModifiers()) : type + " " + concrete;
-                    usedTypes.add(type);
-                    typesToConcretes.add(index);
-                }
-            }
-
-            if (usedTypes.size() == 0) {
-                // No type left that is worth checking for.
-                return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
-            }
-
-            for (ResolvedJavaMethod concrete : concreteMethods) {
-                if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
-                    return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
-                }
-            }
-            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
-        }
-    }
-
-    private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
-        return createAnchoredReceiver(graph, anchor, receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType));
-    }
-
-    private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ValueNode receiver, Stamp stamp) {
-        // to avoid that floating reads on receiver fields float above the type check
-        return graph.unique(new GuardedValueNode(receiver, anchor, stamp));
-    }
-
-    // TODO (chaeubl): cleanup this method
-    private static boolean checkInvokeConditions(Invoke invoke) {
-        if (invoke.predecessor() == null || !invoke.asNode().isAlive()) {
-            return logNotInlinedMethod(invoke, "the invoke is dead code");
-        } else if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
-            return logNotInlinedMethod(invoke, "the invoke has already been lowered, or has been created as a low-level node");
-        } else if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() == null) {
-            return logNotInlinedMethod(invoke, "target method is null");
-        } else if (invoke.stateAfter() == null) {
-            // TODO (chaeubl): why should an invoke not have a state after?
-            return logNotInlinedMethod(invoke, "the invoke has no after state");
-        } else if (!invoke.useForInlining()) {
-            return logNotInlinedMethod(invoke, "the invoke is marked to be not used for inlining");
-        } else if (((MethodCallTargetNode) invoke.callTarget()).receiver() != null && ((MethodCallTargetNode) invoke.callTarget()).receiver().isConstant() &&
-                        ((MethodCallTargetNode) invoke.callTarget()).receiver().asConstant().isNull()) {
-            return logNotInlinedMethod(invoke, "receiver is null");
-        } else {
-            return true;
-        }
-    }
-
-    private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) {
-        if (method == null) {
-            return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method is not resolved");
-        } else if (Modifier.isNative(method.getModifiers()) && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(replacements, method))) {
-            return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is a non-intrinsic native method");
-        } else if (Modifier.isAbstract(method.getModifiers())) {
-            return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is an abstract method");
-        } else if (!method.getDeclaringClass().isInitialized()) {
-            return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method's class is not initialized");
-        } else if (!method.canBeInlined()) {
-            return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is marked non-inlinable");
-        } else if (data.countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
-            return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it exceeds the maximum recursive inlining depth");
-        } else if (new OptimisticOptimizations(method.getProfilingInfo()).lessOptimisticThan(optimisticOpts)) {
-            return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the callee uses less optimistic optimizations than caller");
-        } else {
-            return true;
-        }
-    }
-
-    static MonitorExitNode findPrecedingMonitorExit(UnwindNode unwind) {
-        Node pred = unwind.predecessor();
-        while (pred != null) {
-            if (pred instanceof MonitorExitNode) {
-                return (MonitorExitNode) pred;
-            }
-            pred = pred.predecessor();
-        }
-        return null;
-    }
-
-    /**
-     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
-     *
-     * @param invoke the invoke that will be replaced
-     * @param inlineGraph the graph that the invoke will be replaced with
-     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
-     *            false if no such check is required
-     */
-    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
-        final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
-        FixedNode invokeNode = invoke.asNode();
-        StructuredGraph graph = invokeNode.graph();
-        assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
-        assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
-
-        Kind returnKind = invokeNode.getKind();
-
-        FrameState stateAfter = invoke.stateAfter();
-        assert stateAfter == null || stateAfter.isAlive();
-        if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
-            nonNullReceiver(invoke);
-        }
-
-        ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
-        ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
-        UnwindNode unwindNode = null;
-        final StartNode entryPointNode = inlineGraph.start();
-        FixedNode firstCFGNode = entryPointNode.next();
-        if (firstCFGNode == null) {
-            throw new IllegalStateException("Inlined graph is in invalid state");
-        }
-        for (Node node : inlineGraph.getNodes()) {
-            if (node == entryPointNode || node == entryPointNode.stateAfter() || node instanceof ParameterNode) {
-                // Do nothing.
-            } else {
-                nodes.add(node);
-                if (node instanceof ReturnNode) {
-                    returnNodes.add((ReturnNode) node);
-                } else if (node instanceof UnwindNode) {
-                    assert unwindNode == null;
-                    unwindNode = (UnwindNode) node;
-                }
-            }
-        }
-
-        final BeginNode prevBegin = BeginNode.prevBegin(invokeNode);
-        DuplicationReplacement localReplacement = new DuplicationReplacement() {
-
-            public Node replacement(Node node) {
-                if (node instanceof ParameterNode) {
-                    return parameters.get(((ParameterNode) node).index());
-                } else if (node == entryPointNode) {
-                    return prevBegin;
-                }
-                return node;
-            }
-        };
-
-        assert invokeNode.successors().first() != null : invoke;
-        assert invokeNode.predecessor() != null;
-
-        Map<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
-        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
-        invokeNode.replaceAtPredecessor(firstCFGNodeDuplicate);
-
-        FrameState stateAtExceptionEdge = null;
-        if (invoke instanceof InvokeWithExceptionNode) {
-            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
-            if (unwindNode != null) {
-                assert unwindNode.predecessor() != null;
-                assert invokeWithException.exceptionEdge().successors().count() == 1;
-                ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
-                stateAtExceptionEdge = obj.stateAfter();
-                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                obj.replaceAtUsages(unwindDuplicate.exception());
-                unwindDuplicate.clearInputs();
-                Node n = obj.next();
-                obj.setNext(null);
-                unwindDuplicate.replaceAndDelete(n);
-            } else {
-                invokeWithException.killExceptionEdge();
-            }
-
-            // get rid of memory kill
-            BeginNode begin = invokeWithException.next();
-            if (begin instanceof KillingBeginNode) {
-                BeginNode newBegin = new BeginNode();
-                graph.addAfterFixed(begin, graph.add(newBegin));
-                begin.replaceAtUsages(newBegin);
-                graph.removeFixed(begin);
-            }
-        } else {
-            if (unwindNode != null) {
-                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                MonitorExitNode monitorExit = findPrecedingMonitorExit(unwindDuplicate);
-                DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
-                unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode));
-                // move the deopt upwards if there is a monitor exit that tries to use the
-                // "after exception" frame state
-                // (because there is no "after exception" frame state!)
-                if (monitorExit != null) {
-                    if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) {
-                        FrameState monitorFrameState = monitorExit.stateAfter();
-                        graph.removeFixed(monitorExit);
-                        monitorFrameState.safeDelete();
-                    }
-                }
-            }
-        }
-
-        if (stateAfter != null) {
-            FrameState outerFrameState = null;
-            int callerLockDepth = stateAfter.nestedLockDepth();
-            for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
-                FrameState frameState = (FrameState) duplicates.get(original);
-                if (frameState != null) {
-                    assert frameState.bci != FrameState.BEFORE_BCI : frameState;
-                    if (frameState.bci == FrameState.AFTER_BCI) {
-                        frameState.replaceAndDelete(returnKind == Kind.Void ? stateAfter : stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), returnKind,
-                                        frameState.stackAt(0)));
-                    } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) {
-                        if (frameState.isAlive()) {
-                            assert stateAtExceptionEdge != null;
-                            frameState.replaceAndDelete(stateAtExceptionEdge);
-                        } else {
-                            assert stateAtExceptionEdge == null;
-                        }
-                    } else {
-                        // only handle the outermost frame states
-                        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.getKind());
-                                outerFrameState.setDuringCall(true);
-                            }
-                            frameState.setOuterFrameState(outerFrameState);
-                        }
-                    }
-                }
-            }
-            if (callerLockDepth != 0) {
-                for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
-                    MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
-                    monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
-                }
-            }
-        } else {
-            assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
-        }
-        if (!returnNodes.isEmpty()) {
-            FixedNode n = invoke.next();
-            invoke.setNext(null);
-            if (returnNodes.size() == 1) {
-                ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0));
-                Node returnValue = returnNode.result();
-                invokeNode.replaceAtUsages(returnValue);
-                returnNode.clearInputs();
-                returnNode.replaceAndDelete(n);
-            } else {
-                ArrayList<ReturnNode> returnDuplicates = new ArrayList<>(returnNodes.size());
-                for (ReturnNode returnNode : returnNodes) {
-                    returnDuplicates.add((ReturnNode) duplicates.get(returnNode));
-                }
-                MergeNode merge = graph.add(new MergeNode());
-                merge.setStateAfter(stateAfter);
-                ValueNode returnValue = mergeReturns(merge, returnDuplicates);
-                invokeNode.replaceAtUsages(returnValue);
-                merge.setNext(n);
-            }
-        }
-
-        invokeNode.replaceAtUsages(null);
-        GraphUtil.killCFG(invokeNode);
-
-        return duplicates;
-    }
-
-    public static ValueNode mergeReturns(MergeNode merge, List<? extends ReturnNode> returnNodes) {
-        PhiNode returnValuePhi = null;
-
-        for (ReturnNode returnNode : returnNodes) {
-            // create and wire up a new EndNode
-            EndNode endNode = merge.graph().add(new EndNode());
-            merge.addForwardEnd(endNode);
-
-            if (returnNode.result() != null) {
-                if (returnValuePhi == null) {
-                    returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
-                }
-                returnValuePhi.addInput(returnNode.result());
-            }
-            returnNode.clearInputs();
-            returnNode.replaceAndDelete(endNode);
-
-        }
-        return returnValuePhi;
-    }
-
-    private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map<Node, Node> duplicates) {
-        for (Node node : duplicates.values()) {
-            if (node instanceof FrameState) {
-                FrameState frameState = (FrameState) node;
-                assert frameState.bci == FrameState.AFTER_BCI || frameState.bci == FrameState.INVALID_FRAMESTATE_BCI : node.toString(Verbosity.Debugger);
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null.
-     */
-    public static ValueNode nonNullReceiver(Invoke invoke) {
-        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-        assert !callTarget.isStatic() : callTarget.targetMethod();
-        StructuredGraph graph = callTarget.graph();
-        ValueNode firstParam = callTarget.arguments().get(0);
-        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));
-            graph.addBeforeFixed(invoke.asNode(), nonNullReceiver);
-            callTarget.replaceFirstInput(firstParam, nonNullReceiver);
-            return nonNullReceiver;
-        }
-        return firstParam;
-    }
-
-    public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
-        return getIntrinsicGraph(replacements, target) != null || getMacroNodeClass(replacements, target) != null;
-    }
-
-    public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
-        return replacements.getMethodSubstitution(target);
-    }
-
-    public static Class<? extends FixedWithNextNode> getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) {
-        return replacements.getMacroSubstitution(target);
-    }
-
-    public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
-        StructuredGraph graph = invoke.asNode().graph();
-        if (!concrete.equals(((MethodCallTargetNode) invoke.callTarget()).targetMethod())) {
-            assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
-            InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
-        }
-
-        FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke);
-
-        CallTargetNode callTarget = invoke.callTarget();
-        if (invoke instanceof InvokeNode) {
-            graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode));
-        } else {
-            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-            invokeWithException.killExceptionEdge();
-            graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next());
-        }
-        GraphUtil.killWithUnusedFloatingInputs(callTarget);
-        return macroNode;
-    }
-
-    private static FixedWithNextNode createMacroNodeInstance(Class<? extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalInternalError {
-        try {
-            return macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
-        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
-            throw new GraalGraphInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -62,7 +62,7 @@
             canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
             listener.getChangedNodes().clear();
             if (++count > MAX_ITERATIONS) {
-                throw new BailoutException("Number of iterations in conditional elimination phase exceeds " + MAX_ITERATIONS);
+                throw new BailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds " + MAX_ITERATIONS);
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.phases.common;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.phases.common;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
@@ -36,7 +37,6 @@
 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.phases.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
@@ -145,8 +145,7 @@
             } else {
                 GuardNode newGuard = graph.unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, Constant.NULL_OBJECT));
                 if (OptEliminateGuards.getValue()) {
-                    activeGuards.grow();
-                    activeGuards.mark(newGuard);
+                    activeGuards.markAndGrow(newGuard);
                 }
                 return newGuard;
             }
@@ -240,14 +239,20 @@
 
         private final PhaseContext context;
         private final SchedulePhase schedule;
+        private final int iteration;
 
         private Round(int iteration, PhaseContext context) {
-            super("LoweringIteration" + iteration);
+            this.iteration = iteration;
             this.context = context;
             this.schedule = new SchedulePhase();
         }
 
         @Override
+        protected CharSequence createName() {
+            return "LoweringIteration" + iteration;
+        }
+
+        @Override
         public void run(StructuredGraph graph) {
             schedule.apply(graph, false);
             processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null);
@@ -277,7 +282,7 @@
 
             if (parentAnchor == null && OptEliminateGuards.getValue()) {
                 for (GuardNode guard : anchor.asNode().usages().filter(GuardNode.class)) {
-                    if (activeGuards.contains(guard)) {
+                    if (activeGuards.isMarkedAndGrow(guard)) {
                         activeGuards.clear(guard);
                     }
                 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.phases.common;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 
 /**
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.phases.common;
 
 import java.util.*;
+import java.util.function.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.*;
@@ -33,7 +34,6 @@
 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.*;
@@ -55,34 +55,52 @@
 
     private static final String GROUP_NAME = "~profiled weight";
     private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)";
+    private static final String GROUP_NAME_INVOKES = "~profiled invokes";
 
     private static final boolean WITH_SECTION_HEADER = false;
+    private static boolean WITH_INVOKE_FREE_SECTIONS = false;
+    private static boolean WITH_INVOKES = true;
 
     @Override
     protected void run(StructuredGraph graph) {
-        ComputeProbabilityClosure closure = new ComputeProbabilityClosure(graph);
-        NodesToDoubles probabilities = closure.apply();
+        ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
         SchedulePhase schedule = new SchedulePhase();
         schedule.apply(graph, false);
 
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
         for (Loop<Block> loop : cfg.getLoops()) {
-            double loopProbability = probabilities.get(loop.header.getBeginNode());
+            double loopProbability = probabilities.applyAsDouble(loop.getHeader().getBeginNode());
             if (loopProbability > (1D / Integer.MAX_VALUE)) {
-                addSectionCounters(loop.header.getBeginNode(), loop.blocks, loop.children, schedule, probabilities);
+                addSectionCounters(loop.getHeader().getBeginNode(), loop.getBlocks(), loop.getChildren(), schedule, probabilities);
             }
         }
-        addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+        // don't put the counter increase directly after the start (problems with OSR)
+        FixedWithNextNode current = graph.start();
+        while (current.next() instanceof FixedWithNextNode) {
+            current = (FixedWithNextNode) current.next();
+        }
+        addSectionCounters(current, cfg.getBlocks(), cfg.getLoops(), schedule, probabilities);
+
+        if (WITH_INVOKES) {
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Invoke) {
+                    Invoke invoke = (Invoke) node;
+                    DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode());
+
+                }
+            }
+        }
     }
 
-    private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) {
+    private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, SchedulePhase schedule,
+                    ToDoubleFunction<FixedNode> probabilities) {
         HashSet<Block> blocks = new HashSet<>(sectionBlocks);
         for (Loop<?> loop : childLoops) {
-            blocks.removeAll(loop.blocks);
+            blocks.removeAll(loop.getBlocks());
         }
-        double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start);
+        double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.applyAsDouble(start);
         DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
-        if (!hasInvoke(blocks)) {
+        if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) {
             DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next());
         }
     }
@@ -95,10 +113,10 @@
         }
     }
 
-    private static double getSectionWeight(SchedulePhase schedule, NodesToDoubles probabilities, Collection<Block> blocks) {
+    private static double getSectionWeight(SchedulePhase schedule, ToDoubleFunction<FixedNode> probabilities, Collection<Block> blocks) {
         double count = 0;
         for (Block block : blocks) {
-            double blockProbability = probabilities.get(block.getBeginNode());
+            double blockProbability = probabilities.applyAsDouble(block.getBeginNode());
             for (ScheduledNode node : schedule.getBlockToNodesMap().get(block)) {
                 count += blockProbability * getNodeWeight(node);
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.common;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.phases.*;
-
-public class ReadEliminationPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) {
-            if (isReadEliminable(n)) {
-                NodeMap<ValueNode> nodeMap = n.graph().createNodeMap();
-                ValueNode value = getValue(n, n.getLastLocationAccess(), nodeMap);
-                Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value);
-                graph.replaceFloating(n, value);
-            }
-        }
-    }
-
-    private static boolean isReadEliminable(FloatingReadNode n) {
-        return isWrites(n, n.getLastLocationAccess(), n.graph().createNodeBitMap());
-    }
-
-    private static boolean isWrites(FloatingReadNode n, MemoryNode lastLocationAccess, NodeBitMap visited) {
-        if (lastLocationAccess == null) {
-            return false;
-        }
-        if (visited.isMarked(ValueNodeUtil.asNode(lastLocationAccess))) {
-            return true; // dataflow loops must come from Phis assume them ok until proven wrong
-        }
-        if (lastLocationAccess instanceof ProxyNode) {
-            return isWrites(n, (MemoryNode) ((ProxyNode) lastLocationAccess).value(), visited);
-        }
-        if (lastLocationAccess instanceof WriteNode) {
-            WriteNode other = (WriteNode) lastLocationAccess;
-            return other.object() == n.object() && other.location() == n.location();
-        }
-        if (lastLocationAccess instanceof MemoryPhiNode) {
-            visited.mark(ValueNodeUtil.asNode(lastLocationAccess));
-            for (ValueNode value : ((MemoryPhiNode) lastLocationAccess).values()) {
-                if (!isWrites(n, (MemoryNode) value, visited)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private static ValueNode getValue(FloatingReadNode n, MemoryNode lastLocationAccess, NodeMap<ValueNode> nodeMap) {
-        ValueNode exisiting = nodeMap.get(ValueNodeUtil.asNode(lastLocationAccess));
-        if (exisiting != null) {
-            return exisiting;
-        }
-        if (lastLocationAccess instanceof MemoryProxyNode) {
-            MemoryProxyNode proxy = (MemoryProxyNode) lastLocationAccess;
-            ValueNode value = getValue(n, proxy.getOriginalMemoryNode(), nodeMap);
-            return ProxyNode.forValue(value, proxy.proxyPoint(), proxy.graph());
-        }
-        if (lastLocationAccess instanceof WriteNode) {
-            return ((WriteNode) lastLocationAccess).value();
-        }
-        if (lastLocationAccess instanceof MemoryPhiNode) {
-            MemoryPhiNode phi = (MemoryPhiNode) lastLocationAccess;
-            ValuePhiNode newPhi = phi.graph().addWithoutUnique(new ValuePhiNode(n.stamp().unrestricted(), phi.merge()));
-            nodeMap.set(phi, newPhi);
-            for (ValueNode value : phi.values()) {
-                newPhi.addInput(getValue(n, (MemoryNode) value, nodeMap));
-            }
-            return newPhi;
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.phases.common;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
+import java.util.function.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -39,7 +40,6 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
@@ -154,13 +154,15 @@
 
     @Override
     protected void run(StructuredGraph graph, PhaseContext phaseContext) {
-        NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
+        if (graph.hasNode(MergeNode.class)) {
+            ToDoubleFunction<FixedNode> nodeProbabilities = new FixedNodeProbabilityCache();
 
-        // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
-        // duplication.
-        for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
-            if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= TailDuplicationProbability.getValue()) {
-                tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer);
+            // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
+            // duplication.
+            for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
+                if (!(merge instanceof LoopBeginNode) && nodeProbabilities.applyAsDouble(merge) >= TailDuplicationProbability.getValue()) {
+                    tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,10 @@
  */
 package com.oracle.graal.phases.common;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -34,6 +37,10 @@
 
 public class UseTrappingNullChecksPhase extends BasePhase<LowTierContext> {
 
+    private static final DebugMetric metricTrappingNullCheck = Debug.metric("TrappingNullCheck");
+    private static final DebugMetric metricTrappingNullCheckUnreached = Debug.metric("TrappingNullCheckUnreached");
+    private static final DebugMetric metricTrappingNullCheckDynamicDeoptimize = Debug.metric("TrappingNullCheckDynamicDeoptimize");
+
     @Override
     protected void run(StructuredGraph graph, LowTierContext context) {
         if (context.getTarget().implicitNullCheckLimit <= 0) {
@@ -42,36 +49,111 @@
         assert graph.getGuardsStage().ordinal() >= GuardsStage.AFTER_FSA.ordinal();
 
         for (DeoptimizeNode deopt : graph.getNodes(DeoptimizeNode.class)) {
-            tryUseTrappingNullCheck(deopt);
+            tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.reason(), deopt.getSpeculation());
+        }
+        for (DynamicDeoptimizeNode deopt : graph.getNodes(DynamicDeoptimizeNode.class)) {
+            tryUseTrappingNullCheck(context.getMetaAccess(), deopt);
         }
     }
 
-    private static void tryUseTrappingNullCheck(DeoptimizeNode deopt) {
-        if (deopt.reason() != DeoptimizationReason.NullCheckException) {
-            return;
+    private static void tryUseTrappingNullCheck(MetaAccessProvider metaAccessProvider, DynamicDeoptimizeNode deopt) {
+        Node predecessor = deopt.predecessor();
+        if (predecessor instanceof MergeNode) {
+            MergeNode merge = (MergeNode) predecessor;
+
+            // Process each predecessor at the merge, unpacking the reasons and speculations as
+            // needed.
+            ValueNode reason = deopt.getActionAndReason();
+            ValuePhiNode reasonPhi = null;
+            List<ValueNode> reasons = null;
+            int expectedPhis = 0;
+
+            if (reason instanceof ValuePhiNode) {
+                reasonPhi = (ValuePhiNode) reason;
+                if (reasonPhi.merge() != merge) {
+                    return;
+                }
+                reasons = reasonPhi.values().snapshot();
+                expectedPhis++;
+            } else if (!reason.isConstant()) {
+                return;
+            }
+
+            ValueNode speculation = deopt.getSpeculation();
+            ValuePhiNode speculationPhi = null;
+            List<ValueNode> speculations = null;
+            if (speculation instanceof ValuePhiNode) {
+                speculationPhi = (ValuePhiNode) speculation;
+                if (speculationPhi.merge() != merge) {
+                    return;
+                }
+                speculations = speculationPhi.values().snapshot();
+                expectedPhis++;
+            }
+
+            if (merge.phis().count() != expectedPhis) {
+                return;
+            }
+
+            int index = 0;
+            for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+                ValueNode thisReason = reasons != null ? reasons.get(index) : reason;
+                ValueNode thisSpeculation = speculations != null ? speculations.get(index++) : speculation;
+                if (!thisReason.isConstant() || !thisSpeculation.isConstant() || !thisSpeculation.asConstant().equals(Constant.NULL_OBJECT)) {
+                    continue;
+                }
+                DeoptimizationReason deoptimizationReason = metaAccessProvider.decodeDeoptReason(thisReason.asConstant());
+                tryUseTrappingNullCheck(deopt, end.predecessor(), deoptimizationReason, null);
+            }
         }
-        if (deopt.getSpeculation() != null && !deopt.getSpeculation().equals(Constant.NULL_OBJECT)) {
+    }
+
+    private static void tryUseTrappingNullCheck(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason, Constant speculation) {
+        if (deoptimizationReason != DeoptimizationReason.NullCheckException && deoptimizationReason != DeoptimizationReason.UnreachedCode) {
             return;
         }
-        Node predecessor = deopt.predecessor();
+        if (speculation != null && !speculation.equals(Constant.NULL_OBJECT)) {
+            return;
+        }
+        if (predecessor instanceof MergeNode) {
+            MergeNode merge = (MergeNode) predecessor;
+            if (merge.phis().isEmpty()) {
+                for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+                    checkPredecessor(deopt, end.predecessor(), deoptimizationReason);
+                }
+            }
+        } else if (predecessor instanceof BeginNode) {
+            checkPredecessor(deopt, predecessor, deoptimizationReason);
+        }
+    }
+
+    private static void checkPredecessor(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason) {
+        Node current = predecessor;
         Node branch = null;
-        while (predecessor instanceof BeginNode) {
-            branch = predecessor;
-            predecessor = predecessor.predecessor();
+        while (current instanceof BeginNode) {
+            branch = current;
+            current = current.predecessor();
         }
-        if (predecessor instanceof IfNode) {
-            IfNode ifNode = (IfNode) predecessor;
+        if (current instanceof IfNode) {
+            IfNode ifNode = (IfNode) current;
             if (branch != ifNode.trueSuccessor()) {
                 return;
             }
             LogicNode condition = ifNode.condition();
             if (condition instanceof IsNullNode) {
-                replaceWithTrappingNullCheck(deopt, ifNode, condition);
+                replaceWithTrappingNullCheck(deopt, ifNode, condition, deoptimizationReason);
             }
         }
     }
 
-    private static void replaceWithTrappingNullCheck(DeoptimizeNode deopt, IfNode ifNode, LogicNode condition) {
+    private static void replaceWithTrappingNullCheck(AbstractDeoptimizeNode deopt, IfNode ifNode, LogicNode condition, DeoptimizationReason deoptimizationReason) {
+        metricTrappingNullCheck.increment();
+        if (deopt instanceof DynamicDeoptimizeNode) {
+            metricTrappingNullCheckDynamicDeoptimize.increment();
+        }
+        if (deoptimizationReason == DeoptimizationReason.UnreachedCode) {
+            metricTrappingNullCheckUnreached.increment();
+        }
         IsNullNode isNullNode = (IsNullNode) condition;
         BeginNode nonTrappingContinuation = ifNode.falseSuccessor();
         BeginNode trappingContinuation = ifNode.trueSuccessor();
@@ -79,6 +161,17 @@
         trappingNullCheck.setStateBefore(deopt.stateBefore());
         deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation);
 
+        /*
+         * We now have the pattern NullCheck/BeginNode/... It's possible some node is using the
+         * BeginNode as a guard input, so replace guard users of the Begin with the NullCheck and
+         * then remove the Begin from the graph.
+         */
+        nonTrappingContinuation.replaceAtUsages(InputType.Guard, trappingNullCheck);
+        FixedNode next = nonTrappingContinuation.next();
+        nonTrappingContinuation.clearSuccessors();
+        trappingNullCheck.setNext(next);
+        nonTrappingContinuation.safeDelete();
+
         GraphUtil.killCFG(trappingContinuation);
         if (isNullNode.usages().isEmpty()) {
             GraphUtil.killWithUnusedFloatingInputs(isNullNode);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -63,9 +63,9 @@
         }
     }
 
-    private static class CleanupValueAnchorsClosure extends PostOrderNodeIterator<State> {
+    private static class CleanupValueAnchorsClosure extends SinglePassNodeIterator<State> {
 
-        public CleanupValueAnchorsClosure(FixedNode start) {
+        public CleanupValueAnchorsClosure(StartNode start) {
             super(start, new State());
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.phases.graph.SinglePassNodeIterator;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.util.ArrayList;
+
+/**
+ * <p>
+ * For readability purposes the code realizing control-flow-sensitive reductions is chopped into
+ * several classes in an inheritance hierarchy, this class being their common ancestor. That way,
+ * many dependencies can be ruled out immediately (e.g., private members of a class aren't needed by
+ * other classes). The whole thing is reminiscent of trait-based patterns, minus their
+ * disadvantages.
+ * </p>
+ *
+ * <p>
+ * This class makes available little more than a few fields and a few utility methods used
+ * throughout the remaining components making up control-flow sensitive reductions.
+ * </p>
+ *
+ * <p>
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ * </p>
+ *
+ */
+public abstract class BaseReduction extends SinglePassNodeIterator<State> {
+
+    protected static final DebugMetric metricCheckCastRemoved = Debug.metric("FSR-CheckCastRemoved");
+    protected static final DebugMetric metricGuardingPiNodeRemoved = Debug.metric("FSR-GuardingPiNodeRemoved");
+    protected static final DebugMetric metricFixedGuardNodeRemoved = Debug.metric("FSR-FixedGuardNodeRemoved");
+    protected static final DebugMetric metricMethodResolved = Debug.metric("FSR-MethodResolved");
+    protected static final DebugMetric metricUnconditionalDeoptInserted = Debug.metric("FSR-UnconditionalDeoptInserted");
+
+    /**
+     * <p>
+     * Upon visiting a {@link com.oracle.graal.nodes.FixedNode FixedNode} in
+     * {@link #node(com.oracle.graal.nodes.FixedNode)}, an impossible path may be detected. We'd
+     * like to insert an unconditional deoptimizing node as a hint for Dead Code Elimination to kill
+     * that branch. However that can't be made on the go (a
+     * {@link com.oracle.graal.nodes.ControlSinkNode} can't have successors). Thus their insertion
+     * is postponed till the end of a round of
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}.
+     * </p>
+     *
+     * @see State#impossiblePath()
+     * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#finished()
+     */
+    public static class PostponedDeopt {
+
+        private final boolean goesBeforeFixed;
+        private final FixedWithNextNode fixed;
+        private final DeoptimizationReason deoptReason;
+
+        public PostponedDeopt(boolean goesBeforeFixed, FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            this.goesBeforeFixed = goesBeforeFixed;
+            this.fixed = fixed;
+            this.deoptReason = deoptReason;
+        }
+
+        /*
+         * TODO Actually, we want to emit instructions to signal "should-not-reach-here". An
+         * imperfect substitute (as done here) is emitting FixedGuard(false).
+         * "should-not-reach-here" would be better for the runtime error it raises, thus pointing to
+         * a bug in FlowSensitiveReduction (the code was reachable, after all).
+         */
+        public void doRewrite(LogicNode falseConstant) {
+            metricUnconditionalDeoptInserted.increment();
+            StructuredGraph graph = fixed.graph();
+            // have to insert a FixedNode other than a ControlSinkNode
+            FixedGuardNode buckStopsHere = graph.add(new FixedGuardNode(falseConstant, deoptReason, DeoptimizationAction.None));
+            if (goesBeforeFixed) {
+                fixed.replaceAtPredecessor(buckStopsHere);
+            } else {
+                graph.addAfterFixed(fixed, buckStopsHere);
+            }
+        }
+
+    }
+
+    protected static class PostponedDeopts extends ArrayList<PostponedDeopt> {
+
+        private static final long serialVersionUID = 7188324432387121238L;
+
+        /**
+         * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right before the fixed
+         * argument, will be done once we're done traversing the graph.
+         *
+         * @see #finished()
+         */
+        void addDeoptBefore(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            add(new PostponedDeopt(true, fixed, deoptReason));
+        }
+
+        /**
+         * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right after the fixed
+         * argument, will be done once we're done traversing the graph.
+         *
+         * @see #finished()
+         */
+        void addDeoptAfter(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            add(new PostponedDeopt(false, fixed, deoptReason));
+        }
+
+    }
+
+    /**
+     * <p>
+     * One of the promises of
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+     * is that a "maximally reduced" node is returned. That is achieved in part by leveraging
+     * {@link com.oracle.graal.graph.Node#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)}.
+     * Doing so, in turn, requires this subclass of
+     * {@link com.oracle.graal.graph.spi.CanonicalizerTool}.
+     * </p>
+     */
+    public final class Tool implements CanonicalizerTool {
+
+        private final PhaseContext context;
+
+        public Tool(PhaseContext context) {
+            this.context = context;
+        }
+
+        @Override
+        public Assumptions assumptions() {
+            return context.getAssumptions();
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return context.getMetaAccess();
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return context.getConstantReflection();
+        }
+
+        /**
+         * Postpone
+         * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)}
+         * until {@link FlowSensitiveReduction#finished()} for the reasons covered there.
+         */
+        @Override
+        public void removeIfUnused(Node node) {
+            // GraphUtil.tryKillUnused(node);
+        }
+
+        @Override
+        public boolean canonicalizeReads() {
+            return false;
+        }
+    } // end of class FlowSensitiveReduction.Tool
+
+    protected final LogicConstantNode trueConstant;
+    protected final LogicConstantNode falseConstant;
+    protected final ConstantNode nullConstant;
+
+    protected final CanonicalizerTool tool;
+    protected final StructuredGraph graph;
+
+    protected EquationalReasoner reasoner;
+
+    protected final PostponedDeopts postponedDeopts = new PostponedDeopts();
+
+    protected BaseReduction(StartNode start, State initialState, PhaseContext context) {
+        super(start, initialState);
+        graph = start.graph();
+        trueConstant = LogicConstantNode.tautology(graph);
+        falseConstant = LogicConstantNode.contradiction(graph);
+        nullConstant = ConstantNode.defaultForKind(Kind.Object, graph); // ConstantNode.forObject(null,
+                                                                        // metaAccess, graph);
+        tool = new Tool(context);
+        reasoner = new EquationalReasoner(graph, tool, trueConstant, falseConstant, nullConstant);
+    }
+
+    /**
+     * <p>
+     * Test whether the output's stamp is an upcast of that of the input. For example, upon
+     * replacing a CheckCastNode in
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, com.oracle.graal.nodes.ValueNode)}
+     * we don't want to be left with an upcast, as it loses precision.
+     * </p>
+     *
+     * <p>
+     * As usual with object stamps, they can be compared along different dimensions (alwaysNull,
+     * etc.) It's enough for one such dimension to show precision loss for the end result to be
+     * reported as such.
+     * </p>
+     *
+     */
+    public static boolean precisionLoss(ValueNode input, ValueNode output) {
+        ObjectStamp inputStamp = (ObjectStamp) input.stamp();
+        ObjectStamp outputStamp = (ObjectStamp) output.stamp();
+        if (FlowUtil.isMorePrecise(inputStamp.type(), outputStamp.type())) {
+            return true;
+        }
+        if (lessThan(outputStamp.alwaysNull(), inputStamp.alwaysNull())) {
+            return true;
+        }
+        if (lessThan(outputStamp.nonNull(), inputStamp.nonNull())) {
+            return true;
+        }
+        if (lessThan(outputStamp.isExactType(), inputStamp.isExactType())) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean lessThan(boolean a, boolean b) {
+        return a == false && b == true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.LogicNode;
+import com.oracle.graal.nodes.ShortCircuitOrNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+
+/**
+ * @see #extract(com.oracle.graal.nodes.LogicNode)
+ */
+class CastCheckExtractor {
+
+    public final ResolvedJavaType type;
+    public final ValueNode subject;
+
+    CastCheckExtractor(ResolvedJavaType type, ValueNode subject) {
+        this.type = type;
+        this.subject = subject;
+    }
+
+    private static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) {
+        if (x instanceof IsNullNode) {
+            IsNullNode isNull = (IsNullNode) x;
+            ValueNode subject = isNull.object();
+            if (isInstanceOfCheckOn(y, subject)) {
+                InstanceOfNode iOf = (InstanceOfNode) y;
+                return new CastCheckExtractor(iOf.type(), subject);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method detects whether the argument realizes the CheckCast pattern. If so, distills and
+     * returns the essentials of such check, otherwise returns null.
+     */
+    static CastCheckExtractor extract(LogicNode cond) {
+        if (!(cond instanceof ShortCircuitOrNode)) {
+            return null;
+        }
+        ShortCircuitOrNode orNode = (ShortCircuitOrNode) cond;
+        if (orNode.isXNegated() || orNode.isYNegated()) {
+            return null;
+        }
+        CastCheckExtractor result = extractCastCheckInfo(orNode.getX(), orNode.getY());
+        if (result != null) {
+            return result;
+        }
+        result = extractCastCheckInfo(orNode.getY(), orNode.getX());
+        return result;
+    }
+
+    /**
+     * Porcelain method.
+     */
+    static boolean isInstanceOfCheckOn(LogicNode cond, ValueNode subject) {
+        if (!(cond instanceof InstanceOfNode)) {
+            return false;
+        }
+        InstanceOfNode io = (InstanceOfNode) cond;
+        return io.object() == subject;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.java.CheckCastNode}.
+ * </p>
+ *
+ * <p>
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ * </p>
+ *
+ * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+ */
+public abstract class CheckCastReduction extends GuardingPiReduction {
+
+    public CheckCastReduction(StartNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * Upon visiting a {@link com.oracle.graal.nodes.java.CheckCastNode}, based on flow-sensitive
+     * conditions, we need to determine whether:
+     * <ul>
+     * <li>it is redundant (in which case it should be simplified), or</li>
+     * <li>flow-sensitive information can be gained from it. "Gain information from it" requires
+     * lowering the {@link com.oracle.graal.nodes.java.CheckCastNode} such that a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} becomes available.</li>
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * This method realizes the above by testing first for situations that require less work:
+     * <ol>
+     * <li>the stamp of the subject deems the check-cast redundant or unsatisfiable (ie,
+     * always-succeeds or always-fails). A previous round of canonicalization takes care of this
+     * situation, however it can also arise due to consecutive runs of
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} without intervening
+     * {@link com.oracle.graal.phases.common.CanonicalizerPhase canonicalization}.</li>
+     * <li>
+     * flow-sensitive information reveals the subject to be null, trivially fulfilling the
+     * check-cast.</li>
+     * <li>
+     * flow-sensitive information reveals the subject to be narrower than it stamp says. If the
+     * narrower ("downcasted") value fulfills the check-cast, the check-cast is removed.</li>
+     * <li>
+     * otherwise the check-cast provides additional flow-sensitive information. For that, a
+     * {@link com.oracle.graal.nodes.FixedGuardNode} is needed, as described in
+     * {@link #lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, com.oracle.graal.nodes.ValueNode)}
+     * . Please notice this lowering is currently performed unconditionally: it might occur no
+     * flow-sensitive reduction is enabled down the road.</li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * Precondition: the inputs (ie, object) hasn't been deverbosified yet.
+     * </p>
+     */
+    protected final void visitCheckCastNode(CheckCastNode checkCast) {
+
+        /*
+         * checkCast.object() hasn't been deverbosified yet.
+         */
+
+        if (!FlowUtil.hasLegalObjectStamp(checkCast)) {
+            // This situation is exercised by test Class_cast01
+            return;
+        }
+
+        final ValueNode subject = checkCast.object();
+        final ResolvedJavaType toType = checkCast.type();
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        // --------- checkCast deemed redundant by subject-stamp alone ---------
+        // --------- in particular due to stamp informing always null ----------
+        boolean isRedundantPerStamp = StampTool.isObjectAlwaysNull(subject) || (subjectType != null && toType.isAssignableFrom(subjectType));
+        if (isRedundantPerStamp) {
+            metricCheckCastRemoved.increment();
+            checkCast.replaceAtUsages(subject);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        assert !StampTool.isObjectAlwaysNull(subject) : "Null as per stamp subjects should have been handled above";
+
+        // --------- checkCast deemed unsatisfiable by subject-stamp alone ---------
+        if (state.knownNotToPassCheckCast(subject, toType)) {
+            postponedDeopts.addDeoptBefore(checkCast, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException);
+            state.impossiblePath();
+            // let FixedGuardNode(false).simplify() prune the dead-code control-path
+            return;
+        }
+
+        /*
+         * Remark: subject may be TypeProxyNode, GuardedValueNode, ProxyNode, GuardingPiNode, among
+         * others.
+         */
+
+        PiNode untrivialNull = reasoner.nonTrivialNull(subject);
+        if (untrivialNull != null) {
+            metricCheckCastRemoved.increment();
+            checkCast.replaceAtUsages(untrivialNull);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        Witness w = state.typeInfo(subject);
+
+        if (w == null) {
+            /*
+             * If there's no witness, attempting `downcast(subject)` is futile.
+             */
+            visitCheckCastNodeLackingWitness(checkCast);
+            return;
+        }
+
+        visitCheckCastNodeWithWitness(checkCast);
+
+    }
+
+    /**
+     * Given that no witness is available for the {@link com.oracle.graal.nodes.java.CheckCastNode}
+     * 's subject there's no point in downcasting such subject, ie no
+     * {@link com.oracle.graal.nodes.PiNode} can be fabricated for the subject.
+     *
+     * @see #lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode,
+     *      com.oracle.graal.nodes.ValueNode)
+     *
+     */
+    private void visitCheckCastNodeLackingWitness(CheckCastNode checkCast) {
+        final ValueNode subject = checkCast.object();
+        final ResolvedJavaType toType = checkCast.type();
+        if (toType.isInterface()) {
+            return;
+        }
+        assert reasoner.downcast(subject) == subject;
+        lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+    }
+
+    /**
+     * Porcelain method.
+     *
+     * <p>
+     * Rather than tracking the CheckCastNode via {@link com.oracle.graal.phases.common.cfs.State
+     * State} (doing so would add a special case because a
+     * {@link com.oracle.graal.nodes.java.CheckCastNode} isn't a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode guarding node}) this method creates an
+     * anchor by lowering the CheckCastNode into a FixedGuardNode. Not the same as the
+     * {@link com.oracle.graal.nodes.java.CheckCastNode#lower(com.oracle.graal.nodes.spi.LoweringTool)
+     * lowering of a CheckCastNode} which results in a {@link com.oracle.graal.nodes.GuardingPiNode}
+     * (which is not a {@link com.oracle.graal.nodes.extended.GuardingNode guarding node}).
+     * </p>
+     *
+     * <p>
+     * With that, state tracking can proceed as usual.
+     * </p>
+     *
+     * <p>
+     * TODO This lowering is currently performed unconditionally: it might occur no flow-sensitive
+     * reduction is enabled down the road
+     * </p>
+     *
+     * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     *
+     */
+    public void lowerCheckCastAnchorFriendlyWay(CheckCastNode checkCast, ValueNode subject) {
+        ValueNode originalCheckCastObject = checkCast.object();
+
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        final ResolvedJavaType toType = checkCast.type();
+        ObjectStamp resultStamp = (ObjectStamp) StampFactory.declared(toType);
+        JavaTypeProfile profile = checkCast.profile();
+
+        assert FlowUtil.isLegalObjectStamp(subjectStamp);
+        assert subjectStamp.type() == null || !toType.isAssignableFrom(subjectStamp.type()) : "No need to lower in an anchor-friendly way in the first place";
+
+        /*
+         * Depending on what is known about the subject:
+         * 
+         * (a) definitely-non-null
+         * 
+         * (b) null-not-seen-in-profiling
+         * 
+         * (c) runtime-null-check-needed
+         * 
+         * the condition (of the cast-guard to be emitted) and the stamp (of the PiNode to be
+         * emitted) are going to be different. Each of the three branches below deals with one of
+         * the cases above.
+         */
+        LogicNode condition;
+        if (subjectStamp.nonNull()) {
+            /*
+             * (1 of 3) definitely-non-null
+             */
+            // addWithoutUnique for the same reason as in CheckCastNode.lower()
+            condition = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+            reasoner.added.add(condition);
+            resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+            // TODO fix in CheckCastNode.lower()
+        } else {
+            if (profile != null && profile.getNullSeen() == ProfilingInfo.TriState.FALSE) {
+                /*
+                 * (2 of 3) null-not-seen-in-profiling
+                 */
+                IsNullNode isNN = graph.unique(new IsNullNode(subject));
+                reasoner.added.add(isNN);
+                FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true));
+                graph.addBeforeFixed(checkCast, nullCheck);
+                // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+                PiNode nonNullGuarded = graph.unique(new PiNode(subject, FlowUtil.asNonNullStamp(subjectStamp), nullCheck));
+                reasoner.added.add(nonNullGuarded);
+                // addWithoutUnique for the same reason as in CheckCastNode.lower()
+                condition = graph.addWithoutUnique(new InstanceOfNode(toType, nonNullGuarded, profile));
+                reasoner.added.add(condition);
+                resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+            } else {
+                /*
+                 * (3 of 3) runtime-null-check-needed
+                 */
+                // addWithoutUnique for the same reason as in CheckCastNode.lower()
+                InstanceOfNode typeTest = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+                reasoner.added.add(typeTest);
+                LogicNode nullTest = graph.unique(new IsNullNode(subject));
+                reasoner.added.add(nullTest);
+                // TODO (ds) replace with probability of null-seen when available
+                final double shortCircuitProbability = NOT_FREQUENT_PROBABILITY;
+                condition = LogicNode.or(nullTest, typeTest, shortCircuitProbability);
+                reasoner.added.add(condition);
+            }
+        }
+
+        /*
+         * Add a cast-guard (checking only what needs to be checked) and a PiNode (to be used in
+         * place of the CheckCastNode).
+         */
+        FixedGuardNode castGuard = graph.add(new FixedGuardNode(condition, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException, InvalidateReprofile));
+        graph.addBeforeFixed(checkCast, castGuard);
+
+        assert FlowUtil.isLegalObjectStamp(resultStamp);
+        Witness w = state.typeInfo(subject);
+        assert !isTypeOfWitnessBetter(w, resultStamp);
+
+        if (!FlowUtil.lacksUsages(checkCast)) {
+            // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+            PiNode checkedObject = graph.unique(new PiNode(subject, resultStamp, castGuard));
+            reasoner.added.add(checkedObject);
+            assert !precisionLoss(originalCheckCastObject, checkedObject);
+            assert !precisionLoss(subject, checkedObject);
+            checkCast.replaceAtUsages(checkedObject);
+        }
+
+        graph.removeFixed(checkCast);
+
+        if (resultStamp.nonNull()) {
+            state.trackIO(subject, toType, castGuard);
+        } else {
+            state.trackCC(subject, toType, castGuard);
+        }
+    }
+
+    /**
+     * Porcelain method.
+     */
+    public static boolean isTypeOfWitnessBetter(Witness w, ObjectStamp stamp) {
+        if (w == null) {
+            return false;
+        }
+        return FlowUtil.isMorePrecise(w.type(), stamp.type());
+    }
+
+    /**
+     *
+     * Please note in this method "subject" refers to the downcasted input to the checkCast.
+     *
+     * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     */
+    private void visitCheckCastNodeWithWitness(CheckCastNode checkCast) {
+
+        final ResolvedJavaType toType = checkCast.type();
+
+        ValueNode subject;
+        if (checkCast.object() instanceof CheckCastNode) {
+            subject = reasoner.downcast(checkCast);
+            if (subject == checkCast) {
+                subject = reasoner.downcast(checkCast.object());
+            }
+        } else {
+            subject = reasoner.downcast(checkCast.object());
+        }
+
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        /*
+         * At this point, two sources of (partial) information: the witness and the stamp of
+         * subject. The latter might be more precise than the witness (eg, subject might be
+         * GuardedValueNode)
+         */
+
+        // --------- checkCast made redundant by downcasting its input ---------
+        if (subjectType != null && toType.isAssignableFrom(subjectType)) {
+            checkCast.replaceAtUsages(subject);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        /*
+         * At this point, `downcast()` might or might not have delivered a more precise value. If
+         * more precise, it wasn't precise enough to conform to `toType`. Even so, for the
+         * `toType.isInterface()` case (dealt with below) we'll replace the checkCast's input with
+         * that value (its class-stamp being more precise than the original).
+         */
+
+        if (toType.isInterface()) {
+            boolean wasDowncasted = (subject != checkCast.object());
+            if (wasDowncasted) {
+                FlowUtil.replaceInPlace(checkCast, checkCast.object(), subject);
+            }
+            return;
+        }
+
+        lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,953 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * <p>
+ * This class implements a simple partial evaluator that recursively reduces a given
+ * {@link com.oracle.graal.nodes.calc.FloatingNode} into a simpler one based on the current state.
+ * Such evaluator comes handy when visiting a {@link com.oracle.graal.nodes.FixedNode} N, just
+ * before updating the state for N. At the pre-state, an {@link EquationalReasoner} can be used to
+ * reduce N's inputs (actually only those inputs of Value and Condition
+ * {@link com.oracle.graal.graph.InputType InputType}). For an explanation of where it's warranted
+ * to replace "old input" with "reduced input", see the inline comments in method
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node n) deverbosify(Node n)}
+ * </p>
+ *
+ * <p>
+ * The name {@link EquationalReasoner EquationalReasoner} was chosen because it conveys what it
+ * does.
+ * </p>
+ */
+public final class EquationalReasoner {
+
+    private static final DebugMetric metricInstanceOfRemoved = Debug.metric("FSR-InstanceOfRemoved");
+    private static final DebugMetric metricNullCheckRemoved = Debug.metric("FSR-NullCheckRemoved");
+    private static final DebugMetric metricObjectEqualsRemoved = Debug.metric("FSR-ObjectEqualsRemoved");
+    private static final DebugMetric metricEquationalReasoning = Debug.metric("FSR-EquationalReasoning");
+    private static final DebugMetric metricDowncasting = Debug.metric("FSR-Downcasting");
+    private static final DebugMetric metricNullInserted = Debug.metric("FSR-NullInserted");
+
+    private final StructuredGraph graph;
+    private final CanonicalizerTool tool;
+    private final LogicConstantNode trueConstant;
+    private final LogicConstantNode falseConstant;
+    private final ConstantNode nullConstant;
+
+    private State state;
+    private NodeBitMap visited;
+
+    /**
+     * The reduction of a {@link com.oracle.graal.nodes.calc.FloatingNode} performed by
+     * {@link EquationalReasoner EquationalReasoner} may result in a FloatingNode being added to the
+     * graph. Those nodes aren't tracked in the {@link EquationalReasoner#visited visited}
+     * {@link com.oracle.graal.graph.NodeBitMap NodeBitMap} but in this set instead (those nodes are
+     * added after the {@link com.oracle.graal.graph.NodeBitMap} was obtained).
+     */
+    final Set<ValueNode> added = newNodeIdentitySet();
+
+    /**
+     * The reduction of a FloatingNode performed by {@link EquationalReasoner EquationalReasoner}
+     * may result in a FloatingNode being added to the graph. Those nodes are tracked in this map,
+     * to avoid recomputing them.
+     *
+     * The substitutions tracked in this field become invalid as described in
+     * {@link #updateState(com.oracle.graal.phases.common.cfs.State) updateState(State)}
+     */
+    private final Map<ValueNode, ValueNode> substs = newNodeIdentityMap();
+
+    public EquationalReasoner(StructuredGraph graph, CanonicalizerTool tool, LogicConstantNode trueConstant, LogicConstantNode falseConstant, ConstantNode nullConstant) {
+        this.graph = graph;
+        this.tool = tool;
+        this.trueConstant = trueConstant;
+        this.falseConstant = falseConstant;
+        this.nullConstant = nullConstant;
+    }
+
+    /**
+     * {@link #added} grows during a run of
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase
+     * FlowSensitiveReductionPhase}, and doesn't survive across runs.
+     */
+    public void forceState(State s) {
+        state = s;
+        assert state.repOK();
+        substs.clear();
+        added.clear();
+        visited = null;
+        versionNrAsofLastForce = s.versionNr;
+    }
+
+    /**
+     * <p>
+     * Gaining more precise type information about an SSA value doesn't "invalidate" as such any of
+     * the substitutions tracked in {@link EquationalReasoner#substs substs}, at least not in the
+     * sense of making the value tracked by one such entry "wrong". However, clearing the
+     * {@link EquationalReasoner#substs substs} is still justified because next time they are
+     * computed, the newly computed reduction could (in principle) be more effective (due to the
+     * more precise type information).
+     * </p>
+     *
+     * <p>
+     * Between clearings of cached substitutions, it is expected they get applied a number of times
+     * to justify the bookkeeping cost.
+     * </p>
+     *
+     */
+    public void updateState(State s) {
+        assert s != null;
+        if (state == null || state != s || state.versionNr != versionNrAsofLastForce) {
+            forceState(s);
+        }
+    }
+
+    private int versionNrAsofLastForce = 0;
+
+    /**
+     * Reduce the argument based on the state at the program point where the argument is consumed.
+     * For most FixedNodes, that's how their inputs can be reduced. Two exceptions:
+     * <ul>
+     * <li>
+     * the condition of a {@link com.oracle.graal.nodes.GuardingPiNode}, see
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+     * </li>
+     * <li>
+     * the condition of a {@link com.oracle.graal.nodes.FixedGuardNode}, see
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)}
+     * </li>
+     *
+     * </ul>
+     *
+     *
+     * <p>
+     * Part of the reduction work is delegated to baseCase-style reducers, whose contract explicitly
+     * requires them not to deverbosify the argument's inputs --- the decision is made based on the
+     * argument only (thus "base case"). Returning the unmodified argument is how a baseCase-style
+     * tells this method to fall to the default case (for a floating node only: walk into the
+     * argument's inputs, canonicalize followed by
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+     * rememberSubstitution()} if any input changed).
+     * </p>
+     *
+     * <p>
+     * This method must behave as a function (idempotent query method), ie refrain from mutating the
+     * state other than updating caches:
+     * <ul>
+     * <li>{@link EquationalReasoner#added EquationalReasoner#added},</li>
+     * <li>{@link EquationalReasoner#visited EquationalReasoner#visited} and</li>
+     * <li>the cache updated via
+     * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+     * EquationalReasoner#rememberSubstitution(ValueNode, FloatingNode)}.</li>
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * In turn, baseCase-style reducers are even more constrained: besides behaving as functions,
+     * their contract prevents them from updating any caches (basically because they already grab
+     * the answer from caches, if the answer isn't there they should just return their unmodified
+     * argument).
+     * </p>
+     *
+     * <p>
+     * This method returns:
+     * <ul>
+     * <li>
+     * the original argument, in case no reduction possible.</li>
+     * <li>
+     * a {@link com.oracle.graal.nodes.ValueNode ValueNode} different from the argument, in case the
+     * conditions for a reduction were met. The node being returned might be already in the graph.
+     * In any case it's canonicalized already, the caller need not perform that again.</li>
+     * <li>
+     * the unmodified argument, in case no reduction was made. Otherwise, a maximally reduced
+     * {@link com.oracle.graal.nodes.ValueNode}.</li>
+     * </ul>
+     * </p>
+     *
+     * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)
+     *
+     * @see com.oracle.graal.phases.common.cfs.BaseReduction.Tool
+     *
+     */
+    public Node deverbosify(final Node n) {
+
+        // --------------------------------------------------------------------
+        // cases that don't initiate any call-chain that may enter this method
+        // --------------------------------------------------------------------
+
+        if (n == null) {
+            return null;
+        }
+        assert !(n instanceof GuardNode) : "This phase not intended to run during MidTier";
+        if (!(n instanceof ValueNode)) {
+            return n;
+        }
+        ValueNode v = (ValueNode) n;
+        if (v.stamp() instanceof IllegalStamp) {
+            return v;
+        }
+        if (FlowUtil.isLiteralNode(v)) {
+            return v;
+        }
+        ValueNode result = substs.get(v);
+        if (result != null) {
+            // picked cached substitution
+            return result;
+        }
+        if (FlowUtil.hasLegalObjectStamp(v) && state.isNull(v)) {
+            // it's ok to return nullConstant in deverbosify unlike in downcast
+            metricNullInserted.increment();
+            return nullConstant;
+        }
+        if (v instanceof ValueProxy) {
+            return v;
+        }
+        if (!(n instanceof FloatingNode)) {
+            return n;
+        }
+        if ((visited != null && visited.contains(n)) || added.contains(v)) {
+            return v;
+        }
+
+        // --------------------------------------------------------------------
+        // stack overflow prevention via added, visited
+        // --------------------------------------------------------------------
+
+        if (visited == null) {
+            visited = graph.createNodeBitMap();
+        }
+        visited.mark(n);
+
+        /*
+         * Past this point, if we ever want `n` to be deverbosified, it must be looked-up by one of
+         * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)`
+         */
+
+        /*
+         * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not possible
+         * anymore it resorts to calling `downcast()`. Thus it's ok to take the
+         * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be missed.
+         */
+        return deverbosifyFloatingNode((FloatingNode) n);
+    }
+
+    /**
+     * This method:
+     *
+     * <ul>
+     * <li>
+     * Recurses only over floating inputs to attempt reductions, leave anything else as is.</li>
+     * <li>
+     * Performs copy-on-write aka lazy-DAG-copying as described in source comments, in-line.</li>
+     * <li>
+     * Usage: must be called only from {@link #deverbosify(com.oracle.graal.graph.Node)
+     * deverbosify(Node)}.</li>
+     * </ul>
+     */
+    public Node deverbosifyFloatingNode(final FloatingNode n) {
+
+        assert n != null : "Should have been caught in deverbosify()";
+        assert !(n instanceof ValueProxy) : "Should have been caught in deverbosify()";
+        assert !FlowUtil.isLiteralNode(n) : "Should have been caught in deverbosify()";
+
+        if (n instanceof PhiNode) {
+            /*
+             * Each input to a PhiNode should be deverbosified with the state applicable to the path
+             * providing such input, as done in visitAbstractEndNode()
+             */
+            return n;
+        }
+
+        final FloatingNode f = baseCaseFloating(n);
+        if (f != n) {
+            return f;
+        }
+
+        FloatingNode changed = null;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(f)) {
+            /*
+             * Although deverbosify() is invoked below, it's only for floating inputs. That way, the
+             * state can't be used to make invalid conclusions.
+             */
+            Node j = (i instanceof FloatingNode) ? deverbosify(i) : i;
+            if (i != j) {
+                assert j != f;
+                if (changed == null) {
+                    changed = (FloatingNode) f.copyWithInputs();
+                    added.add(changed);
+                    // copyWithInputs() implies graph.unique(changed)
+                    assert changed.isAlive();
+                    assert FlowUtil.lacksUsages(changed);
+                }
+                /*
+                 * Note: we don't trade i for j at each usage of i (doing so would change meaning)
+                 * but only at those usages consumed by `changed`. In turn, `changed` won't replace
+                 * `n` at arbitrary usages, but only where such substitution is valid as per the
+                 * state holding there. In practice, this means the buck stops at the "root"
+                 * FixedNode on whose inputs deverbosify() is invoked for the first time, via
+                 * deverbosifyInputsInPlace().
+                 */
+                FlowUtil.replaceInPlace(changed, i, j);
+            }
+        }
+        if (changed == null) {
+            assert visited.contains(f) || added.contains(f);
+            return f;
+        }
+        FlowUtil.inferStampAndCheck(changed);
+        added.add(changed);
+        ValueNode canon = (ValueNode) changed.canonical(tool);
+        // might be already in `added`, no problem adding it again.
+        added.add(canon);
+        rememberSubstitution(f, canon);
+        return canon;
+    }
+
+    /**
+     * In case of doubt (on whether a reduction actually triggered) it's always ok to invoke "
+     * <code>rememberSubstitution(f, downcast(f))</code>": this method records a map entry only if
+     * pre-image and image differ.
+     *
+     * @return the image of the substitution (ie, the second argument) unmodified.
+     */
+    private <M extends ValueNode> M rememberSubstitution(ValueNode from, M to) {
+        assert from != null && to != null;
+        if (from == to) {
+            return to;
+        }
+        // we don't track literals because they map to themselves
+        if (FlowUtil.isLiteralNode(from)) {
+            assert from == to;
+            return to;
+        }
+        /*
+         * It's ok for different keys (which were not unique in the graph after all) to map to the
+         * same value. However any given key can't map to different values.
+         */
+        ValueNode image = substs.get(from);
+        if (image != null) {
+            assert image == to;
+            return to;
+        }
+        substs.put(from, to);
+        return to;
+    }
+
+    /**
+     * The contract for this baseCase-style method is covered in
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()}
+     *
+     * @return a {@link com.oracle.graal.nodes.calc.FloatingNode} different from the argument, in
+     *         case a reduction was made. The node being returned might be already in the graph. In
+     *         any case it's canonicalized already, the caller need not perform that again. In case
+     *         no reduction was made, this method returns the unmodified argument.
+     */
+    private FloatingNode baseCaseFloating(final FloatingNode f) {
+        if (f instanceof LogicNode) {
+            FloatingNode result = baseCaseLogicNode((LogicNode) f);
+            return rememberSubstitution(f, result);
+        }
+        return f;
+    }
+
+    /**
+     * <p>
+     * Reduce the argument based on the state at the program point for it (ie, based on
+     * "valid facts" only, without relying on any floating-guard-assumption).
+     * </p>
+     *
+     * <p>
+     * The inputs of the argument aren't traversed into, for that
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()} should be used instead.
+     * </p>
+     * <p>
+     * This method must behave as a function (idempotent query method): it should refrain from
+     * changing the state, as well as from updating caches (other than DebugMetric-s).
+     * </p>
+     *
+     * @return a {@link com.oracle.graal.nodes.LogicNode} different from the argument, in case a
+     *         reduction was made. The node being returned might be already in the graph. In any
+     *         case it's canonicalized already, the caller need not perform that again. In case no
+     *         reduction was made, this method returns the unmodified argument.
+     *
+     */
+    public FloatingNode baseCaseLogicNode(LogicNode condition) {
+        assert condition != null;
+        if (condition instanceof LogicConstantNode) {
+            return condition;
+        } else if (state.trueFacts.containsKey(condition)) {
+            metricEquationalReasoning.increment();
+            return trueConstant;
+        } else if (state.falseFacts.containsKey(condition)) {
+            metricEquationalReasoning.increment();
+            return falseConstant;
+        } else {
+            if (condition instanceof InstanceOfNode) {
+                return baseCaseInstanceOfNode((InstanceOfNode) condition);
+            } else if (condition instanceof IsNullNode) {
+                return baseCaseIsNullNode((IsNullNode) condition);
+            } else if (condition instanceof ObjectEqualsNode) {
+                return baseCaseObjectEqualsNode((ObjectEqualsNode) condition);
+            } else if (condition instanceof ShortCircuitOrNode) {
+                return baseCaseShortCircuitOrNode((ShortCircuitOrNode) condition);
+            }
+        }
+        return condition;
+    }
+
+    /**
+     * Actually the same result delivered by this method could be obtained by just letting
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()} handle the argument in the default case for floating nodes
+     * (ie, deverbosify inputs followed by canonicalize). However it's done here for metrics
+     * purposes.
+     *
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+     *         otherwise the unmodified argument.
+     *
+     */
+    private LogicNode baseCaseInstanceOfNode(InstanceOfNode instanceOf) {
+        ValueNode scrutinee = GraphUtil.unproxify(instanceOf.object());
+        if (!FlowUtil.hasLegalObjectStamp(scrutinee)) {
+            return instanceOf;
+        }
+        if (state.isNull(scrutinee)) {
+            metricInstanceOfRemoved.increment();
+            return falseConstant;
+        } else if (state.knownNotToPassInstanceOf(scrutinee, instanceOf.type())) {
+            // scrutinee turns out to be null -> falseConstant right answer
+            // scrutinee not null, but known-not-to-conform -> falseConstant
+            metricInstanceOfRemoved.increment();
+            return falseConstant;
+        } else if (state.isNonNull(scrutinee) && state.knownToConform(scrutinee, instanceOf.type())) {
+            metricInstanceOfRemoved.increment();
+            return trueConstant;
+        }
+        return instanceOf;
+    }
+
+    /**
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was
+     *         performed; otherwise the unmodified argument.
+     *
+     */
+    private FloatingNode baseCaseIsNullNode(IsNullNode isNu) {
+        ValueNode object = isNu.object();
+        if (!FlowUtil.hasLegalObjectStamp(object)) {
+            return isNu;
+        }
+        if (state.isNull(object)) {
+            metricNullCheckRemoved.increment();
+            return trueConstant;
+        } else if (state.isNonNull(object)) {
+            metricNullCheckRemoved.increment();
+            return falseConstant;
+        }
+        return isNu;
+    }
+
+    /**
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+     *         otherwise the unmodified argument.
+     */
+    private LogicNode baseCaseObjectEqualsNode(ObjectEqualsNode equals) {
+        if (!FlowUtil.hasLegalObjectStamp(equals.x()) || !FlowUtil.hasLegalObjectStamp(equals.y())) {
+            return equals;
+        }
+        ValueNode x = GraphUtil.unproxify(equals.x());
+        ValueNode y = GraphUtil.unproxify(equals.y());
+        if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) {
+            metricObjectEqualsRemoved.increment();
+            return falseConstant;
+        } else if (state.isNull(x) && state.isNull(y)) {
+            metricObjectEqualsRemoved.increment();
+            return trueConstant;
+        }
+        return equals;
+    }
+
+    /**
+     * The following is tried:
+     *
+     * <ol>
+     * <li>
+     * A {@link com.oracle.graal.phases.common.cfs.Witness} that is at check-cast level level
+     * doesn't entail {@link com.oracle.graal.nodes.calc.IsNullNode} (on its own) nor
+     * {@link com.oracle.graal.nodes.java.InstanceOfNode} (also on its own) but of course it entails
+     * <code>(IsNull || IsInstanceOf)</code>. Good thing
+     * {@link com.oracle.graal.phases.common.cfs.CastCheckExtractor} detects that very pattern.</li>
+     * <li>
+     * Otherwise return the unmodified argument (later on,
+     * {@link #deverbosifyFloatingNode(com.oracle.graal.nodes.calc.FloatingNode)} will attempt to
+     * simplify the {@link com.oracle.graal.nodes.ShortCircuitOrNode}).</li>
+     * </ol>
+     *
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+     *         otherwise the unmodified argument.
+     */
+    private LogicNode baseCaseShortCircuitOrNode(ShortCircuitOrNode orNode) {
+        CastCheckExtractor cast = CastCheckExtractor.extract(orNode);
+        if (cast != null) {
+            if (state.knownToConform(cast.subject, cast.type)) {
+                return trueConstant;
+            } else if (state.knownNotToPassCheckCast(cast.subject, cast.type)) {
+                return falseConstant;
+            }
+            return orNode;
+        }
+        return orNode;
+    }
+
+    /**
+     * It's always ok to use "<code>downcast(object)</code>" instead of " <code>object</code>"
+     * because this method re-wraps the argument in a {@link com.oracle.graal.nodes.PiNode} only if
+     * the new stamp is strictly more refined than the original.
+     *
+     * <p>
+     * This method does not
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * .
+     * </p>
+     *
+     * @return One of:
+     *         <ul>
+     *         <li>a {@link com.oracle.graal.nodes.PiNode} with more precise stamp than the input if
+     *         the state warrants such downcasting</li>
+     *         <li>a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} for the same
+     *         scrutinee in question</li>
+     *         <li>the unmodified argument otherwise.</li>
+     *         </ul>
+     */
+    ValueNode downcast(final ValueNode object) {
+
+        // -------------------------------------------------
+        // actions based only on the stamp of the input node
+        // -------------------------------------------------
+
+        if (!FlowUtil.hasLegalObjectStamp(object)) {
+            return object;
+        }
+        if (FlowUtil.isLiteralNode(object)) {
+            return object;
+        }
+        if (StampTool.isObjectAlwaysNull(object.stamp())) {
+            return object;
+        }
+
+        // ------------------------------------------
+        // actions based on the stamp and the witness
+        // ------------------------------------------
+
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+
+        PiNode untrivialNull = nonTrivialNull(scrutinee);
+        if (untrivialNull != null) {
+            metricNullInserted.increment();
+            return untrivialNull;
+        }
+
+        Witness w = state.typeInfo(scrutinee);
+        if (w == null) {
+            // no additional hints being tracked for the scrutinee
+            return object;
+        }
+
+        assert !w.clueless();
+
+        ObjectStamp inputStamp = (ObjectStamp) object.stamp();
+        ObjectStamp witnessStamp = w.asStamp();
+        if (inputStamp.equals(witnessStamp) || !FlowUtil.isMorePrecise(witnessStamp, inputStamp)) {
+            // the witness offers no additional precision over current one
+            fixupTypeProfileStamp(object);
+            return object;
+        }
+
+        assert !FlowUtil.isMorePrecise(inputStamp.type(), w.type());
+
+        ValueNode result;
+        if (object instanceof ValueProxy) {
+            result = downcastValueProxy((ValueProxy) object, w);
+        } else {
+            result = downcastedUtil(object, w);
+        }
+
+        assert !BaseReduction.precisionLoss(object, result);
+
+        return result;
+    }
+
+    /**
+     * TODO TypeProfileProxyNode.inferStamp doesn't infer non-null from non-null payload
+     *
+     * <p>
+     * And there's a bunch of asserts in
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} that assert no
+     * type-precision gets lost. Thus the need to fix-up on our own, as done here.
+     * </p>
+     */
+    private static void fixupTypeProfileStamp(ValueNode object) {
+        if (!(object instanceof TypeProfileProxyNode)) {
+            return;
+        }
+        TypeProfileProxyNode profile = (TypeProfileProxyNode) object;
+        ObjectStamp outgoinStamp = (ObjectStamp) profile.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) profile.getObject().stamp();
+        if (payloadStamp.nonNull() && !outgoinStamp.nonNull()) {
+            profile.setStamp(FlowUtil.asNonNullStamp(outgoinStamp));
+        }
+    }
+
+    /**
+     * <p>
+     * Porcelain method.
+     * </p>
+     *
+     * <p>
+     * Utility to create, add to the graph,
+     * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * , and return a {@link com.oracle.graal.nodes.PiNode} that narrows into the given stamp,
+     * anchoring the payload.
+     * </p>
+     *
+     * <p>
+     * The resulting node might not have been in the graph already.
+     * </p>
+     */
+    private PiNode wrapInPiNode(ValueNode payload, GuardingNode anchor, ObjectStamp newStamp, boolean remember) {
+        try (Debug.Scope s = Debug.scope("Downcast", payload)) {
+            assert payload != anchor : payload.graph().toString();
+            metricDowncasting.increment();
+            PiNode result = graph.unique(new PiNode(payload, newStamp, anchor.asNode()));
+            // we've possibly got a new node in the graph --- bookkeeping is in order.
+            added.add(result);
+            if (remember) {
+                rememberSubstitution(payload, result);
+            }
+            Debug.log("Downcasting from %s to %s", payload, result);
+            return result;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    /**
+     *
+     * This method returns:
+     * <ul>
+     * <li><b>null</b>, if the argument is known null due to its stamp. Otherwise,</li>
+     * <li><b>a PiNode</b> wrapping the null constant and an anchor offering evidence as to why the
+     * argument is known null, if such anchor is available. Otherwise,</li>
+     * <li><b>null</b></li>
+     * </ul>
+     * <p>
+     * This method does not
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * .
+     * </p>
+     */
+    public PiNode nonTrivialNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        GuardingNode anchor = state.nonTrivialNullAnchor(object);
+        if (anchor == null) {
+            return null;
+        }
+        if (object instanceof GuardedNode && StampTool.isObjectAlwaysNull(object.stamp())) {
+            return (PiNode) object;
+        }
+        // notice nullConstant is wrapped, not object
+        PiNode result = wrapInPiNode(nullConstant, anchor, (ObjectStamp) StampFactory.alwaysNull(), false);
+        return result;
+    }
+
+    // @formatter:off
+    /**
+     * <p>ValueProxys can be classified along two dimensions,
+     * in addition to the fixed-floating dichotomy.</p>
+     *
+     * <p>
+     *     First, we might be interested in separating those ValueProxys
+     *     that are entitled to change (usually narrow) their stamp from those that aren't.
+     *     In the first category are:
+     *       PiNode, PiArrayNode, GuardingPiNode,
+     *       CheckCastNode, UnsafeCastNode, and
+     *       GuardedValueNode.
+     * </p>
+     *
+     * <p>
+     *     A note on stamp-narrowing ValueProxys:
+     *     our state abstraction tracks only the type refinements induced by CheckCastNode and GuardingPiNode
+     *     (which are fixed nodes, unlike the other stamp-narrowing ValueProxys;
+     *     the reason being that the state abstraction can be updated only at fixed nodes).
+     *     As a result, the witness for a (PiNode, PiArrayNode, UnsafeCastNode, or GuardedValueNode)
+     *     may be less precise than the proxy's stamp. We don't want to lose such precision,
+     *     thus <code>downcast(proxy) == proxy</code> in such cases.
+     * </p>
+     *
+     * <p>
+     *     The second classification focuses on
+     *     the additional information that travels with the proxy
+     *     (in addition to its "payload", ie getOriginalValue(), and any narrowing-stamp).
+     *     Such additional information boils down to:
+     *
+     *   (a) type profile (TypeProfileProxyNode)
+     *   (b) type profile (CheckCastNode)
+     *   (c) anchor (GuardedValueNode)
+     *   (d) anchor (PiNode)
+     *   (e) anchor and array length (PiArrayNode)
+     *   (f) optional anchor (UnsafeCastNode)
+     *   (g) deopt-condition (GuardingPiNode)
+     *   (h) LocationIdentity (MemoryProxyNOde)
+     *   (i) control-flow dependency (FixedValueAnchorNode)
+     *   (j) proxyPoint (ProxyNode -- think loops)
+     *</p>
+     */
+    // @formatter:on
+    private ValueNode downcastValueProxy(ValueProxy proxy, Witness w) {
+        assert FlowUtil.hasLegalObjectStamp((ValueNode) proxy);
+        assert FlowUtil.hasLegalObjectStamp((proxy).getOriginalNode());
+        assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify(proxy.getOriginalNode());
+
+        assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify((proxy).getOriginalNode());
+
+        if (proxy instanceof PiNode) {
+            return downcastPiNodeOrPiArrayNode((PiNode) proxy, w);
+        } else if (proxy instanceof GuardingPiNode) {
+            return downcastGuardingPiNode((GuardingPiNode) proxy, w);
+        } else if (proxy instanceof TypeProfileProxyNode) {
+            return downcastTypeProfileProxyNode((TypeProfileProxyNode) proxy);
+        } else if (proxy instanceof CheckCastNode) {
+            return downcastCheckCastNode((CheckCastNode) proxy, w);
+        } else if (proxy instanceof ProxyNode || proxy instanceof GuardedValueNode) {
+            // TODO scaladacapo return downcastedUtil((ValueNode) proxy, w);
+            return (ValueNode) proxy;
+        }
+
+        assert false : "TODO case not yet handled";
+
+        // TODO complete the missing implementation for the cases not yet handled
+
+        return ((ValueNode) proxy);
+    }
+
+    /**
+     * <p>
+     * Why would we want to downcast a GuardingPiNode? Is it even possible? Like, for example, a
+     * GuardingPiNode originating in the lowering of a CheckCastNode (carried out by
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     * visitCheckCastNode()}).
+     * </p>
+     *
+     * <p>
+     * It's both possible and desirable. Example: <code>
+     *         Number n = (Number) o;
+     *         if (n instanceof Integer) {
+     *            return n.intValue();
+     *         }
+     *     </code>
+     *
+     * The receiver of intValue() is a usage of a previous checkCast, for which the current witness
+     * provides a more refined type (and an anchor). In this case, the advantage of downcasting a
+     * GuardingPiNode is clear: devirtualizing the `intValue()` callsite.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    public ValueNode downcastGuardingPiNode(GuardingPiNode envelope, Witness w) {
+        assert envelope != w.guard().asNode() : "The stamp of " + envelope + " would lead to downcasting with that very same GuardingPiNode as guard.";
+        return downcastedUtil(envelope, w);
+    }
+
+    /**
+     * <p>
+     * This method accepts both {@link com.oracle.graal.nodes.PiNode} and
+     * {@link com.oracle.graal.nodes.PiArrayNode} argument.
+     * </p>
+     *
+     * <p>
+     * In case a witness reveals a strictly more precise type than the
+     * {@link com.oracle.graal.nodes.PiNode}'s stamp, this method wraps the argument in a new
+     * {@link com.oracle.graal.nodes.PiNode} with updated stamp, and returns it.
+     * </p>
+     *
+     * <p>
+     * A {@link com.oracle.graal.nodes.PiArrayNode} argument ends up wrapped in a
+     * {@link com.oracle.graal.nodes.PiNode}. Thus, the
+     * {@link com.oracle.graal.nodes.PiArrayNode#length} information doesn't get lost.
+     * </p>
+     *
+     * <p>
+     * Note: {@link com.oracle.graal.nodes.PiNode}'s semantics allow un-packing its payload as soon
+     * as it type conforms to that of the {@link com.oracle.graal.nodes.PiNode} (that's what
+     * {@link com.oracle.graal.nodes.PiNode#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)
+     * PiNode.canonical()} does). Not clear the benefits of duplicating that logic here.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastPiNodeOrPiArrayNode(PiNode envelope, Witness w) {
+        return downcastedUtil(envelope, w);
+    }
+
+    /**
+     * <p>
+     * In a case the payload of the {@link com.oracle.graal.nodes.TypeProfileProxyNode} can be
+     * downcasted, this method returns a copy-on-write version with the downcasted payload.
+     * </p>
+     *
+     * <p>
+     * Otherwise returns the unmodified argument.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastTypeProfileProxyNode(TypeProfileProxyNode envelope) {
+        ValueNode payload = envelope.getOriginalNode();
+        ValueNode d = downcast(payload);
+        if (payload != d) {
+            TypeProfileProxyNode changed = (TypeProfileProxyNode) envelope.copyWithInputs();
+            added.add(changed);
+            // copyWithInputs() implies graph.unique(changed)
+            FlowUtil.replaceInPlace(changed, payload, d);
+            FlowUtil.inferStampAndCheck(changed);
+            fixupTypeProfileStamp(changed);
+            /*
+             * It's not prudent to (1) obtain the canonical() of the (changed) TypeProfileProxyNode
+             * to (2) replace its usages; because we're potentially walking a DAG (after all,
+             * TypeProfileProxyNode is a floating-node). Those steps, which admittedly are needed,
+             * are better performed upon replacing in-place the inputs of a FixedNode, or during
+             * Canonicalize.
+             */
+            return changed;
+        }
+        fixupTypeProfileStamp(envelope);
+        return envelope;
+    }
+
+    /**
+     * <p>
+     * Re-wrap the checkCast in a type-refining {@link com.oracle.graal.nodes.PiNode PiNode} only if
+     * the downcasted scrutinee does not conform to the checkCast's target-type.
+     * </p>
+     */
+    private ValueNode downcastCheckCastNode(CheckCastNode checkCast, Witness w) {
+
+        final ResolvedJavaType toType = checkCast.type();
+
+        if (checkCast.object() instanceof CheckCastNode) {
+            ValueNode innerMost = checkCast;
+            while (innerMost instanceof CheckCastNode) {
+                innerMost = ((CheckCastNode) innerMost).object();
+            }
+            ValueNode deepest = downcast(innerMost);
+            ResolvedJavaType deepestType = ((ObjectStamp) deepest.stamp()).type();
+            if ((deepestType != null && deepestType.equals(toType)) || FlowUtil.isMorePrecise(deepestType, toType)) {
+                assert !w.knowsBetterThan(deepest);
+                return deepest;
+            }
+        }
+
+        ValueNode subject = downcast(checkCast.object());
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        if (subjectType != null && toType.isAssignableFrom(subjectType)) {
+            assert !w.knowsBetterThan(subject);
+            return subject;
+        }
+
+        return downcastedUtil(checkCast, w);
+    }
+
+    /**
+     * <p>
+     * Porcelain method.
+     * </p>
+     *
+     * <p>
+     * This method wraps the argument in a new {@link com.oracle.graal.nodes.PiNode PiNode} (created
+     * to hold an updated stamp) provided the argument's stamp can be strictly refined, and returns
+     * it.
+     * </p>
+     */
+    private ValueNode downcastedUtil(ValueNode subject, Witness w) {
+
+        ObjectStamp originalStamp = (ObjectStamp) subject.stamp();
+        ObjectStamp outgoingStamp = originalStamp;
+
+        if (w.isNonNull() && !outgoingStamp.nonNull()) {
+            outgoingStamp = FlowUtil.asNonNullStamp(outgoingStamp);
+        }
+        if (FlowUtil.isMorePrecise(w.type(), outgoingStamp.type())) {
+            outgoingStamp = FlowUtil.asRefinedStamp(outgoingStamp, w.type());
+        }
+
+        if (outgoingStamp != originalStamp) {
+            assert FlowUtil.isMorePrecise(outgoingStamp, originalStamp);
+
+            boolean isWitnessGuardAnAliasForScrutinee = false;
+            if (w.guard() instanceof GuardingPiNode || w.guard() instanceof PiNode) {
+                /*
+                 * The guard offered by the witness canonicalizes into its subject (a possibly
+                 * type-refined scrutinee) provided its subject conforms as per stamp.
+                 */
+                if (w.guard().asNode().stamp().equals(outgoingStamp)) {
+                    isWitnessGuardAnAliasForScrutinee = true;
+                }
+            }
+
+            ValueNode result;
+            if (isWitnessGuardAnAliasForScrutinee) {
+                result = w.guard().asNode();
+                assert !w.knowsBetterThan(result);
+                return result; // TODO this works. explain why.
+            } else {
+                result = wrapInPiNode(subject, w.guard(), outgoingStamp, true);
+                assert !w.knowsBetterThan(result);
+                return result;
+            }
+
+        } else {
+            assert !w.knowsBetterThan(subject);
+            return subject;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Evidence.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.nodes.extended.GuardingNode;
+
+public class Evidence {
+
+    public final GuardingNode success;
+    public final boolean failure;
+
+    public Evidence(GuardingNode success, boolean failure) {
+        this.success = success;
+        this.failure = failure;
+        assert repOK();
+    }
+
+    public Evidence(GuardingNode success) {
+        this(success, false);
+    }
+
+    private Evidence(boolean failure) {
+        this(null, failure);
+    }
+
+    public boolean isPositive() {
+        return success != null;
+    }
+
+    public boolean isNegative() {
+        return failure;
+    }
+
+    private boolean repOK() {
+        // either success or failure, ie boolean-XOR
+        return (success != null) != failure;
+    }
+
+    public static Evidence COUNTEREXAMPLE = new Evidence(true);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.FixedGuardNode}.
+ * </p>
+ *
+ * <p>
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ * </p>
+ * 
+ * @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)
+ */
+public abstract class FixedGuardReduction extends CheckCastReduction {
+
+    public FixedGuardReduction(StartNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * Upon visiting a {@link com.oracle.graal.nodes.FixedGuardNode}, based on flow-sensitive
+     * conditions, we need to determine whether:
+     * <ul>
+     * <li>it is redundant (in which case it should be simplified), or</li>
+     * <li>flow-sensitive information can be gained from it.</li>
+     * </ul>
+     * </p>
+     * 
+     * <p>
+     * This method realizes the above by inspecting the
+     * {@link com.oracle.graal.nodes.FixedGuardNode}'s condition:
+     * <ol>
+     * <li>a constant condition signals the node won't be reduced here</li>
+     * <li>the outcome of the condition can be predicted:</li>
+     * <ul>
+     * <li>
+     * "always succeeds", after finding an equivalent (or stronger)
+     * {@link com.oracle.graal.nodes.extended.GuardingNode} in scope. The
+     * {@link com.oracle.graal.nodes.FixedGuardNode} is removed after replacing its usages with the
+     * existing guarding node</li>
+     * <li>
+     * "always fails", which warrants making that explicit by making the condition constant, see
+     * {@link #markFixedGuardNodeAlwaysFails(com.oracle.graal.nodes.FixedGuardNode)}</li>
+     * </ul>
+     * <li>otherwise the condition is tracked flow-sensitively</li>
+     * </ol>
+     * </p>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     */
+    protected final void visitFixedGuardNode(FixedGuardNode f) {
+
+        /*
+         * A FixedGuardNode with LogicConstantNode condition is left untouched.
+         * `FixedGuardNode.simplify()` will eventually remove the FixedGuardNode (in case it
+         * "always succeeds") or kill code ("always fails").
+         */
+
+        if (f.condition() instanceof LogicConstantNode) {
+            if (FlowUtil.alwaysFails(f.isNegated(), f.condition())) {
+                state.impossiblePath();
+                // let FixedGuardNode(false).simplify() prune the dead-code control-path
+                return;
+            }
+            assert FlowUtil.alwaysSucceeds(f.isNegated(), f.condition());
+            return;
+        }
+
+        final boolean isTrue = !f.isNegated();
+        final Evidence evidence = state.outcome(isTrue, f.condition());
+
+        // can't produce evidence, must be information gain
+        if (evidence == null) {
+            state.addFact(isTrue, f.condition(), f);
+            return;
+        }
+
+        if (evidence.isPositive()) {
+            /*
+             * A FixedGuardNode can only be removed provided a replacement anchor is found (so
+             * called "evidence"), ie an anchor that amounts to the same combination of (negated,
+             * condition) as for the FixedGuardNode at hand. Just deverbosifying the condition in
+             * place isn't semantics-preserving.
+             * 
+             * Eliminate the current FixedGuardNode by using another GuardingNode already in scope,
+             * a GuardingNode that guards a condition that is at least as strong as that of the
+             * FixedGuardNode.
+             */
+            removeFixedGuardNode(f, evidence.success);
+            return;
+        }
+
+        assert evidence.isNegative();
+        markFixedGuardNodeAlwaysFails(f);
+
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private void markFixedGuardNodeAlwaysFails(FixedGuardNode f) {
+        metricFixedGuardNodeRemoved.increment();
+        state.impossiblePath();
+        f.setCondition(f.isNegated() ? trueConstant : falseConstant);
+        // `f.condition()` if unused will be removed in finished()
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * <p>
+     * The `replacement` guard must be such that it implies the `old` guard. Moreover, rhe
+     * `replacement` guard must be in scope.
+     * </p>
+     */
+    private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) {
+        assert replacement != null;
+        metricFixedGuardNodeRemoved.increment();
+        old.replaceAtUsages(replacement.asNode());
+        graph.removeFixed(old);
+        // `old.condition()` if unused will be removed in finished()
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.LoadHubNode;
+import com.oracle.graal.nodes.extended.NullCheckNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.IllegalStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.lang.reflect.Modifier;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+
+/**
+ * <p>
+ * In a nutshell, {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} makes a
+ * single pass in dominator-based order over the graph:
+ * <ol>
+ * <li>collecting properties of interest at control-splits; as well as for check-casts,
+ * guarding-pis, null-checks, and fixed-guards. Such flow-sensitive information is tracked via a
+ * dedicated {@link com.oracle.graal.phases.common.cfs.State state instance} for each control-flow
+ * path.</li>
+ * <li>performing rewritings that are safe at specific program-points. This comprises:
+ * <ul>
+ * <li>simplification of side-effects free expressions, via
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+ * <ul>
+ * <li>
+ * at certain {@link com.oracle.graal.nodes.FixedNode}, see
+ * {@link #deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)}</li>
+ * <li>
+ * including for devirtualization, see
+ * {@link #deverbosifyInputsCopyOnWrite(com.oracle.graal.nodes.java.MethodCallTargetNode)}</li>
+ * </ul>
+ * </li>
+ * <li>simplification of control-flow:
+ * <ul>
+ * <li>
+ * by simplifying the input-condition to an {@link com.oracle.graal.nodes.IfNode}</li>
+ * <li>
+ * by eliminating redundant check-casts, guarding-pis, null-checks, and fixed-guards; where
+ * "redundancy" is determined using flow-sensitive information. In these cases, redundancy can be
+ * due to:
+ * <ul>
+ * <li>an equivalent, existing, guarding node is already in scope (thus, use it as replacement and
+ * remove the redundant one)</li>
+ * <li>"always fails" (thus, replace the node in question with <code>FixedGuardNode(false)</code>)</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </li>
+ * </ol>
+ * </p>
+ *
+ * <p>
+ * Metrics for this phase are displayed starting with <code>FSR-</code>prefix, their counters are
+ * hosted in {@link com.oracle.graal.phases.common.cfs.BaseReduction},
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner} and
+ * {@link com.oracle.graal.phases.common.cfs.State}.
+ * </p>
+ *
+ * @see com.oracle.graal.phases.common.cfs.CheckCastReduction
+ * @see com.oracle.graal.phases.common.cfs.GuardingPiReduction
+ * @see com.oracle.graal.phases.common.cfs.FixedGuardReduction
+ *
+ */
+public class FlowSensitiveReduction extends FixedGuardReduction {
+
+    public FlowSensitiveReduction(StartNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * This method performs two kinds of cleanup:
+     * <ol>
+     * <li>
+     * marking as unreachable certain code-paths, as described in
+     * {@link com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt}</li>
+     * <li>
+     * Removing nodes not in use that were added during this phase, as described next.</li>
+     * </ol>
+     * </p>
+     *
+     *
+     * <p>
+     * Methods like
+     * {@link com.oracle.graal.phases.common.cfs.FlowUtil#replaceInPlace(com.oracle.graal.graph.Node, com.oracle.graal.graph.Node, com.oracle.graal.graph.Node)}
+     * may result in old inputs becoming disconnected from the graph. It's not advisable to
+     * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} at
+     * that moment, because one of the inputs that might get killed is one of {@link #nullConstant},
+     * {@link #falseConstant}, or {@link #trueConstant}; which thus could get killed too early,
+     * before another invocation of
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+     * needs them. To recap,
+     * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} also
+     * recursively visits the inputs of the its argument.
+     * </p>
+     *
+     * <p>
+     * This method goes over all of the nodes that deverbosification might have added, which are
+     * either:
+     * <ul>
+     * <li>
+     * {@link com.oracle.graal.nodes.calc.FloatingNode}, added by
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosifyFloatingNode(com.oracle.graal.nodes.calc.FloatingNode)}
+     * ; or</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode}, added by
+     * {@link #deverbosifyInputsCopyOnWrite(com.oracle.graal.nodes.java.MethodCallTargetNode)}</li>
+     * </ul>
+     *
+     * Checking if they aren't in use, proceeding to remove them in that case.
+     * </p>
+     *
+     */
+    @Override
+    public void finished() {
+        if (!postponedDeopts.isEmpty()) {
+            for (PostponedDeopt postponed : postponedDeopts) {
+                postponed.doRewrite(falseConstant);
+            }
+            new DeadCodeEliminationPhase().apply(graph);
+        }
+        for (MethodCallTargetNode mcn : graph.getNodes().filter(MethodCallTargetNode.class)) {
+            if (mcn.isAlive() && FlowUtil.lacksUsages(mcn)) {
+                mcn.safeDelete();
+            }
+        }
+        for (Node n : graph.getNodes().filter(FloatingNode.class)) {
+            GraphUtil.tryKillUnused(n);
+        }
+        assert !isAliveWithoutUsages(trueConstant);
+        assert !isAliveWithoutUsages(falseConstant);
+        assert !isAliveWithoutUsages(nullConstant);
+        super.finished();
+    }
+
+    private static boolean isAliveWithoutUsages(FloatingNode node) {
+        return node.isAlive() && FlowUtil.lacksUsages(node);
+    }
+
+    private void registerControlSplit(Node pred, BeginNode begin) {
+        assert pred != null && begin != null;
+        assert !state.isUnreachable;
+
+        if (begin instanceof LoopExitNode) {
+            state.clear();
+            /*
+             * TODO return or not? (by not returning we agree it's ok to update the state as below)
+             */
+        }
+
+        if (pred instanceof IfNode) {
+            registerIfNode((IfNode) pred, begin);
+        } else if (pred instanceof TypeSwitchNode) {
+            registerTypeSwitchNode((TypeSwitchNode) pred, begin);
+        }
+    }
+
+    private void registerIfNode(IfNode ifNode, BeginNode begin) {
+        final boolean isThenBranch = (begin == ifNode.trueSuccessor());
+
+        if (ifNode.condition() instanceof LogicConstantNode) {
+            final LogicConstantNode constCond = (LogicConstantNode) ifNode.condition();
+            if (isThenBranch != constCond.getValue()) {
+                state.impossiblePath();
+                // let IfNode(constant) prune the dead-code control-path
+            }
+        }
+
+        if (state.isUnreachable) {
+            if (!(ifNode.condition() instanceof LogicConstantNode)) {
+                // if condition constant, no need to add a Deopt node
+                postponedDeopts.addDeoptAfter(begin, UnreachedCode);
+            }
+        } else {
+            state.addFact(isThenBranch, ifNode.condition(), begin);
+        }
+    }
+
+    /**
+     * TODO When tracking integer-stamps, the state at each successor of a TypeSwitchNode should
+     * track an integer-stamp for the LoadHubNode (meet over the constants leading to that
+     * successor). However, are LoadHubNode-s shared frequently enough?
+     */
+    private void registerTypeSwitchNode(TypeSwitchNode typeSwitch, BeginNode begin) {
+        if (typeSwitch.value() instanceof LoadHubNode) {
+            LoadHubNode loadHub = (LoadHubNode) typeSwitch.value();
+            ResolvedJavaType type = null;
+            for (int i = 0; i < typeSwitch.keyCount(); i++) {
+                if (typeSwitch.keySuccessor(i) == begin) {
+                    if (type == null) {
+                        type = typeSwitch.typeAt(i);
+                    } else {
+                        type = FlowUtil.widen(type, typeSwitch.typeAt(i));
+                    }
+                }
+            }
+            if (type == null) {
+                // `begin` denotes the default case of the TypeSwitchNode
+                return;
+            }
+            // it's unwarranted to assume loadHub.object() to be non-null
+            state.trackCC(loadHub.object(), type, begin);
+        }
+    }
+
+    /**
+     *
+     * <p>
+     * Reduce input nodes based on the state at the program point for the argument (ie, based on
+     * "valid facts" only, without relying on any floating-guard-assumption).
+     * </p>
+     *
+     * <p>
+     * For each (direct or indirect) child, a copy-on-write version is made in case any of its
+     * children changed, with the copy accommodating the updated children. If the parent was shared,
+     * copy-on-write prevents the updates from becoming visible to anyone but the invoker of this
+     * method.
+     * </p>
+     *
+     * <p>
+     * <b> Please note the parent node is mutated upon any descendant changing. No copy-on-write is
+     * performed for the parent node itself. </b>
+     * </p>
+     *
+     * <p>
+     * In more detail, for each direct {@link com.oracle.graal.nodes.ValueNode} input of the node at
+     * hand,
+     *
+     * <ol>
+     * <li>
+     * Obtain a lazy-copied version (via spanning tree) of the DAG rooted at the input-usage in
+     * question. Lazy-copying is done by walking a spanning tree of the original DAG, stopping at
+     * non-FloatingNodes but transitively walking FloatingNodes and their inputs. Upon arriving at a
+     * (floating) node N, the state's facts are checked to determine whether a constant C can be
+     * used instead in the resulting lazy-copied DAG. A NodeBitMap is used to realize the spanning
+     * tree.</li>
+     *
+     * <li>
+     * Provided one or more N-to-C node replacements took place, the resulting lazy-copied DAG has a
+     * parent different from the original (ie different object identity) which indicates the
+     * (copied, updated) DAG should replace the original via replaceFirstInput(), and inferStamp()
+     * should be invoked to reflect the updated inputs.</li>
+     *
+     * </ol>
+     * </p>
+     *
+     * @return whether any reduction was performed on the inputs of the arguments.
+     */
+    public boolean deverbosifyInputsInPlace(ValueNode parent) {
+        boolean changed = false;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
+            assert !(i instanceof GuardNode) : "This phase not intended to run during MidTier";
+            ValueNode j = (ValueNode) reasoner.deverbosify(i);
+            if (i != j) {
+                changed = true;
+                FlowUtil.replaceInPlace(parent, i, j);
+            }
+        }
+        if (changed) {
+            FlowUtil.inferStampAndCheck(parent);
+        }
+        return changed;
+    }
+
+    /**
+     * Similar to {@link #deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)}, except that
+     * not the parent but a fresh clone is updated upon any of its children changing.
+     *
+     * @return the original parent if no updated took place, a copy-on-write version of it
+     *         otherwise.
+     *
+     */
+    private MethodCallTargetNode deverbosifyInputsCopyOnWrite(MethodCallTargetNode parent) {
+        final MethodCallTargetNode.InvokeKind ik = parent.invokeKind();
+        final boolean shouldTryDevirt = (ik == MethodCallTargetNode.InvokeKind.Interface || ik == MethodCallTargetNode.InvokeKind.Virtual);
+        boolean shouldDowncastReceiver = shouldTryDevirt;
+        MethodCallTargetNode changed = null;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
+            ValueNode j = (ValueNode) reasoner.deverbosify(i);
+            if (shouldDowncastReceiver) {
+                shouldDowncastReceiver = false;
+                j = reasoner.downcast(j);
+            }
+            if (i != j) {
+                assert j != parent;
+                if (changed == null) {
+                    changed = (MethodCallTargetNode) parent.copyWithInputs();
+                    reasoner.added.add(changed);
+                    // copyWithInputs() implies graph.unique(changed)
+                    assert changed.isAlive();
+                    assert FlowUtil.lacksUsages(changed);
+                }
+                FlowUtil.replaceInPlace(changed, i, j);
+            }
+        }
+        if (changed == null) {
+            return parent;
+        }
+        FlowUtil.inferStampAndCheck(changed);
+        /*
+         * No need to rememberSubstitution() because not called from deverbosify(). In detail, it's
+         * only deverbosify() that skips visited nodes (thus we'd better have recorded any
+         * substitutions we want for them). Not this case.
+         */
+        return changed;
+    }
+
+    /**
+     * Precondition: This method assumes that either:
+     *
+     * <ul>
+     * <li>the state has already stabilized (ie no more pending iterations in the "iterative"
+     * dataflow algorithm); or</li>
+     * <li>any rewritings made based on the state in its current form are conservative enough to be
+     * safe.</li>
+     * </ul>
+     *
+     * <p>
+     * The overarching goal is to perform just enough rewriting to trigger other phases (
+     * {@link com.oracle.graal.graph.spi.SimplifierTool SimplifierTool},
+     * {@link com.oracle.graal.phases.common.DeadCodeEliminationPhase DeadCodeEliminationPhase},
+     * etc) to perform the bulk of rewriting, thus lowering the maintenance burden.
+     * </p>
+     *
+     */
+    @Override
+    protected void node(FixedNode node) {
+
+        assert node.isAlive();
+
+        /*-------------------------------------------------------------------------------------
+         * Step 1: Unreachable paths are still visited (PostOrderNodeIterator requires all ends
+         * of a merge to have been visited), but time is saved by neither updating the state nor
+         * rewriting anything while on an an unreachable path.
+         *-------------------------------------------------------------------------------------
+         */
+        if (state.isUnreachable) {
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 2: For an AbstractBeginNode, determine whether this path is reachable, register
+         * any associated guards.
+         *-------------------------------------------------------------------------------------
+         */
+        if (node instanceof BeginNode) {
+            BeginNode begin = (BeginNode) node;
+            Node pred = node.predecessor();
+
+            if (pred != null) {
+                registerControlSplit(pred, begin);
+            }
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 3: Check whether EquationalReasoner caches should be cleared upon state updates.
+         *-------------------------------------------------------------------------------------
+         */
+        reasoner.updateState(state);
+
+        /*-------------------------------------------------------------------------------------
+         * Step 4: Whatever special-case handling makes sense for the FixedNode at hand before
+         * its inputs are reduced.
+         *-------------------------------------------------------------------------------------
+         */
+
+        if (node instanceof AbstractEndNode) {
+            visitAbstractEndNode((AbstractEndNode) node);
+            return;
+        } else if (node instanceof Invoke) {
+            visitInvoke((Invoke) node);
+            return;
+        } else if (node instanceof CheckCastNode) {
+            // it's important not to call deverbosification for visitCheckCastNode()
+            visitCheckCastNode((CheckCastNode) node);
+            return;
+        } else if (node instanceof GuardingPiNode) {
+            visitGuardingPiNode((GuardingPiNode) node);
+            return;
+        } else if (node instanceof NullCheckNode) {
+            visitNullCheckNode((NullCheckNode) node);
+            return;
+        } else if (node instanceof FixedGuardNode) {
+            visitFixedGuardNode((FixedGuardNode) node);
+            return;
+        } else if (node instanceof ConditionAnchorNode) {
+            // ConditionAnchorNode shouldn't occur during HighTier
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 5: After special-case handling, we do our best for those FixedNode-s
+         * where the effort to reduce their inputs might pay off.
+         *
+         * Why is this useful? For example, by the time the BeginNode for an If-branch
+         * is visited (in general a ControlSplitNode), the If-condition will have gone already
+         * through simplification (and thus potentially have been reduced to a
+         * LogicConstantNode).
+         *-------------------------------------------------------------------------------------
+         */
+        boolean paysOffToReduce = false;
+        if (node instanceof ControlSplitNode) {
+            // desire to simplify control flow
+            paysOffToReduce = true;
+        } else if (node instanceof ReturnNode) {
+            paysOffToReduce = true;
+        } else if (node instanceof AccessFieldNode || node instanceof AccessArrayNode) {
+            // desire to remove null-checks
+            paysOffToReduce = true;
+        }
+
+        // TODO comb remaining FixedWithNextNode subclasses, pick those with chances of paying-off
+
+        // TODO UnsafeLoadNode takes a condition
+
+        if (paysOffToReduce) {
+            deverbosifyInputsInPlace(node);
+        }
+
+        /*---------------------------------------------------------------------------------------
+         * Step 6: Any additional special-case handling, this time after having inputs reduced.
+         * For example, leverage anchors provided by the FixedNode, to add facts to the factbase.
+         *---------------------------------------------------------------------------------------
+         */
+
+        // TODO some nodes are GuardingNodes (eg, FixedAccessNode) we could use them to track state
+        // TODO other nodes are guarded (eg JavaReadNode), thus *their* guards could be replaced.
+
+    }
+
+    /**
+     * In case the scrutinee:
+     *
+     * <ul>
+     * <li>is known to be null, an unconditional deopt is added.</li>
+     * <li>is known to be non-null, the NullCheckNode is removed.</li>
+     * <li>otherwise, the NullCheckNode is lowered to a FixedGuardNode which then allows using it as
+     * anchor for state-tracking.</li>
+     * </ul>
+     *
+     * <p>
+     * Precondition: the input (ie, object) hasn't been deverbosified yet.
+     * </p>
+     */
+    private void visitNullCheckNode(NullCheckNode ncn) {
+        ValueNode object = ncn.getObject();
+        if (state.isNull(object)) {
+            postponedDeopts.addDeoptBefore(ncn, NullCheckException);
+            state.impossiblePath();
+            return;
+        }
+        if (state.isNonNull(object)) {
+            /*
+             * Redundant NullCheckNode. Unlike GuardingPiNode or FixedGuardNode, NullCheckNode-s
+             * aren't used as GuardingNode-s, thus in this case can be removed without further ado.
+             */
+            assert FlowUtil.lacksUsages(ncn);
+            graph.removeFixed(ncn);
+            return;
+        }
+        /*
+         * Lower the NullCheckNode to a FixedGuardNode which then allows using it as anchor for
+         * state-tracking. TODO the assumption here is that the code emitted for the resulting
+         * FixedGuardNode is as efficient as for NullCheckNode.
+         */
+        IsNullNode isNN = graph.unique(new IsNullNode(object));
+        reasoner.added.add(isNN);
+        FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true));
+        graph.replaceFixedWithFixed(ncn, nullCheck);
+
+        state.trackNN(object, nullCheck);
+    }
+
+    /**
+     * The {@link com.oracle.graal.nodes.AbstractEndNode} at the end of the current code path
+     * contributes values to {@link com.oracle.graal.nodes.PhiNode}s. Now is a good time to
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify} those values.
+     *
+     * <p>
+     * Precondition: inputs haven't been deverbosified yet.
+     * </p>
+     */
+    private void visitAbstractEndNode(AbstractEndNode endNode) {
+        MergeNode merge = endNode.merge();
+        for (PhiNode phi : merge.phis()) {
+            if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+                assert phi.verify();
+                int index = merge.phiPredecessorIndex(endNode);
+                ValueNode original = phi.valueAt(index);
+                ValueNode reduced = (ValueNode) reasoner.deverbosify(original);
+                if (reduced != original) {
+                    phi.setValueAt(index, reduced);
+                    // `original` if unused will be removed in finished()
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * For one or more `invoke` arguments, flow-sensitive information may suggest their narrowing or
+     * simplification. In those cases, a new
+     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode MethodCallTargetNode} is prepared
+     * just for this callsite, consuming reduced arguments.
+     * </p>
+     *
+     * <p>
+     * Specializing the {@link com.oracle.graal.nodes.java.MethodCallTargetNode
+     * MethodCallTargetNode} as described above may enable two optimizations:
+     * <ul>
+     * <li>
+     * devirtualization of an
+     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind#Interface} or
+     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind#Virtual} callsite
+     * (devirtualization made possible after narrowing the type of the receiver)</li>
+     * <li>
+     * (future work) actual-argument-aware inlining, ie, to specialize callees on the types of
+     * arguments other than the receiver (examples: multi-methods, the inlining problem, lambdas as
+     * arguments).</li>
+     *
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * Precondition: inputs haven't been deverbosified yet.
+     * </p>
+     */
+    private void visitInvoke(Invoke invoke) {
+        if (invoke.asNode().stamp() instanceof IllegalStamp) {
+            return; // just to be safe
+        }
+        boolean isMethodCallTarget = invoke.callTarget() instanceof MethodCallTargetNode;
+        if (!isMethodCallTarget) {
+            return;
+        }
+        FlowUtil.replaceInPlace(invoke.asNode(), invoke.callTarget(), deverbosifyInputsCopyOnWrite((MethodCallTargetNode) invoke.callTarget()));
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        if (callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Virtual) {
+            return;
+        }
+        ValueNode receiver = callTarget.receiver();
+        if (receiver == null) {
+            return;
+        }
+        if (!FlowUtil.hasLegalObjectStamp(receiver)) {
+            return;
+        }
+        Witness w = state.typeInfo(receiver);
+        ResolvedJavaType type;
+        ResolvedJavaType stampType = StampTool.typeOrNull(receiver);
+        if (w == null || w.cluelessAboutType()) {
+            // can't improve on stamp but wil try to devirtualize anyway
+            type = stampType;
+        } else {
+            type = FlowUtil.tighten(w.type(), stampType);
+        }
+        if (type == null) {
+            return;
+        }
+        ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod(), invoke.getContextType());
+        if (method == null) {
+            return;
+        }
+        if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
+            metricMethodResolved.increment();
+            callTarget.setInvokeKind(MethodCallTargetNode.InvokeKind.Special);
+            callTarget.setTargetMethod(method);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+public class FlowSensitiveReductionPhase extends BasePhase<PhaseContext> {
+
+    private final MetaAccessProvider metaAccess;
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public FlowSensitiveReductionPhase(MetaAccessProvider metaAccess) {
+        this.metaAccess = metaAccess;
+    }
+
+    @Override
+    protected final void run(StructuredGraph graph, PhaseContext context) {
+        try (Debug.Scope s = Debug.scope("FlowSensitiveReduction")) {
+            if (graph.isOSR()) {
+                Debug.log("Skipping OSR method %s", graph.method() == null ? "" : MetaUtil.format("%H.%n", graph.method()));
+                return;
+            }
+            Debug.dump(graph, "FlowSensitiveReduction initial");
+            new FlowSensitiveReduction(graph.start(), new State(), context).apply();
+            Debug.dump(graph, "FlowSensitiveReduction done");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.graph.InputType;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class FlowUtil {
+
+    private FlowUtil() {
+        // no instances of this class
+    }
+
+    public static boolean lacksUsages(Node n) {
+        return n.recordsUsages() && n.usages().isEmpty();
+    }
+
+    public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null || b == null) {
+            return null;
+        } else if (a.equals(b)) {
+            return a;
+        } else {
+            return a.findLeastCommonAncestor(b);
+        }
+    }
+
+    /**
+     * @return whether the first argument is strictly more precise than the second.
+     */
+    public static boolean isMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null) {
+            return false;
+        }
+        if (b == null) {
+            return true;
+        }
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (a.equals(b)) {
+            return false;
+        }
+        if (b.isInterface()) {
+            return b.isAssignableFrom(a);
+        }
+        if (a.isInterface()) {
+            return b.isInterface() && b.isAssignableFrom(a);
+        }
+        return b.isAssignableFrom(a);
+    }
+
+    public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null) {
+            assert b == null || !b.isPrimitive();
+            return b;
+        }
+        if (b == null) {
+            assert !a.isPrimitive();
+            return a;
+        }
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (a.equals(b)) {
+            return a;
+        }
+        if (isMorePrecise(a, b)) {
+            return a;
+        } else if (isMorePrecise(b, a)) {
+            return b;
+        } else {
+            /*
+             * Not comparable, two cases:
+             * 
+             * Example 1: 'a' standing for j.l.Number and 'b' for j.l.String We return null for lack
+             * of a value representing NullType, the right answer. Same goes when both arguments are
+             * non-comparable interfaces.
+             * 
+             * Example 2: 'a' standing for sun/nio/ch/DirectBuffer (an interface) and b for
+             * java/nio/Buffer (an abstract class). The class always takes precedence.
+             */
+            if (a.isInterface()) {
+                return b.isInterface() ? null : b;
+            }
+            if (b.isInterface()) {
+                return a.isInterface() ? null : a;
+            }
+            return null; // a and b aren't comparable, can't tighten() them
+        }
+    }
+
+    /**
+     *
+     * There are "illegal" stamps that are not of type IllegalStamp.
+     *
+     * For example, there may be an IntegerStamp with upperBound < lowerBound that returns
+     * !isLegal() but we still know it's an integer and thus not of type IllegalStamp.
+     *
+     * An IllegalStamp should never happen. In contrast, !isLegal() values could happen due to dead
+     * code not yet removed, or upon some non-sideeffecting instructions floating out of a dead
+     * branch.
+     */
+    public static boolean isLegalObjectStamp(Stamp s) {
+        return isObjectStamp(s) && s.isLegal();
+    }
+
+    public static boolean hasLegalObjectStamp(ValueNode v) {
+        return isLegalObjectStamp(v.stamp());
+    }
+
+    public static boolean isObjectStamp(Stamp stamp) {
+        return stamp instanceof ObjectStamp;
+    }
+
+    public static void inferStampAndCheck(ValueNode n) {
+        n.inferStamp();
+        if (n.stamp() instanceof ObjectStamp) {
+            ObjectStamp objectStamp = (ObjectStamp) n.stamp();
+            assert !objectStamp.isExactType() || objectStamp.type() != null;
+        }
+    }
+
+    /**
+     * Compares the arguments along three dimensions (nullness, exactness, and type). For the first
+     * argument to be more precise than the second, it may not score lower in any dimension and must
+     * score higher in at least one dimension.
+     *
+     * When comparing types s and t, sameness counts as 0; while being more precise is awarded with
+     * a score of 1. In all other cases (non-comparable, or supertype) the score is -1.
+     *
+     * @return whether the first argument is strictly more precise than the second.
+     */
+    public static boolean isMorePrecise(ObjectStamp a, ObjectStamp b) {
+        int d0 = MINUS(a.alwaysNull(), b.alwaysNull());
+        if (d0 == -1) {
+            return false;
+        }
+        int d1 = MINUS(a.nonNull(), b.nonNull());
+        if (d1 == -1) {
+            return false;
+        }
+        int d2 = MINUS(a.isExactType(), b.isExactType());
+        if (d2 == -1) {
+            return false;
+        }
+        int d3;
+        ResolvedJavaType ta = a.type();
+        ResolvedJavaType tb = b.type();
+        if (ta == null) {
+            d3 = (tb == null) ? 0 : -1;
+        } else if (tb == null) {
+            d3 = 1;
+        } else if (isMorePrecise(ta, tb)) {
+            d3 = 1;
+        } else if (ta.equals(tb)) {
+            d3 = 0;
+        } else {
+            d3 = -1;
+        }
+        if (d3 == -1) {
+            return false;
+        }
+        int maxScore = Math.max(Math.max(d0, d1), Math.max(d2, d3));
+        return maxScore > 0;
+    }
+
+    private static int MINUS(boolean a, boolean b) {
+        int aa = a ? 1 : 0;
+        int bb = b ? 1 : 0;
+        return aa - bb;
+    }
+
+    public static LogicConstantNode asLogicConstantNode(LogicNode cond) {
+        return (cond instanceof LogicConstantNode) ? (LogicConstantNode) cond : null;
+    }
+
+    public static boolean isLiteralNode(ValueNode f) {
+        return f instanceof ConstantNode || f instanceof LogicConstantNode;
+    }
+
+    public static boolean isConstantTrue(LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && c.getValue();
+    }
+
+    public static boolean isConstantFalse(LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && !c.getValue();
+    }
+
+    public static boolean alwaysFails(boolean isNegated, LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && (c.getValue() == isNegated);
+    }
+
+    public static boolean alwaysSucceeds(boolean isNegated, LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && (c.getValue() != isNegated);
+    }
+
+    /**
+     * Returns (preserving order) the ValueNodes without duplicates found among the argument's
+     * direct inputs.
+     */
+    @SuppressWarnings("unchecked")
+    public static List<ValueNode> distinctValueAndConditionInputs(Node n) {
+        ArrayList<ValueNode> result = null;
+        NodeClass.NodeClassIterator iter = n.inputs().iterator();
+        while (iter.hasNext()) {
+            NodeClass.Position pos = iter.nextPosition();
+            InputType inputType = pos.getInputType(n);
+            boolean isReducibleInput = (inputType == InputType.Value || inputType == InputType.Condition);
+            if (isReducibleInput) {
+                ValueNode i = (ValueNode) pos.get(n);
+                if (!isLiteralNode(i)) {
+                    if (result == null) {
+                        result = new ArrayList<>();
+                    }
+                    if (!result.contains(i)) {
+                        result.add(i);
+                    }
+                }
+            }
+        }
+        return result == null ? Collections.EMPTY_LIST : result;
+    }
+
+    public static ObjectStamp asNonNullStamp(ObjectStamp stamp) {
+        ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.objectNonNull());
+        assert result.isLegal();
+        return result;
+    }
+
+    public static ObjectStamp asRefinedStamp(ObjectStamp stamp, ResolvedJavaType joinType) {
+        assert !joinType.isInterface();
+        ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.declared(joinType));
+        assert result.isLegal();
+        return result;
+    }
+
+    /**
+     * Start situation: the parent node has <code>oldInput</code> among its (direct) inputs. After
+     * this method has run, all such occurrences have been replaced with <code>newInput</code>. In
+     * case that makes <code>oldInput</code> disconnected, it is removed from the graph.
+     */
+    public static void replaceInPlace(Node parent, Node oldInput, Node newInput) {
+        assert parent != null;
+        assert parent.inputs().contains(oldInput);
+        if (oldInput == newInput) {
+            return;
+        }
+        assert oldInput != null && newInput != null;
+        assert !isLiteralNode((ValueNode) oldInput);
+        do {
+            parent.replaceFirstInput(oldInput, newInput);
+        } while (parent.inputs().contains(oldInput));
+        // `oldInput` if unused wil be removed in finished()
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.GuardingPiNode}.
+ * </p>
+ *
+ * <p>
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ * </p>
+ *
+ * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+ */
+public abstract class GuardingPiReduction extends BaseReduction {
+
+    public GuardingPiReduction(StartNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * By the time a {@link com.oracle.graal.nodes.GuardingPiNode GuardingPiNode} is visited, the
+     * available type refinements may allow reductions similar to those performed for
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     * CheckCastNode}.
+     * </p>
+     * 
+     * <ol>
+     * <li>
+     * If the condition needs no reduction (ie, it's already a
+     * {@link com.oracle.graal.nodes.LogicConstantNode LogicConstantNode}), this method basically
+     * gives up (thus letting other phases take care of it).</li>
+     * <li>
+     * Otherwise, an attempt is made to find a {@link com.oracle.graal.nodes.extended.GuardingNode}
+     * that implies the combination of (negated, condition) of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode} being visited. Details in
+     * {@link #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}. If found, the node
+     * can be removed.</li>
+     * <li>
+     * Otherwise, the node is lowered to a {@link com.oracle.graal.nodes.FixedGuardNode} and its
+     * usages replaced with {@link com.oracle.graal.nodes.PiNode}. Details in
+     * {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}.</li>
+     * </ol>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     * 
+     */
+    protected final void visitGuardingPiNode(GuardingPiNode envelope) {
+
+        if (!FlowUtil.hasLegalObjectStamp(envelope)) {
+            // this situation exercised by com.oracle.graal.jtt.optimize.NCE_FlowSensitive02
+            return;
+        }
+        if (!FlowUtil.hasLegalObjectStamp(envelope.object())) {
+            return;
+        }
+
+        /*
+         * (1 of 3) Cover the case of GuardingPiNode(LogicConstantNode, ...)
+         */
+
+        if (envelope.condition() instanceof LogicConstantNode) {
+            if (FlowUtil.alwaysFails(envelope.isNegated(), envelope.condition())) {
+                state.impossiblePath();
+                // let GuardingPiNode(false).canonical() prune the dead-code control-path
+                return;
+            }
+            // if not always-fails and condition-constant, then it always-succeeds!
+            assert FlowUtil.alwaysSucceeds(envelope.isNegated(), envelope.condition());
+            // let GuardingPiNode(true).canonical() replaceAtUsages
+            return;
+        }
+
+        /*
+         * The trick used in visitFixedGuardNode to look up an equivalent GuardingNode for the
+         * combination of (negated, condition) at hand doesn't work for GuardingPiNode, because the
+         * condition showing up here (a ShortCircuitOrNode that can be detected by
+         * CastCheckExtractor) doesn't appear as key in trueFacts, falseFacts. Good thing we have
+         * CastCheckExtractor!
+         */
+
+        /*
+         * (2 of 3) Cover the case of the condition known-to-be-false or known-to-be-true, but not
+         * LogicConstantNode.
+         * 
+         * If deverbosify(condition) == falseConstant, it would be safe to set:
+         * `envelope.setCondition(falseConstant)` (only the API won't allow).
+         * 
+         * On the other hand, it's totally unsafe to do something like that for trueConstant. What
+         * we can do about that case is the province of `tryRemoveGuardingPiNode(envelope)`
+         */
+
+        if (tryRemoveGuardingPiNode(envelope)) {
+            return;
+        }
+
+        /*
+         * Experience has shown that an attempt to eliminate the current GuardingPiNode by using a
+         * GuardingNode already in scope and with equivalent condition (grabbed from `trueFacts`
+         * resp. `falseFacts`) proves futile. Therefore we're not even attempting that here.
+         */
+
+        /*
+         * (3 of 3) Neither always-succeeds nor always-fails, ie we don't known. Converting to
+         * FixedGuardNode allows tracking the condition via a GuardingNode, thus potentially
+         * triggering simplifications down the road.
+         */
+        FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(envelope.condition(), envelope.getReason(), envelope.getAction(), envelope.isNegated()));
+        graph.addBeforeFixed(envelope, fixedGuard);
+
+        /*
+         * 
+         * TODO This lowering is currently performed unconditionally: it might occur no
+         * flow-sensitive reduction is enabled down the road
+         */
+
+        if (!FlowUtil.lacksUsages(envelope)) {
+            // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+            PiNode replacement = graph.unique(new PiNode(envelope.object(), envelope.stamp(), fixedGuard));
+            reasoner.added.add(replacement);
+            // before removing the GuardingPiNode replace its usages
+            envelope.replaceAtUsages(replacement);
+        }
+
+        graph.removeFixed(envelope);
+
+        state.addFact(!fixedGuard.isNegated(), fixedGuard.condition(), fixedGuard);
+
+    }
+
+    /**
+     * <p>
+     * Based on flow-sensitive knowledge, two pre-requisites have to be fulfilled in order to remove
+     * a {@link com.oracle.graal.nodes.GuardingPiNode}:
+     * 
+     * <ul>
+     * <li>the condition must refer only to the payload of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode}</li>
+     * <li>the condition must check properties about which the state tracks not only a true/false
+     * answer, but also an anchor witnessing that fact</li>
+     * <li>the condition may not check anything else beyond what's stated in the items above.</li>
+     * </ul>
+     * </p>
+     * 
+     * <p>
+     * Provided a condition as above can be reduced to a constant (and an anchor obtained in the
+     * process), this method replaces all usages of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode} (necessarily of
+     * {@link com.oracle.graal.graph.InputType#Value}) with a {@link com.oracle.graal.nodes.PiNode}
+     * that wraps the payload and the anchor in question.
+     * </p>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     * 
+     * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     * 
+     */
+    private boolean tryRemoveGuardingPiNode(GuardingPiNode envelope) {
+
+        LogicNode cond = envelope.condition();
+        ValueNode payload = envelope.object();
+
+        ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+        if (isNullCheckOn(cond, payload)) {
+            if (envelope.isNegated()) {
+                /*
+                 * GuardingPiNode succeeds if payload non-null
+                 */
+                if (!outgoingStamp.equals(FlowUtil.asNonNullStamp(payloadStamp))) {
+                    warnAboutOutOfTheBlueGuardingPiNode(envelope);
+                }
+                return tryRemoveGuardingPiNodeNonNullCond(envelope);
+            } else {
+                /*
+                 * GuardingPiNode succeeds if payload null
+                 */
+                ValueNode replacement = StampTool.isObjectAlwaysNull(payload) ? payload : reasoner.nonTrivialNull(payload);
+                if (replacement != null) {
+                    // replacement == null means !isKnownNull(payload)
+                    removeGuardingPiNode(envelope, replacement);
+                    return true;
+                }
+                return false;
+            }
+        } else if (CastCheckExtractor.isInstanceOfCheckOn(cond, payload)) {
+            if (envelope.isNegated()) {
+                return false;
+            }
+            /*
+             * GuardingPiNode succeeds if payload instanceof <something>
+             */
+            InstanceOfNode io = (InstanceOfNode) cond;
+            assert io.type() != null;
+            Witness w = state.typeInfo(payload);
+            if (w != null && w.isNonNull() && isEqualOrMorePrecise(w.type(), io.type())) {
+                ValueNode d = reasoner.downcast(payload);
+                removeGuardingPiNode(envelope, d);
+                return true;
+            }
+            return false;
+        } else if (cond instanceof ShortCircuitOrNode) {
+            if (envelope.isNegated()) {
+                return false;
+            }
+            CastCheckExtractor cce = CastCheckExtractor.extract(cond);
+            if (cce == null || cce.subject != payload) {
+                return false;
+            }
+            /*
+             * GuardingPiNode succeeds if payload check-casts toType
+             */
+            return tryRemoveGuardingPiNodeCheckCastCond(envelope, cce.type);
+        }
+
+        return false;
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * This method handles the case where the GuardingPiNode succeeds if payload known to be
+     * non-null.
+     * 
+     * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     */
+    private boolean tryRemoveGuardingPiNodeNonNullCond(GuardingPiNode envelope) {
+
+        ValueNode payload = envelope.object();
+
+        if (state.isNull(payload)) {
+            // the GuardingPiNode fails always
+            postponedDeopts.addDeoptBefore(envelope, envelope.getReason());
+            state.impossiblePath();
+            return true;
+        }
+
+        if (StampTool.isObjectNonNull(payload)) {
+            // payload needs no downcasting, it satisfies as-is the GuardingPiNode's condition.
+            if (precisionLoss(envelope, payload)) {
+                /*
+                 * TODO The GuardingPiNode has an outgoing stamp whose narrowing goes beyond what
+                 * the condition checks. That's suspicious.
+                 */
+                PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp()));
+                reasoner.added.add(replacement);
+                removeGuardingPiNode(envelope, replacement);
+                return true;
+            } else {
+                removeGuardingPiNode(envelope, payload);
+                return true;
+            }
+        }
+        // if a non-null witness available, the GuardingPiNode can be removed
+
+        Witness w = state.typeInfo(payload);
+        GuardingNode nonNullAnchor = (w != null && w.isNonNull()) ? w.guard() : null;
+        if (nonNullAnchor != null) {
+            PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp(), nonNullAnchor.asNode()));
+            reasoner.added.add(replacement);
+            removeGuardingPiNode(envelope, replacement);
+            return true;
+        }
+
+        /*
+         * TODO What about, nodes that always denote non-null values? (Even though their stamp
+         * forgot to make that clear) Candidates: ObjectGetClassNode, Parameter(0) on instance
+         */
+
+        return false;
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * This method handles the case where the GuardingPiNode succeeds if payload null or its actual
+     * type equal or subtype of `toType`
+     * 
+     * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     * 
+     */
+    private boolean tryRemoveGuardingPiNodeCheckCastCond(GuardingPiNode envelope, ResolvedJavaType toType) {
+        assert toType != null;
+        ValueNode payload = envelope.object();
+
+        ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+        if (!outgoingStamp.equals(FlowUtil.asRefinedStamp(payloadStamp, toType))) {
+            warnAboutOutOfTheBlueGuardingPiNode(envelope);
+        }
+
+        ValueNode d = reasoner.downcast(payload);
+        if (d == null) {
+            return false;
+        }
+
+        if (StampTool.isObjectAlwaysNull(d)) {
+            removeGuardingPiNode(envelope, d);
+            return true;
+        }
+        ObjectStamp dStamp = (ObjectStamp) d.stamp();
+        if (isEqualOrMorePrecise(dStamp.type(), toType)) {
+            removeGuardingPiNode(envelope, d);
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * TODO There should be an assert in GuardingPiNode to detect that as soon as it happens
+     * (constructor, setStamp).
+     */
+    private static void warnAboutOutOfTheBlueGuardingPiNode(GuardingPiNode envelope) {
+        Debug.log(String.format("GuardingPiNode has an outgoing stamp whose narrowing goes beyond what its condition checks: %s", envelope));
+    }
+
+    private static boolean isNullCheckOn(LogicNode cond, ValueNode subject) {
+        if (!(cond instanceof IsNullNode)) {
+            return false;
+        }
+        IsNullNode isNull = (IsNullNode) cond;
+        return isNull.object() == subject;
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private void removeGuardingPiNode(GuardingPiNode envelope, ValueNode replacement) {
+        assert !precisionLoss(envelope, replacement);
+        metricGuardingPiNodeRemoved.increment();
+        envelope.replaceAtUsages(replacement);
+        assert FlowUtil.lacksUsages(envelope);
+        graph.removeFixed(envelope);
+    }
+
+    public static boolean isEqualOrMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+        return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+    }
+
+    public static boolean isEqualOrMorePrecise(ObjectStamp a, ObjectStamp b) {
+        return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+public class Histogram extends TreeMap<Integer, Integer> {
+
+    private static final long serialVersionUID = 7188324319057387738L;
+
+    private final String prefix;
+
+    public Histogram(String prefix) {
+        this.prefix = prefix;
+    }
+
+    public void tick(int bucket) {
+        Integer entry = get(bucket);
+        put(bucket, entry == null ? 1 : entry + 1);
+    }
+
+    public void print() {
+
+        // printing takes time, allow concurrent updates during printing
+        Histogram histogram = clone();
+
+        float casesTotal = 0;
+        for (int i : histogram.values()) {
+            casesTotal += i;
+        }
+        for (Map.Entry<Integer, Integer> entry : histogram.entrySet()) {
+            int numCases = entry.getValue();
+            int percentOut = (int) (numCases / casesTotal * 100);
+            String msg = prefix + String.format("%d iters in %4d cases (%2d %%)", entry.getKey(), numCases, percentOut);
+            if (entry.getKey() > 3) {
+                highlightInRed(msg);
+            } else {
+                System.out.println(msg);
+            }
+        }
+        System.out.println(prefix + "--------------------------");
+    }
+
+    @Override
+    public Histogram clone() {
+        return (Histogram) super.clone();
+    }
+
+    public static final String ANSI_RESET = "\u001B[0m";
+    public static final String ANSI_RED = "\u001B[31m";
+
+    public static void highlightInRed(String msg) {
+        System.out.println(ANSI_RED + msg + ANSI_RESET);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.util.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class IterativeFlowSensitiveReductionPhase extends BasePhase<PhaseContext> {
+
+    private static final int MAX_ITERATIONS = 256;
+
+    private final CanonicalizerPhase canonicalizer;
+
+    public IterativeFlowSensitiveReductionPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
+    }
+
+    public static class CountingListener extends HashSetNodeChangeListener {
+
+        public int count;
+
+        @Override
+        public void nodeChanged(Node node) {
+            super.nodeChanged(node);
+        }
+
+    }
+
+    // private Histogram histogram = new Histogram("FSR-");
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        FlowSensitiveReductionPhase eliminate = new FlowSensitiveReductionPhase(context.getMetaAccess());
+        CountingListener listener = new CountingListener();
+        int count = 1;
+        while (true) {
+            listener.count = count;
+            graph.trackInputChange(listener);
+            graph.trackUsagesDroppedZero(listener);
+            eliminate.apply(graph, context);
+            graph.stopTrackingInputChange();
+            graph.stopTrackingUsagesDroppedZero();
+            if (listener.getChangedNodes().isEmpty()) {
+                // histogram.tick(count);
+                break;
+            }
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Simplifiable) {
+                    listener.getChangedNodes().add(node);
+                }
+            }
+            canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
+            listener.getChangedNodes().clear();
+            if (++count > MAX_ITERATIONS) {
+                // System.out.println("Bailing out IterativeFlowSensitiveReductionPhase for graph: "
+                // + graph);
+                // FlowUtil.visualize(graph, "Bailout");
+                throw new BailoutException("Number of iterations in FlowSensitiveReductionPhase exceeds " + MAX_ITERATIONS);
+            }
+        }
+        // histogram.print();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.graph.*;
+
+/**
+ * A State instance is mutated in place as each FixedNode is visited in a basic block of
+ * instructions. Basic block: starts with a {@link com.oracle.graal.nodes.BeginNode BeginNode}, ends
+ * at an {@link com.oracle.graal.nodes.EndNode EndNode} or
+ * {@link com.oracle.graal.nodes.ControlSinkNode ControlSinkNode} and lacks intervening control
+ * splits or merges.
+ */
+public final class State extends MergeableState<State> implements Cloneable {
+
+    private static final DebugMetric metricTypeRegistered = Debug.metric("FSR-TypeRegistered");
+    private static final DebugMetric metricNullnessRegistered = Debug.metric("FSR-NullnessRegistered");
+    private static final DebugMetric metricObjectEqualsRegistered = Debug.metric("FSR-ObjectEqualsRegistered");
+    private static final DebugMetric metricImpossiblePathDetected = Debug.metric("FSR-ImpossiblePathDetected");
+
+    /**
+     * <p>
+     * Each state update results in a higher {@link State#versionNr versionNr}. The
+     * {@link State#versionNr versionNr} of different State instances can't be meaningfully compared
+     * (ie, same {@link State#versionNr versionNr} just indicates they've gone through the same
+     * number of updates). In particular, the {@link State#versionNr versionNr} of a merged state
+     * doesn't guarantee any more than being different from those of the states being merged.
+     * </p>
+     *
+     * <p>
+     * Still, {@link State#versionNr versionNr} proves useful in two cases:
+     *
+     * <ul>
+     * <li>recording the {@link State#versionNr versionNr} right after {@link State State} cloning,
+     * allows finding out afterwards whether (a) both states have diverged, (b) just one of them, or
+     * (c) none of them.</li>
+     * <li>a {@link State State} may become {@link State#isUnreachable isUnreachable}. In such case,
+     * it may make a difference whether any updates were performed on the state from the time it was
+     * cloned. Those updates indicate information not available in the state is was cloned from. For
+     * the purposes of {@link FlowSensitiveReduction FlowSensitiveReduction} an unreachable state
+     * need not be merged with any other (because control-flow won't reach the merge point over the
+     * path of the unreachable state).</li>
+     * </ul>
+     * </p>
+     *
+     */
+    int versionNr = 0;
+
+    boolean isUnreachable = false;
+
+    /**
+     * Getting here implies an opportunity was detected for dead-code-elimination. A counterpoint
+     * argument goes as follows: perhaps we don't get here that often, in which case the effort to
+     * detect an "impossible path" could be shaved off.
+     *
+     * @see com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt
+     */
+    void impossiblePath() {
+        isUnreachable = true;
+        metricImpossiblePathDetected.increment();
+    }
+
+    /**
+     * <p>
+     * This map tracks properties about reference-values, ie combinations of: definitely-null,
+     * known-to-be-non-null, seen-type.
+     * </p>
+     *
+     * <p>
+     * In contrast to {@link #trueFacts} and {@link #falseFacts}, this map can answer queries even
+     * though the exact {@link LogicNode} standing for such query hasn't been tracked. For example,
+     * queries about subtyping. Additionally, a {@link Witness} can combine separate pieces of
+     * information more flexibly, eg, two separate observations about non-null and check-cast are
+     * promoted to an instance-of witness.
+     * </p>
+     *
+     */
+    private Map<ValueNode, Witness> typeRefinements;
+
+    Map<LogicNode, GuardingNode> trueFacts;
+    Map<LogicNode, GuardingNode> falseFacts;
+
+    public State() {
+        this.typeRefinements = newNodeIdentityMap();
+        this.trueFacts = newNodeIdentityMap();
+        this.falseFacts = newNodeIdentityMap();
+    }
+
+    public State(State other) {
+        this.isUnreachable = other.isUnreachable;
+        this.versionNr = other.versionNr;
+        this.typeRefinements = newNodeIdentityMap();
+        for (Map.Entry<ValueNode, Witness> entry : other.typeRefinements.entrySet()) {
+            this.typeRefinements.put(entry.getKey(), new Witness(entry.getValue()));
+        }
+        this.trueFacts = newNodeIdentityMap(other.trueFacts);
+        this.falseFacts = newNodeIdentityMap(other.falseFacts);
+    }
+
+    public boolean repOK() {
+        // trueFacts and falseFacts disjoint
+        for (LogicNode trueFact : trueFacts.keySet()) {
+            assert !falseFacts.containsKey(trueFact) : trueFact + " tracked as both true and false fact.";
+        }
+        return true;
+    }
+
+    /**
+     * @return A new list containing only those states that are reachable.
+     */
+    private static ArrayList<State> reachableStates(List<State> states) {
+        ArrayList<State> result = new ArrayList<>(states);
+        Iterator<State> iter = result.iterator();
+        while (iter.hasNext()) {
+            if (iter.next().isUnreachable) {
+                iter.remove();
+            }
+        }
+        return result;
+    }
+
+    private Map<ValueNode, Witness> mergeKnownTypes(MergeNode merge, ArrayList<State> withReachableStates) {
+        Map<ValueNode, Witness> newKnownTypes = newNodeIdentityMap();
+
+        for (Map.Entry<ValueNode, Witness> entry : typeRefinements.entrySet()) {
+            ValueNode node = entry.getKey();
+            Witness type = new Witness(entry.getValue());
+
+            for (State other : withReachableStates) {
+                Witness otherType = other.typeInfo(node);
+                if (otherType == null) {
+                    type = null;
+                    break;
+                }
+                type.merge(otherType, merge);
+            }
+            if (type != null && type.knowsBetterThan(node)) {
+                assert node == GraphUtil.unproxify(node);
+                newKnownTypes.put(node, type);
+            }
+        }
+
+        return newKnownTypes;
+    }
+
+    /**
+     * <p>
+     * This method handles phis, by adding to the resulting state any information that can be gained
+     * (about type-refinement and nullness) based on the data available at each of the incoming
+     * branches.
+     * </p>
+     *
+     * <p>
+     * In more detail, <code>FlowSensitiveReduction#visitAbstractEndNode()</code> has already
+     * deverbosified the phi-values contributed by each reachable branch. The paths that
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction} determined to be
+     * unreachable will be eliminated by canonicalization and dead code elimination. For now they
+     * still exist, thus polluting the result of
+     * {@link com.oracle.graal.nodes.ValuePhiNode#inferStamp()} but we are careful to skip them when
+     * merging type-witnesses and known-null maps.
+     * </p>
+     */
+    private void mergePhis(MergeNode merge, List<State> withStates, Map<ValueNode, Witness> newKnownPhiTypes) {
+
+        if (merge instanceof LoopBeginNode) {
+            return;
+        }
+
+        for (PhiNode phi : merge.phis()) {
+            assert phi == GraphUtil.unproxify(phi);
+            if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+                ArrayList<ValueNode> reachingValues = new ArrayList<>();
+                if (!isUnreachable) {
+                    reachingValues.add(phi.valueAt(0));
+                }
+                for (int i = 0; i < withStates.size(); i++) {
+                    State otherState = withStates.get(i);
+                    if (!otherState.isUnreachable) {
+                        reachingValues.add(phi.valueAt(i + 1));
+                    }
+                }
+                assert !reachingValues.isEmpty();
+                ObjectStamp phiStamp = (ObjectStamp) phi.stamp();
+                ObjectStamp nonPollutedStamp = (ObjectStamp) StampTool.meet(reachingValues);
+                Witness w = new Witness(nonPollutedStamp, merge);
+                if (w.isNull() && !phiStamp.alwaysNull()) {
+                    // precision gain: null
+                    newKnownPhiTypes.put(phi, w);
+                } else if (FlowUtil.isMorePrecise(w.type(), phiStamp.type())) {
+                    // precision gain regarding type
+                    newKnownPhiTypes.put(phi, w);
+                    // confirm no precision loss regarding nullness
+                    assert implies(phiStamp.nonNull(), w.isNonNull());
+                    assert implies(phiStamp.alwaysNull(), w.isNull());
+                } else if (w.isNonNull() && !phiStamp.nonNull()) {
+                    // precision gain: non-null
+                    newKnownPhiTypes.put(phi, w);
+                    // confirm no precision loss regarding type
+                    assert !FlowUtil.isMorePrecise(phiStamp.type(), w.type());
+                }
+            }
+        }
+
+    }
+
+    private static boolean implies(boolean a, boolean b) {
+        return !a || b;
+    }
+
+    @Override
+    public boolean merge(MergeNode merge, List<State> withStates) {
+
+        ArrayList<State> withReachableStates = reachableStates(withStates);
+        if (withReachableStates.isEmpty()) {
+            return true;
+        }
+
+        for (State other : withReachableStates) {
+            versionNr = Math.max(versionNr, other.versionNr) + 1;
+            if (!other.isUnreachable) {
+                isUnreachable = false;
+            }
+        }
+
+        if (isUnreachable) {
+            typeRefinements.clear();
+            trueFacts.clear();
+            falseFacts.clear();
+            return true;
+        }
+
+        // may also get updated in a moment, during processing of phi nodes.
+        Map<ValueNode, Witness> newKnownTypes = mergeKnownTypes(merge, withReachableStates);
+        // may also get updated in a moment, during processing of phi nodes.
+        mergePhis(merge, withStates, newKnownTypes);
+        this.typeRefinements = newKnownTypes;
+
+        this.trueFacts = mergeTrueFacts(withReachableStates, merge);
+        this.falseFacts = mergeFalseFacts(withReachableStates, merge);
+
+        assert repOK();
+
+        return true;
+    }
+
+    private Map<LogicNode, GuardingNode> mergeTrueFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
+        Map<LogicNode, GuardingNode> newTrueConditions = newNodeIdentityMap();
+        for (Map.Entry<LogicNode, GuardingNode> entry : trueFacts.entrySet()) {
+            LogicNode check = entry.getKey();
+            GuardingNode guard = entry.getValue();
+
+            for (State other : withReachableStates) {
+                GuardingNode otherGuard = other.trueFacts.get(check);
+                if (otherGuard == null) {
+                    guard = null;
+                    break;
+                }
+                if (otherGuard != guard) {
+                    guard = merge;
+                }
+            }
+            if (guard != null) {
+                newTrueConditions.put(check, guard);
+            }
+        }
+        return newTrueConditions;
+    }
+
+    private Map<LogicNode, GuardingNode> mergeFalseFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
+        Map<LogicNode, GuardingNode> newFalseConditions = newNodeIdentityMap();
+        for (Map.Entry<LogicNode, GuardingNode> entry : falseFacts.entrySet()) {
+            LogicNode check = entry.getKey();
+            GuardingNode guard = entry.getValue();
+
+            for (State other : withReachableStates) {
+                GuardingNode otherGuard = other.falseFacts.get(check);
+                if (otherGuard == null) {
+                    guard = null;
+                    break;
+                }
+                if (otherGuard != guard) {
+                    guard = merge;
+                }
+            }
+            if (guard != null) {
+                newFalseConditions.put(check, guard);
+            }
+        }
+        return newFalseConditions;
+    }
+
+    /**
+     * @return null if no type-witness available for the argument, the witness otherwise.
+     */
+    public Witness typeInfo(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        return typeRefinements.get(GraphUtil.unproxify(object));
+    }
+
+    /**
+     * @return true iff the argument is known to stand for null.
+     */
+    public boolean isNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        if (StampTool.isObjectAlwaysNull(object)) {
+            return true;
+        }
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+        Witness w = typeRefinements.get(scrutinee);
+        return (w != null) && w.isNull();
+    }
+
+    /**
+     * <p>
+     * It makes a difference calling {@link Witness#isNonNull()} as opposed to
+     * {@link State#isNonNull(com.oracle.graal.nodes.ValueNode)}. The former guarantees the witness
+     * provides a guard certifying non-nullness. The latter just tells us there exists some guard
+     * that certifies the property we asked about.
+     * </p>
+     *
+     * <p>
+     * TODO improvement: isKnownNonNull could be made smarter by noticing some nodes always denote a
+     * non-null value (eg, ObjectGetClassNode). Similarly for isKnownNull. Code that looks at the
+     * stamp as well as code that looks for a non-null-witness would benefit from also checking such
+     * extended isKnownNonNull. Alternatively, the stamp of those nodes should always have
+     * is-non-null set.
+     * </p>
+     *
+     * @return true iff the argument is known to stand for non-null.
+     */
+    public boolean isNonNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        if (StampTool.isObjectNonNull(object)) {
+            return true;
+        }
+        Witness w = typeInfo(object);
+        return w == null ? false : w.isNonNull();
+    }
+
+    /**
+     * @return true iff the argument definitely stands for an object-value that conforms to the
+     *         given type.
+     */
+    public boolean knownToConform(ValueNode object, ResolvedJavaType to) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        assert !to.isPrimitive();
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && to.isAssignableFrom(stampType)) {
+            return true;
+        }
+        final ValueNode scrutinee = GraphUtil.unproxify(object);
+        if (isNull(scrutinee)) {
+            return true;
+        }
+        Witness w = typeInfo(scrutinee);
+        boolean witnessAnswer = w != null && w.type() != null && to.isAssignableFrom(w.type());
+        if (witnessAnswer) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return true iff the argument is known to stand for an object that is definitely non-null and
+     *         moreover does not conform to the given type.
+     */
+    public boolean knownNotToPassCheckCast(ValueNode object, ResolvedJavaType to) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        assert !to.isPrimitive();
+        final ValueNode scrutinee = GraphUtil.unproxify(object);
+        if (isNull(scrutinee)) {
+            // known-null means it conforms to whatever `to`
+            // and thus passes the check-cast
+            return false;
+        }
+        if (!isNonNull(scrutinee)) {
+            // unless `null` can be ruled out, a positive answer isn't safe
+            return false;
+        }
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && knownNotToConform(stampType, to)) {
+            return true;
+        }
+        Witness w = typeInfo(scrutinee);
+        boolean witnessAnswer = w != null && !w.cluelessAboutType() && knownNotToConform(w.type(), to);
+        if (witnessAnswer) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return true iff the argument is known to stand for an object that definitely does not
+     *         conform to the given type (no matter whether the object turns out to be null or
+     *         non-null).
+     */
+    public boolean knownNotToPassInstanceOf(ValueNode object, ResolvedJavaType to) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        assert !to.isPrimitive();
+        final ValueNode scrutinee = GraphUtil.unproxify(object);
+        if (isNull(scrutinee)) {
+            return true;
+        }
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && knownNotToConform(stampType, to)) {
+            // object turns out to be null, positive answer is correct
+            // object turns out non-null, positive answer is also correct
+            return true;
+        }
+        Witness w = typeInfo(scrutinee);
+        boolean witnessAnswer = w != null && !w.cluelessAboutType() && knownNotToConform(w.type(), to);
+        if (witnessAnswer) {
+            // object turns out to be null, positive answer is correct
+            // object turns out non-null, positive answer is also correct
+            return true;
+        }
+        return false;
+    }
+
+    // @formatter:off
+    /**
+     *   \   |     |     |     |
+     *    \ b|     |     |     |
+     *   a \ |     |     |     |
+     *      \|iface|final|non-f|
+     *  -----+-----------------|
+     *  iface|  F  |  F  |  F  |
+     *  -----+-----------------|
+     *  final|  C  |  C  |  C  |
+     *  -----+-----------------|
+     *  non-f|  F  |  C  |  C  |
+     *  -----------------------+
+     *
+     *  where:
+     *    F:     false
+     *    C:     check
+     *    iface: interface
+     *    final: exact non-interface reference-type
+     *    non-f: non-exact non-interface reference-type
+     *
+     * @return true iff the first argument is known not to conform to the second argument.
+     */
+    // @formatter:on
+    public static boolean knownNotToConform(ResolvedJavaType a, ResolvedJavaType b) {
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (b.isAssignableFrom(a)) {
+            return false;
+        }
+        if (a.isInterface()) {
+            return false;
+        }
+        boolean aFinal = Modifier.isFinal(a.getModifiers());
+        if (b.isInterface() && !aFinal) {
+            return false;
+        }
+        if (a.isAssignableFrom(b)) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    @Override
+    public State clone() {
+        return new State(this);
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private Witness getOrElseAddTypeInfo(ValueNode object) {
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+        Witness w = typeRefinements.get(scrutinee);
+        if (w == null) {
+            w = new Witness();
+            typeRefinements.put(scrutinee, w);
+        }
+        return w;
+    }
+
+    /**
+     * <p>
+     * Updates this {@link State State} to account for an observation about the scrutinee being
+     * non-null. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     * </p>
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller takes care of that.
+     * </p>
+     *
+     * @return whether state was updated (iff the observation added any new information)
+     */
+    public boolean trackNN(ValueNode object, GuardingNode anchor) {
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && !stampType.isInterface()) {
+            return trackIO(object, stampType, anchor);
+        }
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackNN(anchor)) {
+            versionNr++;
+            assert repOK();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link State State} to account for an observation about the scrutinee conforming
+     * to a type. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     * @return false iff the observed type is an interface, or doesn't provide any new information
+     *         not already known. Ie, this method returns true iff the observation resulted in
+     *         information gain.
+     */
+    public boolean trackCC(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+        if (observed.isInterface()) {
+            return false;
+        }
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackCC(observed, anchor)) {
+            versionNr++;
+            metricTypeRegistered.increment();
+            assert repOK();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link State State} to account for an observation about the non-null scrutinee
+     * conforming to a type.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     * @return whether state was updated (iff the observation added any new information)
+     */
+    public boolean trackIO(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+        assert !observed.isInterface() : "no infrastructure yet in State.Witness to support interfaces in general";
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackIO(observed, anchor)) {
+            versionNr++;
+            metricTypeRegistered.increment();
+            assert repOK();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * This method increases {@link #versionNr} (thus potentially invalidating
+     * {@link EquationalReasoner EquationalReasoner}'s caches) only if the fact wasn't known
+     * already.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     */
+    private void addFactPrimordial(LogicNode condition, Map<LogicNode, GuardingNode> to, GuardingNode anchor) {
+        assert condition != null;
+        if (!to.containsKey(condition)) {
+            versionNr++;
+            to.put(condition, anchor);
+        }
+    }
+
+    /**
+     * Ideas for the future:
+     * <ul>
+     * <li>track inferred less-than edges from (accumulated) CompareNode-s</li>
+     * <li>track set-representative for equality classes determined by (chained) IntegerTestNode</li>
+     * </ul>
+     *
+     */
+    public void addFact(boolean isTrue, LogicNode condition, GuardingNode anchor) {
+        assert anchor != null;
+        assert anchor instanceof FixedNode;
+        assert !isUnreachable;
+
+        if (condition instanceof LogicConstantNode) {
+            if (((LogicConstantNode) condition).getValue() != isTrue) {
+                impossiblePath();
+            }
+            return;
+        }
+
+        if (condition instanceof LogicNegationNode) {
+            addFact(!isTrue, ((LogicNegationNode) condition).getInput(), anchor);
+        } else if (condition instanceof ShortCircuitOrNode) {
+            /*
+             * We can register the conditions being or-ed as long as the anchor is a fixed node,
+             * because floating guards will be registered at a BeginNode but might be "valid" only
+             * later due to data flow dependencies. Therefore, registering both conditions of a
+             * ShortCircuitOrNode for a floating guard could lead to cycles in data flow, because
+             * the guard will be used as anchor for both conditions, and one condition could be
+             * depending on the other.
+             */
+            if (isTrue) {
+                CastCheckExtractor cce = CastCheckExtractor.extract(condition);
+                if (cce == null || isDependencyTainted(cce.subject, anchor)) {
+                    addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+                } else {
+                    trackCC(cce.subject, cce.type, anchor);
+                }
+            } else {
+                ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition;
+                addFact(disjunction.isXNegated(), disjunction.getX(), anchor);
+                // previous addFact might have resulted in impossiblePath()
+                if (isUnreachable) {
+                    return;
+                }
+                addFact(disjunction.isYNegated(), disjunction.getY(), anchor);
+            }
+        } else if (condition instanceof InstanceOfNode) {
+            addFactInstanceOf(isTrue, (InstanceOfNode) condition, anchor);
+        } else if (condition instanceof IsNullNode) {
+            IsNullNode nullCheck = (IsNullNode) condition;
+            addNullness(isTrue, nullCheck.object(), anchor);
+        } else if (condition instanceof ObjectEqualsNode) {
+            addFactObjectEqualsNode(isTrue, (ObjectEqualsNode) condition, anchor);
+        } else {
+            addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+        }
+        assert repOK();
+    }
+
+    /**
+     * An instanceof hint is tracked differently depending on whether it's an interface-test or not
+     * (because type-refinements currently lacks the ability to track interface types).
+     *
+     */
+    private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) {
+        ValueNode object = instanceOf.object();
+        if (isTrue) {
+            if (knownNotToPassInstanceOf(object, instanceOf.type())) {
+                impossiblePath();
+                return;
+            }
+            addNullness(false, object, anchor);
+            if (instanceOf.type().isInterface()) {
+                if (!knownToConform(object, instanceOf.type())) {
+                    addFactPrimordial(instanceOf, trueFacts, anchor);
+                }
+            } else {
+                trackIO(object, instanceOf.type(), anchor);
+            }
+        }
+    }
+
+    private void addFactObjectEqualsNode(boolean isTrue, ObjectEqualsNode equals, GuardingNode anchor) {
+        if (isDependencyTainted(equals.x(), anchor)) {
+            return;
+        }
+        if (isDependencyTainted(equals.y(), anchor)) {
+            return;
+        }
+        assert anchor instanceof FixedNode;
+        ValueNode x = GraphUtil.unproxify(equals.x());
+        ValueNode y = GraphUtil.unproxify(equals.y());
+        if (isTrue) {
+            if (isNull(x) && isNonNull(y)) {
+                impossiblePath();
+                return;
+            }
+            if (isNonNull(x) && isNull(y)) {
+                impossiblePath();
+                return;
+            }
+            if (isNull(x) || isNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(true, equals.x(), anchor);
+                addNullness(true, equals.y(), anchor);
+            } else if (isNonNull(x) || isNonNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.x(), anchor);
+                addNullness(false, equals.y(), anchor);
+            }
+            Witness wx = typeInfo(x);
+            Witness wy = typeInfo(y);
+            if (wx == null && wy == null) {
+                return;
+            } else if (wx != null && wy != null) {
+                // tighten their type-hints, provided at least one available
+                // both witnesses may have seen == null, ie they may be NN witnesses
+                ResolvedJavaType best = FlowUtil.tighten(wx.type(), wy.type());
+                if (best != null) {
+                    assert !best.isInterface();
+                    // type tightening is enough, nullness already taken care of
+                    trackCC(equals.x(), best, anchor);
+                    trackCC(equals.y(), best, anchor);
+                }
+            } else if (wx == null) {
+                typeRefinements.put(x, new Witness(wy));
+            } else if (wy == null) {
+                typeRefinements.put(y, new Witness(wx));
+            }
+        } else {
+            if (isNull(x) && !isNonNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.y(), anchor);
+            } else if (!isNonNull(x) && isNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.x(), anchor);
+            }
+        }
+    }
+
+    /**
+     * Adds information about the nullness of a value. If isNull is true then the value is known to
+     * be null, otherwise the value is known to be non-null.
+     */
+    public void addNullness(boolean isNull, ValueNode value, GuardingNode anchor) {
+        if (isDependencyTainted(value, anchor)) {
+            return;
+        }
+        assert anchor instanceof FixedNode;
+        ValueNode scrutinee = GraphUtil.unproxify(value);
+        boolean wasNull = isNull(scrutinee);
+        boolean wasNonNull = isNonNull(scrutinee);
+        if (isNull) {
+            if (wasNonNull) {
+                impossiblePath();
+            } else {
+                metricNullnessRegistered.increment();
+                versionNr++;
+                Witness w = getOrElseAddTypeInfo(scrutinee);
+                w.trackDN(anchor);
+            }
+        } else {
+            if (wasNull) {
+                impossiblePath();
+            } else {
+                metricNullnessRegistered.increment();
+                trackNN(scrutinee, anchor);
+            }
+        }
+        assert repOK();
+    }
+
+    /**
+     *
+     * @return true iff `value` may lose dependency not covered by `anchor`.
+     */
+    public static boolean isDependencyTainted(ValueNode value, GuardingNode anchor) {
+        assert anchor instanceof FixedNode;
+        if (value instanceof ValueProxy) {
+            if (value instanceof GuardedNode) {
+                GuardedNode gn = (GuardedNode) value;
+                GuardingNode guardian = gn.getGuard();
+                if (guardian != null) {
+                    boolean isGuardedByFixed = guardian instanceof FixedNode;
+                    if (!isGuardedByFixed) {
+                        return true;
+                    }
+                }
+            }
+            // if (value instanceof GuardingNode) {
+            // return true;
+            // }
+            ValueProxy proxy = (ValueProxy) value;
+            return isDependencyTainted(proxy.getOriginalNode(), anchor);
+        }
+        return false;
+    }
+
+    public void clear() {
+        versionNr = 0;
+        isUnreachable = false;
+        typeRefinements.clear();
+        trueFacts.clear();
+        falseFacts.clear();
+    }
+
+    /**
+     * <p>
+     * If the argument is known null due to its stamp, there's no need to have an anchor for that
+     * fact and this method returns null.
+     * </p>
+     *
+     * <p>
+     * Otherwise, if an anchor is found it is returned, null otherwise.
+     * </p>
+     */
+    public GuardingNode nonTrivialNullAnchor(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        if (StampTool.isObjectAlwaysNull(object)) {
+            return null;
+        }
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+        Witness w = typeRefinements.get(scrutinee);
+        if (w != null && w.isNull()) {
+            return w.guard();
+        }
+        return null;
+    }
+
+    /**
+     * This method:
+     * <ul>
+     * <li>
+     * attempts to find an existing {@link com.oracle.graal.nodes.extended.GuardingNode} that
+     * implies the property stated by the arguments. If found, returns it as positive evidence.</li>
+     * <li>
+     * otherwise, if the property of interest is known not to hold, negative evidence is returned.</li>
+     * <li>
+     * otherwise, null is returned.</li>
+     * </ul>
+     */
+    public Evidence outcome(boolean isTrue, LogicNode cond) {
+
+        // attempt to find an anchor for the condition of interest, verbatim
+        if (isTrue) {
+            GuardingNode existingGuard = trueFacts.get(cond);
+            if (existingGuard != null) {
+                return new Evidence(existingGuard);
+            }
+            if (falseFacts.containsKey(cond)) {
+                return Evidence.COUNTEREXAMPLE;
+            }
+        } else {
+            GuardingNode existingGuard = falseFacts.get(cond);
+            if (existingGuard != null) {
+                return new Evidence(existingGuard);
+            }
+            if (trueFacts.containsKey(cond)) {
+                return Evidence.COUNTEREXAMPLE;
+            }
+        }
+
+        if (cond instanceof IsNullNode) {
+            return outcomeIsNullNode(isTrue, (IsNullNode) cond);
+        }
+
+        if (cond instanceof InstanceOfNode) {
+            return outcomeInstanceOfNode(isTrue, (InstanceOfNode) cond);
+        }
+
+        if (cond instanceof ShortCircuitOrNode) {
+            return outcomeShortCircuitOrNode(isTrue, (ShortCircuitOrNode) cond);
+        }
+
+        // can't produce evidence
+        return null;
+    }
+
+    /**
+     * Utility method for {@link #outcome(boolean, com.oracle.graal.nodes.LogicNode)}
+     */
+    private Evidence outcomeIsNullNode(boolean isTrue, IsNullNode isNullNode) {
+        if (isTrue) {
+            // grab an anchor attesting nullness
+            final GuardingNode replacement = nonTrivialNullAnchor(isNullNode.object());
+            if (replacement != null) {
+                return new Evidence(replacement);
+            }
+            if (isNonNull(isNullNode.object())) {
+                return Evidence.COUNTEREXAMPLE;
+            }
+        } else {
+            // grab an anchor attesting non-nullness
+            final Witness w = typeInfo(isNullNode.object());
+            if (w != null && w.isNonNull()) {
+                return new Evidence(w.guard());
+            }
+            if (isNull(isNullNode.object())) {
+                return Evidence.COUNTEREXAMPLE;
+            }
+        }
+        // can't produce evidence
+        return null;
+    }
+
+    /**
+     * Utility method for {@link #outcome(boolean, com.oracle.graal.nodes.LogicNode)}
+     */
+    private Evidence outcomeInstanceOfNode(boolean isTrue, InstanceOfNode iOf) {
+        final Witness w = typeInfo(iOf.object());
+        if (isTrue) {
+            if (isNull(iOf.object())) {
+                return Evidence.COUNTEREXAMPLE;
+            }
+            // grab an anchor attesting instanceof
+            if ((w != null) && (w.type() != null)) {
+                if (w.isNonNull()) {
+                    if (iOf.type().isAssignableFrom(w.type())) {
+                        return new Evidence(w.guard());
+                    }
+                }
+                if (State.knownNotToConform(w.type(), iOf.type())) {
+                    // null -> fails instanceof
+                    // non-null but non-conformant -> also fails instanceof
+                    return Evidence.COUNTEREXAMPLE;
+                }
+            }
+        } else {
+            // grab an anchor attesting not-instanceof
+            // (1 of 2) attempt determining nullness
+            final GuardingNode nullGuard = nonTrivialNullAnchor(iOf.object());
+            if (nullGuard != null) {
+                return new Evidence(nullGuard);
+            }
+            // (2 of 2) attempt determining known-not-to-conform
+            if (w != null && !w.cluelessAboutType()) {
+                if (State.knownNotToConform(w.type(), iOf.type())) {
+                    return new Evidence(w.guard());
+                }
+            }
+        }
+        // can't produce evidence
+        return null;
+    }
+
+    /**
+     * Utility method for {@link #outcome(boolean, com.oracle.graal.nodes.LogicNode)}
+     */
+    private Evidence outcomeShortCircuitOrNode(boolean isTrue, ShortCircuitOrNode orNode) {
+        if (!isTrue) {
+            // too tricky to reason about
+            return null;
+        }
+        CastCheckExtractor cce = CastCheckExtractor.extract(orNode);
+        if (cce != null) {
+            // grab an anchor attesting check-cast
+            Witness w = typeInfo(cce.subject);
+            if (w != null && w.type() != null) {
+                if (cce.type.isAssignableFrom(w.type())) {
+                    return new Evidence(w.guard());
+                }
+                if (isNonNull(cce.subject) && State.knownNotToConform(w.type(), cce.type)) {
+                    return Evidence.COUNTEREXAMPLE;
+                }
+            }
+        }
+        // search for positive-evidence for the first or-input
+        Evidence evidenceX = outcome(!orNode.isXNegated(), orNode.getX());
+        if (evidenceX != null && evidenceX.isPositive()) {
+            return evidenceX;
+        }
+        // search for positive-evidence for the second or-input
+        Evidence evidenceY = outcome(!orNode.isYNegated(), orNode.getY());
+        if (evidenceY != null && evidenceY.isPositive()) {
+            return evidenceY;
+        }
+        // check for contradictions on both or-inputs
+        if (evidenceX != null && evidenceY != null) {
+            assert evidenceX.isNegative() && evidenceY.isNegative();
+            return Evidence.COUNTEREXAMPLE;
+        }
+        // can't produce evidence
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+
+/**
+ * <p>
+ * A witness progressively tracks more detailed properties about an object value (the scrutinee);
+ * the properties in question comprise whether the scrutinee has been observed:
+ *
+ * <ul>
+ * <li>as non-null,</li>
+ * <li>in a successful checkcast, or</li>
+ * <li>in a successful instanceof.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * A witness is updated only when doing so increases the information content of the witness. For
+ * example, upon visiting a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} the
+ * witness gets a chance to become updated.
+ * </p>
+ *
+ * <p>
+ * Therefore, at any given time, a witness represents the most detailed knowledge available so far
+ * about the scrutinee, which is the knowledge most relevant for upcoming program-points.
+ * </p>
+ *
+ * <p>
+ * The availability of witnesses about both non-nullness and checkcast (for a given scrutinee)
+ * promotes to an instanceof-style witness . The "levels" of knowledge a witness may exhibit are
+ * captured by {@link com.oracle.graal.phases.common.cfs.Witness.LEVEL}. For conciseness, the
+ * following query methods are available for a {@link com.oracle.graal.phases.common.cfs.Witness}:
+ * <ul>
+ * <li>{@link #atNonNull()}</li>
+ * <li>{@link #atCheckCast()}</li>
+ * <li>{@link #atInstanceOf()}</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Only non-interface object types (ie, class and array types) are tracked. Small extensions are
+ * required to track interfaces, extensions that might be added after the current scheme proves
+ * itself.
+ * </p>
+ *
+ * <p>
+ * Some useful facts about the Statechart implemented by {@link Witness Witness}:
+ *
+ * <ul>
+ * <li>the start-state is "clueless"</li>
+ * <li>
+ * A self-transition via trackCC from whichever the current state is to itself, without information
+ * gain, is always possible. Just give {@link Object java.lang.Object} as observed type.</li>
+ * </ul>
+ * </p>
+ *
+ */
+public class Witness implements Cloneable {
+
+    private static enum LEVEL {
+        CLUELESS,
+        NN,
+        CC,
+        IO,
+        DN
+    }
+
+    private boolean atNonNull() {
+        return level == LEVEL.NN;
+    }
+
+    private boolean atCheckCast() {
+        return level == LEVEL.CC;
+    }
+
+    private boolean atInstanceOf() {
+        return level == LEVEL.IO;
+    }
+
+    private boolean atDefinitelyNull() {
+        return level == LEVEL.DN;
+    }
+
+    private void transition(LEVEL to, GuardingNode newAnchor) {
+        this.level = to;
+        this.gn = newAnchor;
+        assert repOK();
+    }
+
+    public Witness() {
+    }
+
+    public Witness(Witness other) {
+        level = other.level;
+        seen = other.seen;
+        gn = other.gn;
+    }
+
+    /**
+     * Counterpart to {@link #asStamp()}
+     */
+    public Witness(ObjectStamp stamp, GuardingNode anchor) {
+        assert stamp.isLegal();
+        assert anchor != null;
+        if (stamp.alwaysNull()) {
+            // seen left null
+            transition(LEVEL.DN, anchor);
+        } else {
+            boolean isNonIface = (stamp.type() != null && !stamp.type().isInterface());
+            if (stamp.nonNull()) {
+                if (isNonIface) {
+                    seen = stamp.type();
+                    transition(LEVEL.IO, anchor);
+                } else {
+                    seen = null;
+                    transition(LEVEL.NN, anchor);
+                }
+            } else {
+                if (isNonIface) {
+                    seen = stamp.type();
+                    transition(LEVEL.CC, anchor);
+                } else {
+                    seen = null;
+                    transition(LEVEL.CLUELESS, null);
+                    assert clueless();
+                }
+            }
+        }
+        assert repOK();
+    }
+
+    public boolean isNonNull() {
+        return atNonNull() || atInstanceOf();
+    }
+
+    public boolean isNull() {
+        return atDefinitelyNull();
+    }
+
+    /**
+     * The most precise type known so far about the scrutinee. (Please notice that nothing can be
+     * deduced about the non-nullness-status of the scrutinee from invoking this method alone).
+     */
+    public ResolvedJavaType type() {
+        return seen;
+    }
+
+    public ObjectStamp asStamp() {
+        boolean isKnownExact = (seen != null && seen.equals(seen.asExactType()));
+        return new ObjectStamp(seen, isKnownExact, isNonNull(), isNull());
+    }
+
+    private LEVEL level = LEVEL.CLUELESS;
+    private ResolvedJavaType seen = null;
+
+    /**
+     * Evidence (ie, a {@link com.oracle.graal.nodes.extended.GuardingNode}) attesting to the status
+     * reported by this witness.
+     *
+     * May be one of:
+     *
+     * <ul>
+     * <li>
+     * {@link com.oracle.graal.nodes.BeginNode BeginNode},</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.LoopExitNode LoopExitNode},</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}</li>
+     * <li>{@link com.oracle.graal.nodes.MergeNode MergeNode}, resulting from merging two witnesses
+     * with different values for this anchor</li>
+     * </ul>
+     *
+     * <p>
+     * An {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} test results in the
+     * more-clueless of both scrutinees having its witness upgraded to that of the other (both
+     * scrutinees share the same {@link Witness Witness} instance from then on). For this reason,
+     * this field may also hold the anchors associated to an
+     * {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} occurrence, ie nodes
+     * that can serve as {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} for the
+     * purposes of building a {@link com.oracle.graal.nodes.PiNode PiNode}.
+     * </p>
+     *
+     */
+    private GuardingNode gn = null;
+
+    /**
+     * Invariants of this class:
+     * <ul>
+     * <li>All fields holding null is ok, the hallmark of a {@link #clueless() clueless} witness.
+     * Another way for a witness to be clueless is by recording <code>java.lang.Object</code> as the
+     * seen type and nothing more.</li>
+     * <li>{@link #seen seen} may be null as long as the only hint being recorded is non-nullness</li>
+     * <li>A non-null value for {@link #seen seen} can't be tracked with NN, that combination
+     * amounts to IO and is tracked as such</li>
+     * <li>At most one of NN, CC, IO may be tracked at any given time</li>
+     * <li>A non-null CC or a non-null IO force {@link #seen seen} to be non-null</li>
+     * <li>{@link #seen seen} must be null or denote a non-interface reference type (ie, either a
+     * class-type or an array-type)</li>
+     * </ul>
+     */
+    private boolean repOK() {
+        if (clueless()) {
+            assert level == LEVEL.CLUELESS;
+            return true;
+        }
+        if (atNonNull() || atDefinitelyNull()) {
+            assert seen == null;
+        }
+        if (seen != null) {
+            assert !seen.isInterface();
+            assert !seen.isPrimitive();
+        }
+        assert gn instanceof BeginNode || gn instanceof LoopExitNode || gn instanceof MergeNode || gn instanceof FixedGuardNode;
+        return true;
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean clueless() {
+        return cluelessAboutType() && cluelessAboutNullity();
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean cluelessAboutType() {
+        // TODO also clueless when `seen` is `java.lang.Object`
+        return seen == null;
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean cluelessAboutNullity() {
+        return !atNonNull() && !atInstanceOf() && !atDefinitelyNull();
+    }
+
+    /**
+     * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+     * the given {@link com.oracle.graal.compiler.common.type.ObjectStamp}.
+     */
+    boolean knowsBetterThan(ObjectStamp other) {
+        return FlowUtil.isMorePrecise(asStamp(), other);
+    }
+
+    /**
+     * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+     * the {@link com.oracle.graal.compiler.common.type.ObjectStamp} of the given argument.
+     */
+    boolean knowsBetterThan(ValueNode other) {
+        return knowsBetterThan((ObjectStamp) other.stamp());
+    }
+
+    /**
+     * Porcelain method for internal use only, invoked upon a Facade method being notified about
+     * checkcast or instanceof.
+     *
+     * @return whether the state was updated (iff the observation adds any new information)
+     */
+    private boolean refinesSeenType(ResolvedJavaType observed) {
+        if (isNull()) {
+            return false;
+        }
+        if (cluelessAboutType() || FlowUtil.isMorePrecise(observed, seen)) {
+            seen = observed;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the scrutinee being
+     * non-null. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead
+     *
+     * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+     *         information)
+     */
+    public boolean trackNN(GuardingNode anchor) {
+        assert repOK();
+        assert !isNull();
+        try {
+            if (atInstanceOf()) {
+                return false;
+            }
+            if (atCheckCast()) {
+                transition(LEVEL.IO, anchor);
+                return true;
+            }
+            if (!atNonNull()) {
+                transition(LEVEL.NN, anchor);
+                return true;
+            }
+            return false;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the scrutinee being
+     * null.
+     *
+     * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+     *         information)
+     */
+    public boolean trackDN(GuardingNode anchor) {
+        assert repOK();
+        assert !isNonNull();
+        try {
+            if (atDefinitelyNull()) {
+                return false;
+            }
+            assert level == LEVEL.CLUELESS || atCheckCast();
+            seen = null;
+            transition(LEVEL.DN, anchor);
+            return true;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the scrutinee
+     * conforming to the provided type. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     *
+     * @return true iff information was gained.
+     */
+    public boolean trackCC(ResolvedJavaType observed, GuardingNode anchor) {
+        assert !observed.isInterface();
+        assert anchor != null;
+        assert repOK();
+        try {
+            boolean anchorObsolete = refinesSeenType(observed);
+            if (atInstanceOf()) {
+                /*
+                 * Statechart: self-transition at IO, potential information gain.
+                 */
+                if (anchorObsolete) {
+                    transition(LEVEL.IO, anchor);
+                    return true;
+                }
+                return false;
+            }
+            if (anchorObsolete) {
+                if (!atNonNull()) {
+                    /* Statechart: transition from clueless to CC. */
+                    transition(LEVEL.CC, anchor);
+                    return true;
+                } else {
+                    /* Statechart: transition from NN to IO. */
+                    transition(LEVEL.IO, anchor);
+                    return true;
+                }
+            }
+            /*
+             * Statechart: self-transition from whichever the current state is to itself, without
+             * information gain.
+             */
+            return false;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the non-null
+     * scrutinee conforming to a type.
+     *
+     * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+     *         information)
+     */
+    public boolean trackIO(ResolvedJavaType observed, GuardingNode anchor) {
+        assert repOK();
+        assert !isNull();
+        try {
+            boolean gotMorePreciseType = refinesSeenType(observed);
+            if (!atInstanceOf() || gotMorePreciseType) {
+                transition(LEVEL.IO, anchor);
+                return true;
+            }
+            return gotMorePreciseType;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Shallow cloning is enough because what's reachable from {@link Witness} is primitive or used
+     * read-only when merging states.
+     */
+    @Override
+    public Witness clone() {
+        return new Witness(this);
+    }
+
+    /**
+     * @return null for a clueless method, non-null otherwise.
+     */
+    GuardingNode guard() {
+        return gn;
+    }
+
+    /**
+     * Merges another state into this one, by mutating this object, the other is left as is.
+     */
+    public void merge(Witness that, MergeNode merge) {
+        assert this.repOK();
+        assert that.repOK();
+
+        if (clueless()) {
+            return;
+        }
+
+        // preserve guarding node only if matches other, otherwise settle on `merge`
+        final GuardingNode resultGuard = (guard() == that.guard()) ? guard() : merge;
+
+        if (isNull()) {
+            switch (that.level) {
+                case CLUELESS:
+                case NN:
+                    // lose is-null status, gain nothing
+                    level = LEVEL.CLUELESS;
+                    seen = null;
+                    break;
+                case CC:
+                case IO:
+                    // demote to check-cast
+                    level = LEVEL.CC;
+                    seen = that.seen;
+                    break;
+                case DN:
+                    // keep is-null status
+            }
+            gn = resultGuard;
+            return;
+        }
+
+        if (that.isNull()) {
+            /*
+             * Same decisions as above (based on this-being-null and that-level) are now made based
+             * on (that-being-null and this-level). Because merge is commutative.
+             */
+            switch (level) {
+                case CLUELESS:
+                case NN:
+                    // lose is-null status, gain nothing
+                    level = LEVEL.CLUELESS;
+                    seen = null;
+                    break;
+                case CC:
+                    break;
+                case IO:
+                    // demote to check-cast
+                    level = LEVEL.CC;
+                    // keep this.seen as-is
+                    break;
+                case DN:
+                    // keep is-null status
+            }
+            gn = resultGuard;
+            return;
+        }
+
+        // by now we know neither this nor that are known-to-be-null
+        assert !isNull() && !that.isNull();
+
+        // umbrella type over the observations from both witnesses
+        ResolvedJavaType newSeen = (seen == null || that.seen == null) ? null : FlowUtil.widen(seen, that.seen);
+
+        /*
+         * guarantee on (both conformance and non-nullness) required from each input in order for
+         * the result to be able to offer such guarantee
+         */
+        final boolean resultIO = atInstanceOf() && that.atInstanceOf();
+        /* failing that, attempt to rescue type-conformance */
+        final boolean resultCC = !resultIO && (!cluelessAboutType() && !that.cluelessAboutType());
+        /* if all else fails, attempt to rescue non-nullness */
+        final boolean resultNN = !resultIO && !resultCC && (isNonNull() && that.isNonNull());
+
+        seen = newSeen;
+        level = resultIO ? LEVEL.IO : resultCC ? LEVEL.CC : resultNN ? LEVEL.NN : LEVEL.CLUELESS;
+        gn = resultGuard;
+
+        assert repOK();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(cluelessAboutType() ? "seen=?" : "seen=" + seen);
+        sb.append(";");
+        sb.append("gn=" + gn);
+        return sb.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,154 @@
+/*
+ * 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.phases.common.inlining;
+
+import java.util.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.options.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.policy.GreedyInliningPolicy;
+import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
+import com.oracle.graal.phases.common.inlining.walker.CallsiteHolder;
+import com.oracle.graal.phases.common.inlining.walker.InliningData;
+import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
+import com.oracle.graal.phases.tiers.*;
+
+public class InliningPhase extends AbstractInliningPhase {
+
+    public static class Options {
+
+        // @formatter:off
+        @Option(help = "Unconditionally inline intrinsics")
+        public static final OptionValue<Boolean> AlwaysInlineIntrinsics = new OptionValue<>(false);
+        // @formatter:on
+    }
+
+    private final InliningPolicy inliningPolicy;
+    private final CanonicalizerPhase canonicalizer;
+
+    private int inliningCount;
+    private int maxMethodPerInlining = Integer.MAX_VALUE;
+
+    public InliningPhase(CanonicalizerPhase canonicalizer) {
+        this(new GreedyInliningPolicy(null), canonicalizer);
+    }
+
+    public InliningPhase(Map<Invoke, Double> hints, CanonicalizerPhase canonicalizer) {
+        this(new GreedyInliningPolicy(hints), canonicalizer);
+    }
+
+    public InliningPhase(InliningPolicy policy, CanonicalizerPhase canonicalizer) {
+        this.inliningPolicy = policy;
+        this.canonicalizer = canonicalizer;
+    }
+
+    public void setMaxMethodsPerInlining(int max) {
+        maxMethodPerInlining = max;
+    }
+
+    public int getInliningCount() {
+        return inliningCount;
+    }
+
+    /**
+     * <p>
+     * The space of inlining decisions is explored depth-first with the help of a stack realized by
+     * {@link com.oracle.graal.phases.common.inlining.walker.InliningData}. At any point in time,
+     * its topmost element consist of:
+     * <ul>
+     * <li>
+     * one or more {@link CallsiteHolder}s of inlining candidates, all of them corresponding to a
+     * single callsite (details below). For example, "exact inline" leads to a single candidate.</li>
+     * <li>
+     * the callsite (for the targets above) is tracked as a {@link MethodInvocation}. The difference
+     * between {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#totalGraphs()}
+     * and {@link MethodInvocation#processedGraphs()} indicates the topmost {@link CallsiteHolder}s
+     * that might be delved-into to explore inlining opportunities.</li>
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * The bottom-most element in the stack consists of:
+     * <ul>
+     * <li>
+     * a single {@link CallsiteHolder} (the root one, for the method on which inlining was called)</li>
+     * <li>
+     * a single {@link MethodInvocation} (the
+     * {@link com.oracle.graal.phases.common.inlining.walker.MethodInvocation#isRoot} one, ie the
+     * unknown caller of the root graph)</li>
+     * </ul>
+     *
+     * </p>
+     *
+     * <p>
+     * The stack grows and shrinks as choices are made among the alternatives below:
+     * <ol>
+     * <li>
+     * not worth inlining: pop any remaining graphs not yet delved into, pop the current invocation.
+     * </li>
+     * <li>
+     * process next invoke: delve into one of the callsites hosted in the current candidate graph,
+     * determine whether any inlining should be performed in it</li>
+     * <li>
+     * try to inline: move past the current inlining candidate (remove it from the topmost element).
+     * If that was the last one then try to inline the callsite that is (still) in the topmost
+     * element of {@link com.oracle.graal.phases.common.inlining.walker.InliningData}, and then
+     * remove such callsite.</li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * Some facts about the alternatives above:
+     * <ul>
+     * <li>
+     * the first step amounts to backtracking, the 2nd one to delving, and the 3rd one also involves
+     * backtracking (however after may-be inlining).</li>
+     * <li>
+     * the choice of abandon-and-backtrack or delve-into is depends on
+     * {@link InliningPolicy#isWorthInlining} and {@link InliningPolicy#continueInlining}.</li>
+     * <li>
+     * the 3rd choice is picked when both of the previous ones aren't picked</li>
+     * <li>
+     * as part of trying-to-inline, {@link InliningPolicy#isWorthInlining} again sees use, but
+     * that's another story.</li>
+     * </ul>
+     * </p>
+     *
+     */
+    @Override
+    protected void run(final StructuredGraph graph, final HighTierContext context) {
+        final InliningData data = new InliningData(graph, context, maxMethodPerInlining, canonicalizer, inliningPolicy);
+
+        while (data.hasUnprocessedGraphs()) {
+            boolean wasInlined = data.moveForward();
+            if (wasInlined) {
+                inliningCount++;
+            }
+        }
+
+        assert data.inliningDepth() == 0;
+        assert data.graphCount() == 0;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,533 @@
+/*
+ * 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.inlining;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.type.StampFactory.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.DuplicationReplacement;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.common.inlining.info.*;
+
+public class InliningUtil {
+
+    private static final String inliningDecisionsScopeString = "InliningDecisions";
+    /**
+     * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level
+     * and all inlined methods), irrespective of how many bytecodes in each method are actually
+     * parsed (which may be none for methods whose IR is retrieved from a cache).
+     */
+    public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes");
+
+    /**
+     * Print a HotSpot-style inlining message to the console.
+     */
+    private static void printInlining(final InlineInfo info, final int inliningDepth, final boolean success, final String msg, final Object... args) {
+        printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args);
+    }
+
+    /**
+     * Print a HotSpot-style inlining message to the console.
+     */
+    private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) {
+        if (HotSpotPrintInlining.getValue()) {
+            // 1234567
+            TTY.print("        ");     // print timestamp
+            // 1234
+            TTY.print("     ");        // print compilation number
+            // % s ! b n
+            TTY.print("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' ');
+            TTY.print("     ");        // more indent
+            TTY.print("    ");         // initial inlining indent
+            for (int i = 0; i < inliningDepth; i++) {
+                TTY.print("  ");
+            }
+            TTY.println(String.format("@ %d  %s   %s%s", invoke.bci(), methodName(method, null), success ? "" : "not inlining ", String.format(msg, args)));
+        }
+    }
+
+    public static void logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
+        logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
+    }
+
+    public static void logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
+        logInliningDecision(info, inliningDepth, true, false, msg, args);
+    }
+
+    public static void logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
+        if (allowLogging) {
+            printInlining(info, inliningDepth, success, msg, args);
+            if (shouldLogInliningDecision()) {
+                logInliningDecision(methodName(info), success, msg, args);
+            }
+        }
+    }
+
+    public static void logInliningDecision(final String msg, final Object... args) {
+        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+            // Can't use log here since we are varargs
+            if (Debug.isLogEnabled()) {
+                Debug.logv(msg, args);
+            }
+        }
+    }
+
+    public static void logNotInlinedMethod(Invoke invoke, String msg) {
+        if (shouldLogInliningDecision()) {
+            String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName());
+            logInliningDecision(methodString, false, msg, new Object[0]);
+        }
+    }
+
+    public static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
+        logNotInlinedInvoke(invoke, inliningDepth, method, msg, new Object[0]);
+    }
+
+    public static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
+        printInlining(method, invoke, inliningDepth, false, msg, args);
+        if (shouldLogInliningDecision()) {
+            String methodString = methodName(method, invoke);
+            logInliningDecision(methodString, false, msg, args);
+        }
+    }
+
+    private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
+        String inliningMsg = "inlining " + methodString + ": " + msg;
+        if (!success) {
+            inliningMsg = "not " + inliningMsg;
+        }
+        logInliningDecision(inliningMsg, args);
+    }
+
+    public static boolean shouldLogInliningDecision() {
+        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+            return Debug.isLogEnabled();
+        }
+    }
+
+    private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
+        if (invoke != null && invoke.stateAfter() != null) {
+            return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
+        } else {
+            return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
+        }
+    }
+
+    private static String methodName(InlineInfo info) {
+        if (info == null) {
+            return "null";
+        } else if (info.invoke() != null && info.invoke().stateAfter() != null) {
+            return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString();
+        } else {
+            return info.toString();
+        }
+    }
+
+    private static String methodName(FrameState frameState, int bci) {
+        StringBuilder sb = new StringBuilder();
+        if (frameState.outerFrameState() != null) {
+            sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
+            sb.append("->");
+        }
+        sb.append(MetaUtil.format("%h.%n", frameState.method()));
+        sb.append("@").append(bci);
+        return sb.toString();
+    }
+
+    public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
+        MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
+        MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType()));
+        invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
+    }
+
+    public static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
+        return createAnchoredReceiver(graph, anchor, receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType));
+    }
+
+    private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ValueNode receiver, Stamp stamp) {
+        // to avoid that floating reads on receiver fields float above the type check
+        return graph.unique(new GuardedValueNode(receiver, anchor, stamp));
+    }
+
+    /**
+     * @return null iff the check succeeds, otherwise a (non-null) descriptive message.
+     */
+    public static String checkInvokeConditions(Invoke invoke) {
+        if (invoke.predecessor() == null || !invoke.asNode().isAlive()) {
+            return "the invoke is dead code";
+        }
+        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
+            return "the invoke has already been lowered, or has been created as a low-level node";
+        }
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        if (callTarget.targetMethod() == null) {
+            return "target method is null";
+        }
+        if (invoke.stateAfter() == null) {
+            // TODO (chaeubl): why should an invoke not have a state after?
+            return "the invoke has no after state";
+        }
+        if (!invoke.useForInlining()) {
+            return "the invoke is marked to be not used for inlining";
+        }
+        ValueNode receiver = callTarget.receiver();
+        if (receiver != null && receiver.isConstant() && receiver.asConstant().isNull()) {
+            return "receiver is null";
+        }
+        return null;
+    }
+
+    /**
+     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
+     *
+     * @param invoke the invoke that will be replaced
+     * @param inlineGraph the graph that the invoke will be replaced with
+     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
+     *            false if no such check is required
+     */
+    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+        final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
+        FixedNode invokeNode = invoke.asNode();
+        StructuredGraph graph = invokeNode.graph();
+        assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
+        assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
+
+        FrameState stateAfter = invoke.stateAfter();
+        assert stateAfter == null || stateAfter.isAlive();
+        if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
+            nonNullReceiver(invoke);
+        }
+
+        ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
+        ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
+        UnwindNode unwindNode = null;
+        final StartNode entryPointNode = inlineGraph.start();
+        FixedNode firstCFGNode = entryPointNode.next();
+        if (firstCFGNode == null) {
+            throw new IllegalStateException("Inlined graph is in invalid state");
+        }
+        for (Node node : inlineGraph.getNodes()) {
+            if (node == entryPointNode || node == entryPointNode.stateAfter() || node instanceof ParameterNode) {
+                // Do nothing.
+            } else {
+                nodes.add(node);
+                if (node instanceof ReturnNode) {
+                    returnNodes.add((ReturnNode) node);
+                } else if (node instanceof UnwindNode) {
+                    assert unwindNode == null;
+                    unwindNode = (UnwindNode) node;
+                }
+            }
+        }
+
+        final BeginNode prevBegin = BeginNode.prevBegin(invokeNode);
+        DuplicationReplacement localReplacement = new DuplicationReplacement() {
+
+            public Node replacement(Node node) {
+                if (node instanceof ParameterNode) {
+                    return parameters.get(((ParameterNode) node).index());
+                } else if (node == entryPointNode) {
+                    return prevBegin;
+                }
+                return node;
+            }
+        };
+
+        assert invokeNode.successors().first() != null : invoke;
+        assert invokeNode.predecessor() != null;
+
+        Map<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
+        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+        invokeNode.replaceAtPredecessor(firstCFGNodeDuplicate);
+
+        FrameState stateAtExceptionEdge = null;
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
+            if (unwindNode != null) {
+                assert unwindNode.predecessor() != null;
+                assert invokeWithException.exceptionEdge().successors().count() == 1;
+                ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+                stateAtExceptionEdge = obj.stateAfter();
+                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+                obj.replaceAtUsages(unwindDuplicate.exception());
+                unwindDuplicate.clearInputs();
+                Node n = obj.next();
+                obj.setNext(null);
+                unwindDuplicate.replaceAndDelete(n);
+            } else {
+                invokeWithException.killExceptionEdge();
+            }
+
+            // get rid of memory kill
+            BeginNode begin = invokeWithException.next();
+            if (begin instanceof KillingBeginNode) {
+                BeginNode newBegin = new BeginNode();
+                graph.addAfterFixed(begin, graph.add(newBegin));
+                begin.replaceAtUsages(newBegin);
+                graph.removeFixed(begin);
+            }
+        } else {
+            if (unwindNode != null) {
+                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+                DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                unwindDuplicate.replaceAndDelete(deoptimizeNode);
+            }
+        }
+
+        if (stateAfter != null) {
+            processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge);
+            int callerLockDepth = stateAfter.nestedLockDepth();
+            if (callerLockDepth != 0) {
+                for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
+                    MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
+                    monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
+                }
+            }
+        } else {
+            assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
+        }
+        if (!returnNodes.isEmpty()) {
+            FixedNode n = invoke.next();
+            invoke.setNext(null);
+            if (returnNodes.size() == 1) {
+                ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0));
+                Node returnValue = returnNode.result();
+                invokeNode.replaceAtUsages(returnValue);
+                returnNode.clearInputs();
+                returnNode.replaceAndDelete(n);
+            } else {
+                ArrayList<ReturnNode> returnDuplicates = new ArrayList<>(returnNodes.size());
+                for (ReturnNode returnNode : returnNodes) {
+                    returnDuplicates.add((ReturnNode) duplicates.get(returnNode));
+                }
+                MergeNode merge = graph.add(new MergeNode());
+                merge.setStateAfter(stateAfter);
+                ValueNode returnValue = mergeReturns(merge, returnDuplicates);
+                invokeNode.replaceAtUsages(returnValue);
+                merge.setNext(n);
+            }
+        }
+
+        invokeNode.replaceAtUsages(null);
+        GraphUtil.killCFG(invokeNode);
+
+        return duplicates;
+    }
+
+    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge) {
+        FrameState stateAtReturn = invoke.stateAfter();
+        FrameState outerFrameState = null;
+        Kind invokeReturnKind = invoke.asNode().getKind();
+        for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+            FrameState frameState = (FrameState) duplicates.get(original);
+            if (frameState != null && frameState.isAlive()) {
+                if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+                    /*
+                     * pop return kind from invoke's stateAfter and replace with this frameState's
+                     * return value (top of stack)
+                     */
+                    FrameState stateAfterReturn = stateAtReturn;
+                    if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) {
+                        stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
+                    }
+                    frameState.replaceAndDelete(stateAfterReturn);
+                } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
+                    /*
+                     * pop exception object from invoke's stateAfter and replace with this
+                     * frameState's exception object (top of stack)
+                     */
+                    FrameState stateAfterException = stateAtExceptionEdge;
+                    if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
+                        stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0));
+                    }
+                    frameState.replaceAndDelete(stateAfterException);
+                } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+                    handleMissingAfterExceptionFrameState(frameState);
+                } else {
+                    // only handle the outermost frame states
+                    if (frameState.outerFrameState() == null) {
+                        assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
+                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
+                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
+                                        frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
+                        if (outerFrameState == null) {
+                            outerFrameState = stateAtReturn.duplicateModified(invoke.bci(), stateAtReturn.rethrowException(), invokeReturnKind);
+                            outerFrameState.setDuringCall(true);
+                        }
+                        frameState.setOuterFrameState(outerFrameState);
+                    }
+                }
+            }
+        }
+    }
+
+    private static boolean isStateAfterException(FrameState frameState) {
+        return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized());
+    }
+
+    protected static void handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
+        Graph graph = nonReplaceableFrameState.graph();
+        NodeWorkList workList = graph.createNodeWorkList();
+        workList.add(nonReplaceableFrameState);
+        for (Node node : workList) {
+            FrameState fs = (FrameState) node;
+            for (Node usage : fs.usages().snapshot()) {
+                if (!usage.isAlive()) {
+                    continue;
+                }
+                if (usage instanceof FrameState) {
+                    workList.add(usage);
+                } else {
+                    StateSplit stateSplit = (StateSplit) usage;
+                    FixedNode fixedStateSplit = stateSplit.asNode();
+                    if (fixedStateSplit instanceof MergeNode) {
+                        MergeNode merge = (MergeNode) fixedStateSplit;
+                        while (merge.isAlive()) {
+                            AbstractEndNode end = merge.forwardEnds().first();
+                            DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                            end.replaceAtPredecessor(deoptimizeNode);
+                            GraphUtil.killCFG(end);
+                        }
+                    } else {
+                        FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                        if (fixedStateSplit instanceof BeginNode) {
+                            deoptimizeNode = BeginNode.begin(deoptimizeNode);
+                        }
+                        fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
+                        GraphUtil.killCFG(fixedStateSplit);
+                    }
+                }
+            }
+        }
+    }
+
+    public static ValueNode mergeReturns(MergeNode merge, List<? extends ReturnNode> returnNodes) {
+        PhiNode returnValuePhi = null;
+
+        for (ReturnNode returnNode : returnNodes) {
+            // create and wire up a new EndNode
+            EndNode endNode = merge.graph().add(new EndNode());
+            merge.addForwardEnd(endNode);
+
+            if (returnNode.result() != null) {
+                if (returnValuePhi == null) {
+                    returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
+                }
+                returnValuePhi.addInput(returnNode.result());
+            }
+            returnNode.clearInputs();
+            returnNode.replaceAndDelete(endNode);
+
+        }
+        return returnValuePhi;
+    }
+
+    private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map<Node, Node> duplicates) {
+        for (Node node : duplicates.values()) {
+            if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+                assert frameState.bci == BytecodeFrame.AFTER_BCI || frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI : node.toString(Verbosity.Debugger);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null.
+     */
+    public static ValueNode nonNullReceiver(Invoke invoke) {
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        assert !callTarget.isStatic() : callTarget.targetMethod();
+        StructuredGraph graph = callTarget.graph();
+        ValueNode firstParam = callTarget.arguments().get(0);
+        if (firstParam.getKind() == Kind.Object && !StampTool.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));
+            graph.addBeforeFixed(invoke.asNode(), nonNullReceiver);
+            callTarget.replaceFirstInput(firstParam, nonNullReceiver);
+            return nonNullReceiver;
+        }
+        return firstParam;
+    }
+
+    public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
+        return getIntrinsicGraph(replacements, target) != null || getMacroNodeClass(replacements, target) != null;
+    }
+
+    public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
+        return replacements.getMethodSubstitution(target);
+    }
+
+    public static Class<? extends FixedWithNextNode> getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) {
+        return replacements.getMacroSubstitution(target);
+    }
+
+    public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
+        StructuredGraph graph = invoke.asNode().graph();
+        if (!concrete.equals(((MethodCallTargetNode) invoke.callTarget()).targetMethod())) {
+            assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
+            InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
+        }
+
+        FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke);
+
+        CallTargetNode callTarget = invoke.callTarget();
+        if (invoke instanceof InvokeNode) {
+            graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode));
+        } else {
+            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+            invokeWithException.killExceptionEdge();
+            graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next());
+        }
+        GraphUtil.killWithUnusedFloatingInputs(callTarget);
+        return macroNode;
+    }
+
+    private static FixedWithNextNode createMacroNodeInstance(Class<? extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalInternalError {
+        try {
+            return macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
+        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+            throw new GraalGraphInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,83 @@
+/*
+ * 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.common.inlining.info;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
+
+public abstract class AbstractInlineInfo implements InlineInfo {
+
+    protected final Invoke invoke;
+
+    public AbstractInlineInfo(Invoke invoke) {
+        this.invoke = invoke;
+    }
+
+    @Override
+    public StructuredGraph graph() {
+        return invoke.asNode().graph();
+    }
+
+    @Override
+    public Invoke invoke() {
+        return invoke;
+    }
+
+    protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
+        Collection<Node> parameterUsages = new ArrayList<>();
+        if (inlineable instanceof InlineableGraph) {
+            StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
+            Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
+            getInlinedParameterUsages(parameterUsages, calleeGraph, duplicateMap);
+        } else {
+            assert inlineable instanceof InlineableMacroNode;
+
+            Class<? extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
+            FixedWithNextNode macroNode = InliningUtil.inlineMacroNode(invoke, concrete, macroNodeClass);
+            parameterUsages.add(macroNode);
+        }
+
+        InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
+        assumptions.recordMethodContents(concrete);
+        return parameterUsages;
+    }
+
+    public static void getInlinedParameterUsages(Collection<Node> parameterUsages, StructuredGraph calleeGraph, Map<Node, Node> duplicateMap) {
+        for (ParameterNode parameter : calleeGraph.getNodes(ParameterNode.class)) {
+            for (Node usage : parameter.usages()) {
+                Node node = duplicateMap.get(usage);
+                if (node != null && node.isAlive()) {
+                    parameterUsages.add(node);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.inlining.info;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaAccessProvider;
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.util.Providers;
+import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+
+/**
+ * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
+ * target method, but for which an assumption has to be registered because of non-final classes.
+ */
+public class AssumptionInlineInfo extends ExactInlineInfo {
+
+    private final Assumption takenAssumption;
+
+    public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumption takenAssumption) {
+        super(invoke, concrete);
+        this.takenAssumption = takenAssumption;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
+        assumptions.record(takenAssumption);
+        return super.inline(providers, assumptions);
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+        assumptions.record(takenAssumption);
+        InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+    }
+
+    @Override
+    public String toString() {
+        return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.inlining.info;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaAccessProvider;
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.util.Providers;
+
+/**
+ * Represents an inlining opportunity where the compiler can statically determine a monomorphic
+ * target method and therefore is able to determine the called method exactly.
+ */
+public class ExactInlineInfo extends AbstractInlineInfo {
+
+    protected final ResolvedJavaMethod concrete;
+    private Inlineable inlineableElement;
+    private boolean suppressNullCheck;
+
+    public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
+        super(invoke);
+        this.concrete = concrete;
+        assert concrete != null;
+    }
+
+    public void suppressNullCheck() {
+        suppressNullCheck = true;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
+        return inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+        // nothing todo, can already be bound statically
+    }
+
+    @Override
+    public int numberOfMethods() {
+        return 1;
+    }
+
+    @Override
+    public ResolvedJavaMethod methodAt(int index) {
+        assert index == 0;
+        return concrete;
+    }
+
+    @Override
+    public double probabilityAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public double relevanceAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public String toString() {
+        return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
+    }
+
+    @Override
+    public Inlineable inlineableElementAt(int index) {
+        assert index == 0;
+        return inlineableElement;
+    }
+
+    @Override
+    public void setInlinableElement(int index, Inlineable inlineableElement) {
+        assert index == 0;
+        this.inlineableElement = inlineableElement;
+    }
+
+    public boolean shouldInline() {
+        return concrete.shouldBeInlined();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,85 @@
+/*
+ * 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.common.inlining.info;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaAccessProvider;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.util.Providers;
+
+/**
+ * Represents an opportunity for inlining at a given invoke, with the given weight and level. The
+ * weight is the amortized weight of the additional code - so smaller is better. The level is the
+ * number of nested inlinings that lead to this invoke.
+ */
+public interface InlineInfo {
+
+    /**
+     * The graph containing the {@link #invoke() invocation} that may be inlined.
+     */
+    StructuredGraph graph();
+
+    /**
+     * The invocation that may be inlined.
+     */
+    Invoke invoke();
+
+    /**
+     * Returns the number of methods that may be inlined by the {@link #invoke() invocation}. This
+     * may be more than one in the case of a invocation profile showing a number of "hot" concrete
+     * methods dispatched to by the invocation.
+     */
+    int numberOfMethods();
+
+    ResolvedJavaMethod methodAt(int index);
+
+    Inlineable inlineableElementAt(int index);
+
+    double probabilityAt(int index);
+
+    double relevanceAt(int index);
+
+    void setInlinableElement(int index, Inlineable inlineableElement);
+
+    /**
+     * Performs the inlining described by this object and returns the node that represents the
+     * return value of the inlined method (or null for void methods and methods that have no
+     * non-exceptional exit).
+     * 
+     * @return a collection of nodes that need to be canonicalized after the inlining
+     */
+    Collection<Node> inline(Providers providers, Assumptions assumptions);
+
+    /**
+     * Try to make the call static bindable to avoid interface and virtual method calls.
+     */
+    void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions);
+
+    boolean shouldInline();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,554 @@
+/*
+ * 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.common.inlining.info;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+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;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+
+/**
+ * Polymorphic inlining of m methods with n type checks (n &ge; m) in case that the profiling
+ * information suggests a reasonable amount of different receiver types and different methods. If an
+ * unknown type is encountered a deoptimization is triggered.
+ */
+public class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
+
+    private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
+
+    private final List<ResolvedJavaMethod> concretes;
+    private final double[] methodProbabilities;
+    private final double maximumMethodProbability;
+    private final ArrayList<Integer> typesToConcretes;
+    private final ArrayList<ProfiledType> ptypes;
+    private final ArrayList<Double> concretesProbabilities;
+    private final double notRecordedTypeProbability;
+    private final Inlineable[] inlineableElements;
+
+    public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<Double> concretesProbabilities, ArrayList<ProfiledType> ptypes,
+                    ArrayList<Integer> typesToConcretes, double notRecordedTypeProbability) {
+        super(invoke);
+        assert concretes.size() > 0 : "must have at least one method";
+        assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
+
+        this.concretesProbabilities = concretesProbabilities;
+        this.concretes = concretes;
+        this.ptypes = ptypes;
+        this.typesToConcretes = typesToConcretes;
+        this.notRecordedTypeProbability = notRecordedTypeProbability;
+        this.inlineableElements = new Inlineable[concretes.size()];
+        this.methodProbabilities = computeMethodProbabilities();
+        this.maximumMethodProbability = maximumMethodProbability();
+        assert maximumMethodProbability > 0;
+    }
+
+    private double[] computeMethodProbabilities() {
+        double[] result = new double[concretes.size()];
+        for (int i = 0; i < typesToConcretes.size(); i++) {
+            int concrete = typesToConcretes.get(i);
+            double probability = ptypes.get(i).getProbability();
+            result[concrete] += probability;
+        }
+        return result;
+    }
+
+    private double maximumMethodProbability() {
+        double max = 0;
+        for (int i = 0; i < methodProbabilities.length; i++) {
+            max = Math.max(max, methodProbabilities[i]);
+        }
+        return max;
+    }
+
+    @Override
+    public int numberOfMethods() {
+        return concretes.size();
+    }
+
+    @Override
+    public ResolvedJavaMethod methodAt(int index) {
+        assert index >= 0 && index < concretes.size();
+        return concretes.get(index);
+    }
+
+    @Override
+    public Inlineable inlineableElementAt(int index) {
+        assert index >= 0 && index < concretes.size();
+        return inlineableElements[index];
+    }
+
+    @Override
+    public double probabilityAt(int index) {
+        return methodProbabilities[index];
+    }
+
+    @Override
+    public double relevanceAt(int index) {
+        return probabilityAt(index) / maximumMethodProbability;
+    }
+
+    @Override
+    public void setInlinableElement(int index, Inlineable inlineableElement) {
+        assert index >= 0 && index < concretes.size();
+        inlineableElements[index] = inlineableElement;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
+        if (hasSingleMethod()) {
+            return inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
+        } else {
+            return inlineMultipleMethods(graph(), providers, assumptions);
+        }
+    }
+
+    public boolean shouldInline() {
+        for (ResolvedJavaMethod method : concretes) {
+            if (method.shouldBeInlined()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean hasSingleMethod() {
+        return concretes.size() == 1 && !shouldFallbackToInvoke();
+    }
+
+    private boolean shouldFallbackToInvoke() {
+        return notRecordedTypeProbability > 0;
+    }
+
+    private Collection<Node> inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
+        int numberOfMethods = concretes.size();
+        FixedNode continuation = invoke.next();
+
+        ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
+        // setup merge and phi nodes for results and exceptions
+        MergeNode returnMerge = graph.add(new MergeNode());
+        returnMerge.setStateAfter(invoke.stateAfter());
+
+        PhiNode returnValuePhi = null;
+        if (invoke.asNode().getKind() != Kind.Void) {
+            returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
+        }
+
+        MergeNode exceptionMerge = null;
+        PhiNode exceptionObjectPhi = null;
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+            ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+
+            exceptionMerge = graph.add(new MergeNode());
+
+            FixedNode exceptionSux = exceptionEdge.next();
+            graph.addBeforeFixed(exceptionSux, exceptionMerge);
+            exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(Kind.Object), exceptionMerge));
+            exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
+        }
+
+        // create one separate block for each invoked method
+        BeginNode[] successors = new BeginNode[numberOfMethods + 1];
+        for (int i = 0; i < numberOfMethods; i++) {
+            successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
+        }
+
+        // create the successor for an unknown type
+        FixedNode unknownTypeSux;
+        if (shouldFallbackToInvoke()) {
+            unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
+        } else {
+            unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
+        }
+        successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+
+        // replace the invoke exception edge
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
+            ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
+            exceptionEdge.replaceAtUsages(exceptionObjectPhi);
+            exceptionEdge.setNext(null);
+            GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
+        }
+
+        assert invoke.asNode().isAlive();
+
+        // replace the invoke with a switch on the type of the actual receiver
+        boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getMetaAccess());
+
+        assert invoke.next() == continuation;
+        invoke.setNext(null);
+        returnMerge.setNext(continuation);
+        invoke.asNode().replaceAtUsages(returnValuePhi);
+        invoke.asNode().replaceAndDelete(null);
+
+        ArrayList<GuardedValueNode> replacementNodes = new ArrayList<>();
+
+        Collection<Node> parameterUsages = new ArrayList<>();
+
+        // do the actual inlining for every invoke
+        for (int i = 0; i < numberOfMethods; i++) {
+            BeginNode node = successors[i];
+            Invoke invokeForInlining = (Invoke) node.next();
+
+            ResolvedJavaType commonType;
+            if (methodDispatch) {
+                commonType = concretes.get(i).getDeclaringClass();
+            } else {
+                commonType = getLeastCommonType(i);
+            }
+
+            ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
+            boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
+            GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, node, commonType, receiver, exact);
+            invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+            parameterUsages.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false));
+
+            replacementNodes.add(anchoredReceiver);
+        }
+        if (shouldFallbackToInvoke()) {
+            replacementNodes.add(null);
+        }
+
+        if (OptTailDuplication.getValue()) {
+            /*
+             * We might want to perform tail duplication at the merge after a type switch, if there
+             * are invokes that would benefit from the improvement in type information.
+             */
+            FixedNode current = returnMerge;
+            int opportunities = 0;
+            do {
+                if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode &&
+                                ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) {
+                    opportunities++;
+                } else if (current.inputs().contains(originalReceiver)) {
+                    opportunities++;
+                }
+                current = ((FixedWithNextNode) current).next();
+            } while (current instanceof FixedWithNextNode);
+
+            if (opportunities > 0) {
+                metricInliningTailDuplication.increment();
+                Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
+                PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+                CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
+                TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
+            }
+        }
+        return parameterUsages;
+    }
+
+    private int getTypeCount(int concreteMethodIndex) {
+        int count = 0;
+        for (int i = 0; i < typesToConcretes.size(); i++) {
+            if (typesToConcretes.get(i) == concreteMethodIndex) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
+        ResolvedJavaType commonType = null;
+        for (int i = 0; i < typesToConcretes.size(); i++) {
+            if (typesToConcretes.get(i) == concreteMethodIndex) {
+                if (commonType == null) {
+                    commonType = ptypes.get(i).getType();
+                } else {
+                    commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
+                }
+            }
+        }
+        assert commonType != null;
+        return commonType;
+    }
+
+    private ResolvedJavaType getLeastCommonType() {
+        ResolvedJavaType result = getLeastCommonType(0);
+        for (int i = 1; i < concretes.size(); i++) {
+            result = result.findLeastCommonAncestor(getLeastCommonType(i));
+        }
+        return result;
+    }
+
+    private Collection<Node> inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
+        assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+
+        BeginNode calleeEntryNode = graph.add(new BeginNode());
+
+        BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+        BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
+        createDispatchOnTypeBeforeInvoke(graph, successors, false, metaAccess);
+
+        calleeEntryNode.setNext(invoke.asNode());
+
+        return inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
+    }
+
+    private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess) {
+        assert ptypes.size() >= 1;
+        ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+        Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(ResolvedJavaType.Representation.ObjectHub).getKind();
+        LoadHubNode hub = graph.unique(new LoadHubNode(nonNullReceiver, hubKind));
+
+        if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
+            assert successors.length == concretes.size() + 1;
+            assert concretes.size() > 0;
+            Debug.log("Method check cascade with %d methods", concretes.size());
+
+            ConstantNode[] constantMethods = new ConstantNode[concretes.size()];
+            double[] probability = new double[concretes.size()];
+            for (int i = 0; i < concretes.size(); ++i) {
+                ResolvedJavaMethod firstMethod = concretes.get(i);
+                Constant firstMethodConstant = firstMethod.getEncoding();
+
+                ConstantNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
+                constantMethods[i] = firstMethodConstantNode;
+                double concretesProbability = concretesProbabilities.get(i);
+                assert concretesProbability >= 0.0;
+                probability[i] = concretesProbability;
+                if (i > 0) {
+                    double prevProbability = probability[i - 1];
+                    if (prevProbability == 1.0) {
+                        probability[i] = 1.0;
+                    } else {
+                        probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
+                    }
+                }
+            }
+
+            ResolvedJavaType receiverType = invoke.getReceiverType();
+            FixedNode lastSucc = successors[concretes.size()];
+            for (int i = concretes.size() - 1; i >= 0; --i) {
+                LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), receiverType, 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);
+                lastSucc = method;
+            }
+
+            FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+            pred.setNext(lastSucc);
+            return true;
+        } else {
+            Debug.log("Type switch with %d types", concretes.size());
+        }
+
+        ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
+        double[] keyProbabilities = new double[ptypes.size() + 1];
+        int[] keySuccessors = new int[ptypes.size() + 1];
+        for (int i = 0; i < ptypes.size(); i++) {
+            keys[i] = ptypes.get(i).getType();
+            keyProbabilities[i] = ptypes.get(i).getProbability();
+            keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
+            assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
+        }
+        keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
+        keySuccessors[keySuccessors.length - 1] = successors.length - 1;
+
+        TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
+        FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+        pred.setNext(typeSwitch);
+        return false;
+    }
+
+    private boolean chooseMethodDispatch() {
+        ResolvedJavaType receiverType = invoke.getReceiverType();
+        for (ResolvedJavaMethod concrete : concretes) {
+            if (!concrete.isInVirtualMethodTable(receiverType)) {
+                return false;
+            }
+        }
+
+        if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
+            // Always chose method dispatch if there is a single concrete method and the call
+            // site is megamorphic.
+            return true;
+        }
+
+        if (concretes.size() == ptypes.size()) {
+            // Always prefer types over methods if the number of types is smaller than the
+            // number of methods.
+            return false;
+        }
+
+        return chooseMethodDispatchCostBased();
+    }
+
+    private boolean chooseMethodDispatchCostBased() {
+        double remainder = 1.0 - this.notRecordedTypeProbability;
+        double costEstimateMethodDispatch = remainder;
+        for (int i = 0; i < concretes.size(); ++i) {
+            if (i != 0) {
+                costEstimateMethodDispatch += remainder;
+            }
+            remainder -= concretesProbabilities.get(i);
+        }
+
+        double costEstimateTypeDispatch = 0.0;
+        remainder = 1.0;
+        for (int i = 0; i < ptypes.size(); ++i) {
+            if (i != 0) {
+                costEstimateTypeDispatch += remainder;
+            }
+            remainder -= ptypes.get(i).getProbability();
+        }
+        costEstimateTypeDispatch += notRecordedTypeProbability;
+        return costEstimateMethodDispatch < costEstimateTypeDispatch;
+    }
+
+    private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
+                    boolean useForInlining) {
+        Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
+        BeginNode calleeEntryNode = graph.add(new BeginNode());
+        calleeEntryNode.setNext(duplicatedInvoke.asNode());
+
+        AbstractEndNode endNode = graph.add(new EndNode());
+        duplicatedInvoke.setNext(endNode);
+        returnMerge.addForwardEnd(endNode);
+
+        if (returnValuePhi != null) {
+            returnValuePhi.addInput(duplicatedInvoke.asNode());
+        }
+        return calleeEntryNode;
+    }
+
+    private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
+        Invoke result = (Invoke) invoke.asNode().copyWithInputs();
+        Node callTarget = result.callTarget().copyWithInputs();
+        result.asNode().replaceFirstInput(result.callTarget(), callTarget);
+        result.setUseForInlining(useForInlining);
+
+        Kind kind = invoke.asNode().getKind();
+        if (kind != Kind.Void) {
+            FrameState stateAfter = invoke.stateAfter();
+            stateAfter = stateAfter.duplicate(stateAfter.bci);
+            stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
+            result.setStateAfter(stateAfter);
+        }
+
+        if (invoke instanceof InvokeWithExceptionNode) {
+            assert exceptionMerge != null && exceptionObjectPhi != null;
+
+            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+            ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+            FrameState stateAfterException = exceptionEdge.stateAfter();
+
+            ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
+            // set new state (pop old exception object, push new one)
+            newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
+
+            AbstractEndNode endNode = graph.add(new EndNode());
+            newExceptionEdge.setNext(endNode);
+            exceptionMerge.addForwardEnd(endNode);
+            exceptionObjectPhi.addInput(newExceptionEdge);
+
+            ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
+        }
+        return result;
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+        if (hasSingleMethod()) {
+            devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), metaAccess);
+        } else {
+            tryToDevirtualizeMultipleMethods(graph(), metaAccess);
+        }
+    }
+
+    private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider metaAccess) {
+        MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
+        if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
+            ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
+            ResolvedJavaType leastCommonType = getLeastCommonType();
+            ResolvedJavaType contextType = invoke.getContextType();
+            // check if we have a common base type that implements the interface -> in that case
+            // we have a vtable entry for the interface method and can use a less expensive
+            // virtual call
+            if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
+                ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod, contextType);
+                if (baseClassTargetMethod != null) {
+                    devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod, contextType), metaAccess);
+                }
+            }
+        }
+    }
+
+    private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider metaAccess) {
+        BeginNode invocationEntry = graph.add(new BeginNode());
+        BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+        BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
+        createDispatchOnTypeBeforeInvoke(graph, successors, true, metaAccess);
+
+        invocationEntry.setNext(invoke.asNode());
+        ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
+        GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
+        invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+        InliningUtil.replaceInvokeCallTarget(invoke, graph, kind, target);
+    }
+
+    private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
+        return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
+        builder.append(", ");
+        builder.append(concretes.size());
+        builder.append(" methods [ ");
+        for (int i = 0; i < concretes.size(); i++) {
+            builder.append(MetaUtil.format("  %H.%n(%p):%r", concretes.get(i)));
+        }
+        builder.append(" ], ");
+        builder.append(ptypes.size());
+        builder.append(" type checks [ ");
+        for (int i = 0; i < ptypes.size(); i++) {
+            builder.append("  ");
+            builder.append(ptypes.get(i).getType().getName());
+            builder.append(ptypes.get(i).getProbability());
+        }
+        builder.append(" ]");
+        return builder.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,127 @@
+/*
+ * 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.common.inlining.info;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.CompareNode;
+import com.oracle.graal.nodes.extended.LoadHubNode;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.util.Providers;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+
+/**
+ * Represents an inlining opportunity for which profiling information suggests a monomorphic
+ * receiver, but for which the receiver type cannot be proven. A type check guard will be generated
+ * if this inlining is performed.
+ */
+public class TypeGuardInlineInfo extends AbstractInlineInfo {
+
+    private final ResolvedJavaMethod concrete;
+    private final ResolvedJavaType type;
+    private Inlineable inlineableElement;
+
+    public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
+        super(invoke);
+        this.concrete = concrete;
+        this.type = type;
+        assert type.isArray() || !type.isAbstract() : type;
+    }
+
+    @Override
+    public int numberOfMethods() {
+        return 1;
+    }
+
+    @Override
+    public ResolvedJavaMethod methodAt(int index) {
+        assert index == 0;
+        return concrete;
+    }
+
+    @Override
+    public Inlineable inlineableElementAt(int index) {
+        assert index == 0;
+        return inlineableElement;
+    }
+
+    @Override
+    public double probabilityAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public double relevanceAt(int index) {
+        assert index == 0;
+        return 1.0;
+    }
+
+    @Override
+    public void setInlinableElement(int index, Inlineable inlineableElement) {
+        assert index == 0;
+        this.inlineableElement = inlineableElement;
+    }
+
+    @Override
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
+        createGuard(graph(), providers.getMetaAccess());
+        return inline(invoke, concrete, inlineableElement, assumptions, false);
+    }
+
+    @Override
+    public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+        createGuard(graph(), metaAccess);
+        InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+    }
+
+    private void createGuard(StructuredGraph graph, MetaAccessProvider metaAccess) {
+        ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+        ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(ResolvedJavaType.Representation.ObjectHub), metaAccess, graph);
+        LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.getKind()));
+
+        CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
+        FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+        assert invoke.predecessor() != null;
+
+        ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
+        invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
+
+        graph.addBeforeFixed(invoke.asNode(), guard);
+    }
+
+    @Override
+    public String toString() {
+        return "type-checked with type " + type.getName() + " and method " + MetaUtil.format("%H.%n(%p):%r", concrete);
+    }
+
+    public boolean shouldInline() {
+        return concrete.shouldBeInlined();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.inlining.info.elem;
+
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.tiers.HighTierContext;
+
+public interface Inlineable {
+
+    static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+        Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
+        if (macroNodeClass != null) {
+            return new InlineableMacroNode(macroNodeClass);
+        } else {
+            return new InlineableGraph(method, invoke, context, canonicalizer);
+        }
+    }
+
+    int getNodeCount();
+
+    Iterable<Invoke> getInvokes();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,155 @@
+/*
+ * 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.inlining.info.elem;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.Constant;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.tiers.HighTierContext;
+
+import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
+
+public class InlineableGraph implements Inlineable {
+
+    private final StructuredGraph graph;
+
+    public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
+        this.graph = buildGraph(method, invoke, context, canonicalizer);
+    }
+
+    private static StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
+        final StructuredGraph newGraph;
+        final boolean parseBytecodes;
+
+        // TODO (chaeubl): copying the graph is only necessary if it is modified or if it contains
+        // any invokes
+        StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
+        if (intrinsicGraph != null) {
+            newGraph = intrinsicGraph.copy();
+            parseBytecodes = false;
+        } else {
+            StructuredGraph cachedGraph = getCachedGraph(method, context);
+            if (cachedGraph != null) {
+                newGraph = cachedGraph.copy();
+                parseBytecodes = false;
+            } else {
+                newGraph = new StructuredGraph(method);
+                parseBytecodes = true;
+            }
+        }
+
+        try (Debug.Scope s = Debug.scope("InlineGraph", newGraph)) {
+            if (parseBytecodes) {
+                parseBytecodes(newGraph, context, canonicalizer);
+            }
+
+            boolean callerHasMoreInformationAboutArguments = false;
+            NodeInputList<ValueNode> args = invoke.callTarget().arguments();
+            ArrayList<Node> parameterUsages = new ArrayList<>();
+            for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) {
+                ValueNode arg = args.get(param.index());
+                if (arg.isConstant()) {
+                    Constant constant = arg.asConstant();
+                    newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
+                    callerHasMoreInformationAboutArguments = true;
+                    param.usages().snapshotTo(parameterUsages);
+                } else {
+                    Stamp joinedStamp = param.stamp().join(arg.stamp());
+                    if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
+                        param.setStamp(joinedStamp);
+                        callerHasMoreInformationAboutArguments = true;
+                        param.usages().snapshotTo(parameterUsages);
+                    }
+                }
+            }
+
+            if (callerHasMoreInformationAboutArguments) {
+                if (OptCanonicalizer.getValue()) {
+                    canonicalizer.applyIncremental(newGraph, context, parameterUsages);
+                }
+            } else {
+                // TODO (chaeubl): if args are not more concrete, inlining should be avoided
+                // in most cases or we could at least use the previous graph size + invoke
+                // probability to check the inlining
+            }
+
+            return newGraph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) {
+        if (context.getGraphCache() != null) {
+            StructuredGraph cachedGraph = context.getGraphCache().get(method);
+            if (cachedGraph != null) {
+                return cachedGraph;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method builds the IR nodes for <code>newGraph</code> and canonicalizes them. Provided
+     * profiling info is mature, the resulting graph is cached.
+     */
+    private static StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context, CanonicalizerPhase canonicalizer) {
+        if (context.getGraphBuilderSuite() != null) {
+            context.getGraphBuilderSuite().apply(newGraph, context);
+        }
+        assert newGraph.start().next() != null : "graph needs to be populated the GraphBuilderSuite";
+
+        new DeadCodeEliminationPhase().apply(newGraph);
+
+        if (OptCanonicalizer.getValue()) {
+            canonicalizer.apply(newGraph, context);
+        }
+
+        if (context.getGraphCache() != null) {
+            context.getGraphCache().put(newGraph.method(), newGraph.copy());
+        }
+        return newGraph;
+    }
+
+    @Override
+    public int getNodeCount() {
+        return graph.getNodeCount();
+    }
+
+    @Override
+    public Iterable<Invoke> getInvokes() {
+        return graph.getInvokes();
+    }
+
+    public StructuredGraph getGraph() {
+        return graph;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * 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.inlining.info.elem;
+
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.Invoke;
+
+import java.util.Collections;
+
+public class InlineableMacroNode implements Inlineable {
+
+    private final Class<? extends FixedWithNextNode> macroNodeClass;
+
+    public InlineableMacroNode(Class<? extends FixedWithNextNode> macroNodeClass) {
+        this.macroNodeClass = macroNodeClass;
+    }
+
+    @Override
+    public int getNodeCount() {
+        return 1;
+    }
+
+    @Override
+    public Iterable<Invoke> getInvokes() {
+        return Collections.emptyList();
+    }
+
+    public Class<? extends FixedWithNextNode> getMacroNodeClass() {
+        return macroNodeClass;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,127 @@
+/*
+ * 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.phases.common.inlining.policy;
+
+import com.oracle.graal.api.meta.ProfilingInfo;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+
+import java.util.Map;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.RelevanceCapForInlining;
+import static com.oracle.graal.phases.common.inlining.InliningPhase.Options.AlwaysInlineIntrinsics;
+
+public abstract class AbstractInliningPolicy implements InliningPolicy {
+
+    protected final Map<Invoke, Double> hints;
+
+    public AbstractInliningPolicy(Map<Invoke, Double> hints) {
+        this.hints = hints;
+    }
+
+    protected double computeMaximumSize(double relevance, int configuredMaximum) {
+        double inlineRatio = Math.min(RelevanceCapForInlining.getValue(), relevance);
+        return configuredMaximum * inlineRatio;
+    }
+
+    protected double getInliningBonus(InlineInfo info) {
+        if (hints != null && hints.containsKey(info.invoke())) {
+            return hints.get(info.invoke());
+        }
+        return 1;
+    }
+
+    protected boolean isIntrinsic(Replacements replacements, InlineInfo info) {
+        if (AlwaysInlineIntrinsics.getValue()) {
+            return onlyIntrinsics(replacements, info);
+        } else {
+            return onlyForcedIntrinsics(replacements, info);
+        }
+    }
+
+    private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+                return false;
+            }
+            if (!replacements.isForcedSubstitution(info.methodAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected static int previousLowLevelGraphSize(InlineInfo info) {
+        int size = 0;
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            ResolvedJavaMethod m = info.methodAt(i);
+            ProfilingInfo profile = m.getProfilingInfo();
+            int compiledGraphSize = profile.getCompilerIRSize(StructuredGraph.class);
+            if (compiledGraphSize > 0) {
+                size += compiledGraphSize;
+            }
+        }
+        return size;
+    }
+
+    protected static int determineNodeCount(InlineInfo info) {
+        int nodes = 0;
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            Inlineable elem = info.inlineableElementAt(i);
+            if (elem != null) {
+                nodes += elem.getNodeCount();
+            }
+        }
+        return nodes;
+    }
+
+    protected static double determineInvokeProbability(ToDoubleFunction<FixedNode> probabilities, InlineInfo info) {
+        double invokeProbability = 0;
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            Inlineable callee = info.inlineableElementAt(i);
+            Iterable<Invoke> invokes = callee.getInvokes();
+            if (invokes.iterator().hasNext()) {
+                for (Invoke invoke : invokes) {
+                    invokeProbability += probabilities.applyAsDouble(invoke.asNode());
+                }
+            }
+        }
+        return invokeProbability;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,112 @@
+/*
+ * 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.phases.common.inlining.policy;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+import java.util.Map;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+public class GreedyInliningPolicy extends AbstractInliningPolicy {
+
+    private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
+
+    public GreedyInliningPolicy(Map<Invoke, Double> hints) {
+        super(hints);
+    }
+
+    public boolean continueInlining(StructuredGraph currentGraph) {
+        if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+            InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
+            metricInliningStoppedByMaxDesiredSize.increment();
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
+                    boolean fullyProcessed) {
+        if (InlineEverything.getValue()) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
+            return true;
+        }
+
+        if (isIntrinsic(replacements, info)) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
+            return true;
+        }
+
+        if (info.shouldInline()) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
+            return true;
+        }
+
+        double inliningBonus = getInliningBonus(info);
+        int nodes = determineNodeCount(info);
+        int lowLevelGraphSize = previousLowLevelGraphSize(info);
+
+        if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
+            InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize,
+                            relevance, probability, inliningBonus, nodes);
+            return false;
+        }
+
+        if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
+            return true;
+        }
+
+        /*
+         * TODO (chaeubl): invoked methods that are on important paths but not yet compiled -> will
+         * be compiled anyways and it is likely that we are the only caller... might be useful to
+         * inline those methods but increases bootstrap time (maybe those methods are also getting
+         * queued in the compilation queue concurrently)
+         */
+        double invokes = determineInvokeProbability(probabilities, info);
+        if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) {
+            InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance,
+                            probability, inliningBonus, nodes);
+            return false;
+        }
+
+        double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus));
+        if (nodes <= maximumNodes) {
+            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
+                            nodes, maximumNodes);
+            return true;
+        }
+
+        InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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.phases.common.inlining.policy;
+
+import com.oracle.graal.api.code.BailoutException;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize;
+
+public final class InlineEverythingPolicy implements InliningPolicy {
+
+    public boolean continueInlining(StructuredGraph graph) {
+        if (graph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+            throw new BailoutException("Inline all calls failed. The resulting graph is too large.");
+        }
+        return true;
+    }
+
+    public boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
+                    boolean fullyProcessed) {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.phases.common.inlining.policy;
+
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.Replacements;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+import java.util.function.ToDoubleFunction;
+
+public interface InliningPolicy {
+
+    boolean continueInlining(StructuredGraph graph);
+
+    boolean isWorthInlining(ToDoubleFunction<FixedNode> probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolder.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,126 @@
+/*
+ * 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.phases.common.inlining.walker;
+
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.CapInheritedRelevance;
+
+/**
+ * Information about a graph that will potentially be inlined. This includes tracking the
+ * invocations in graph that will subject to inlining themselves.
+ */
+public class CallsiteHolder {
+
+    private final StructuredGraph graph;
+    private final LinkedList<Invoke> remainingInvokes;
+    private final double probability;
+    private final double relevance;
+
+    private final ToDoubleFunction<FixedNode> probabilities;
+    private final ComputeInliningRelevance computeInliningRelevance;
+
+    public CallsiteHolder(StructuredGraph graph, double probability, double relevance) {
+        this.graph = graph;
+        this.probability = probability;
+        this.relevance = relevance;
+        if (graph == null) {
+            remainingInvokes = new LinkedList<>();
+            probabilities = null;
+            computeInliningRelevance = null;
+        } else {
+            remainingInvokes = new InliningIterator(graph).apply();
+            assert remainingInvokes.size() == count(graph.getInvokes());
+            if (remainingInvokes.isEmpty()) {
+                probabilities = null;
+                computeInliningRelevance = null;
+            } else {
+                probabilities = new FixedNodeProbabilityCache();
+                computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
+                computeProbabilities();
+            }
+        }
+    }
+
+    private static int count(Iterable<Invoke> invokes) {
+        int count = 0;
+        Iterator<Invoke> iterator = invokes.iterator();
+        while (iterator.hasNext()) {
+            iterator.next();
+            count++;
+        }
+        return count;
+    }
+
+    /**
+     * Gets the method associated with the {@linkplain #graph() graph} represented by this object.
+     */
+    public ResolvedJavaMethod method() {
+        return graph == null ? null : graph.method();
+    }
+
+    public boolean hasRemainingInvokes() {
+        return !remainingInvokes.isEmpty();
+    }
+
+    /**
+     * The graph about which this object contains inlining information.
+     */
+    public StructuredGraph graph() {
+        return graph;
+    }
+
+    public Invoke popInvoke() {
+        return remainingInvokes.removeFirst();
+    }
+
+    public void pushInvoke(Invoke invoke) {
+        remainingInvokes.push(invoke);
+    }
+
+    public void computeProbabilities() {
+        computeInliningRelevance.compute();
+    }
+
+    public double invokeProbability(Invoke invoke) {
+        return probability * probabilities.applyAsDouble(invoke.asNode());
+    }
+
+    public double invokeRelevance(Invoke invoke) {
+        return Math.min(CapInheritedRelevance.getValue(), relevance) * computeInliningRelevance.getRelevance(invoke);
+    }
+
+    @Override
+    public String toString() {
+        return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "<null method>") + remainingInvokes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,324 @@
+/*
+ * 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.common.inlining.walker;
+
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+import edu.umd.cs.findbugs.annotations.*;
+
+public class ComputeInliningRelevance {
+
+    private static final double EPSILON = 1d / Integer.MAX_VALUE;
+    private static final double UNINITIALIZED = -1D;
+
+    private static final int EXPECTED_MIN_INVOKE_COUNT = 3;
+    private static final int EXPECTED_INVOKE_RATIO = 20;
+    private static final int EXPECTED_LOOP_COUNT = 3;
+
+    private final StructuredGraph graph;
+    private final ToDoubleFunction<FixedNode> nodeProbabilities;
+
+    /**
+     * Node relevances are pre-computed for all invokes if the graph contains loops. If there are no
+     * loops, the computation happens lazily based on {@link #rootScope}.
+     */
+    private Map<FixedNode, Double> nodeRelevances;
+    /**
+     * This scope is non-null if (and only if) there are no loops in the graph. In this case, the
+     * root scope is used to compute invoke relevances on the fly.
+     */
+    private Scope rootScope;
+
+    public ComputeInliningRelevance(StructuredGraph graph, ToDoubleFunction<FixedNode> nodeProbabilities) {
+        this.graph = graph;
+        this.nodeProbabilities = nodeProbabilities;
+    }
+
+    /**
+     * Initializes or updates the relevance computation. If there are no loops within the graph,
+     * most computation happens lazily.
+     */
+    public void compute() {
+        rootScope = null;
+        if (!graph.hasLoops()) {
+            // fast path for the frequent case of no loops
+            rootScope = new Scope(graph.start(), null);
+        } else {
+            if (nodeRelevances == null) {
+                nodeRelevances = newNodeIdentityMap(EXPECTED_MIN_INVOKE_COUNT + graph.getNodeCount() / EXPECTED_INVOKE_RATIO);
+            }
+            NodeWorkList workList = graph.createNodeWorkList();
+            Map<LoopBeginNode, Scope> loops = newNodeIdentityMap(EXPECTED_LOOP_COUNT);
+
+            loops.put(null, new Scope(graph.start(), null));
+            for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) {
+                createLoopScope(loopBegin, loops);
+            }
+
+            for (Scope scope : loops.values()) {
+                scope.process(workList);
+            }
+        }
+    }
+
+    public double getRelevance(Invoke invoke) {
+        if (rootScope != null) {
+            return rootScope.computeInvokeRelevance(invoke);
+        }
+        assert nodeRelevances != null : "uninitialized relevance";
+        return nodeRelevances.get(invoke);
+    }
+
+    /**
+     * Determines the parent of the given loop and creates a {@link Scope} object for each one. This
+     * method will call itself recursively if no {@link Scope} for the parent loop exists.
+     */
+    private Scope createLoopScope(LoopBeginNode loopBegin, Map<LoopBeginNode, Scope> loops) {
+        Scope scope = loops.get(loopBegin);
+        if (scope == null) {
+            final Scope parent;
+            // look for the parent scope
+            FixedNode current = loopBegin.forwardEnd();
+            while (true) {
+                if (current.predecessor() == null) {
+                    if (current instanceof LoopBeginNode) {
+                        // if we reach a LoopBeginNode then we're within this loop
+                        parent = createLoopScope((LoopBeginNode) current, loops);
+                        break;
+                    } else if (current instanceof StartNode) {
+                        // we're within the outermost scope
+                        parent = loops.get(null);
+                        break;
+                    } else {
+                        assert current.getClass() == MergeNode.class : current;
+                        // follow any path upwards - it doesn't matter which one
+                        current = ((MergeNode) current).forwardEndAt(0);
+                    }
+                } else if (current instanceof LoopExitNode) {
+                    // if we reach a loop exit then we follow this loop and have the same parent
+                    parent = createLoopScope(((LoopExitNode) current).loopBegin(), loops).parent;
+                    break;
+                } else {
+                    current = (FixedNode) current.predecessor();
+                }
+            }
+            scope = new Scope(loopBegin, parent);
+            loops.put(loopBegin, scope);
+        }
+        return scope;
+    }
+
+    /**
+     * A scope holds information for the contents of one loop or of the root of the method. It does
+     * not include child loops, i.e., the iteration in {@link #process(NodeWorkList)} explicitly
+     * excludes the nodes of child loops.
+     */
+    private class Scope {
+        public final FixedNode start;
+        public final Scope parent; // can be null for the outermost scope
+
+        /**
+         * The minimum probability along the most probable path in this scope. Computed lazily.
+         */
+        private double fastPathMinProbability = UNINITIALIZED;
+        /**
+         * A measure of how important this scope is within its parent scope. Computed lazily.
+         */
+        private double scopeRelevanceWithinParent = UNINITIALIZED;
+
+        public Scope(FixedNode start, Scope parent) {
+            this.start = start;
+            this.parent = parent;
+        }
+
+        @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
+        public double getFastPathMinProbability() {
+            if (fastPathMinProbability == UNINITIALIZED) {
+                fastPathMinProbability = Math.max(EPSILON, computeFastPathMinProbability(start));
+            }
+            return fastPathMinProbability;
+        }
+
+        /**
+         * Computes the ratio between the probabilities of the current scope's entry point and the
+         * parent scope's fastPathMinProbability.
+         */
+        @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
+        public double getScopeRelevanceWithinParent() {
+            if (scopeRelevanceWithinParent == UNINITIALIZED) {
+                if (start instanceof LoopBeginNode) {
+                    assert parent != null;
+                    double scopeEntryProbability = nodeProbabilities.applyAsDouble(((LoopBeginNode) start).forwardEnd());
+
+                    scopeRelevanceWithinParent = scopeEntryProbability / parent.getFastPathMinProbability();
+                } else {
+                    scopeRelevanceWithinParent = 1D;
+                }
+            }
+            return scopeRelevanceWithinParent;
+        }
+
+        /**
+         * Processes all invokes in this scope by starting at the scope's start node and iterating
+         * all fixed nodes. Child loops are skipped by going from loop entries directly to the loop
+         * exits. Processing stops at loop exits of the current loop.
+         */
+        public void process(NodeWorkList workList) {
+            assert !(start instanceof Invoke);
+            workList.addAll(start.successors());
+
+            for (Node current : workList) {
+                assert current.isAlive();
+
+                if (current instanceof Invoke) {
+                    // process the invoke and queue its successors
+                    nodeRelevances.put((FixedNode) current, computeInvokeRelevance((Invoke) current));
+                    workList.addAll(current.successors());
+                } else if (current instanceof LoopBeginNode) {
+                    // skip child loops by advancing over the loop exits
+                    ((LoopBeginNode) current).loopExits().forEach(exit -> workList.add(exit.next()));
+                } else if (current instanceof LoopEndNode) {
+                    // nothing to do
+                } else if (current instanceof LoopExitNode) {
+                    // nothing to do
+                } else if (current instanceof FixedWithNextNode) {
+                    workList.add(((FixedWithNextNode) current).next());
+                } else if (current instanceof EndNode) {
+                    workList.add(((EndNode) current).merge());
+                } else if (current instanceof ControlSinkNode) {
+                    // nothing to do
+                } else if (current instanceof ControlSplitNode) {
+                    workList.addAll(current.successors());
+                } else {
+                    assert false : current;
+                }
+            }
+        }
+
+        /**
+         * The relevance of an invoke is the ratio between the invoke's probability and the current
+         * scope's fastPathMinProbability, adjusted by scopeRelevanceWithinParent.
+         */
+        public double computeInvokeRelevance(Invoke invoke) {
+            double invokeProbability = nodeProbabilities.applyAsDouble(invoke.asNode());
+            assert !Double.isNaN(invokeProbability);
+
+            double relevance = (invokeProbability / getFastPathMinProbability()) * Math.min(1.0, getScopeRelevanceWithinParent());
+            assert !Double.isNaN(relevance) : invoke + ": " + relevance + " / " + invokeProbability + " / " + getFastPathMinProbability() + " / " + getScopeRelevanceWithinParent();
+            return relevance;
+        }
+    }
+
+    /**
+     * Computes the minimum probability along the most probable path within the scope. During
+     * iteration, the method returns immediately once a loop exit is discovered.
+     */
+    private double computeFastPathMinProbability(FixedNode scopeStart) {
+        ArrayList<FixedNode> pathBeginNodes = new ArrayList<>();
+        pathBeginNodes.add(scopeStart);
+        double minPathProbability = nodeProbabilities.applyAsDouble(scopeStart);
+        boolean isLoopScope = scopeStart instanceof LoopBeginNode;
+
+        do {
+            Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
+            do {
+                if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
+                    return minPathProbability;
+                } else if (current instanceof LoopBeginNode && current != scopeStart) {
+                    current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
+                    minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+                } else if (current instanceof ControlSplitNode) {
+                    current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
+                    minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+                } else {
+                    assert current.successors().count() <= 1;
+                    current = current.successors().first();
+                }
+            } while (current != null);
+        } while (!pathBeginNodes.isEmpty());
+
+        return minPathProbability;
+    }
+
+    private double getMinPathProbability(FixedNode current, double minPathProbability) {
+        return current == null ? minPathProbability : Math.min(minPathProbability, nodeProbabilities.applyAsDouble(current));
+    }
+
+    /**
+     * Returns the most probable successor. If multiple successors share the maximum probability,
+     * one is returned and the others are enqueued in pathBeginNodes.
+     */
+    private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList<FixedNode> pathBeginNodes) {
+        Node maxSux = null;
+        double maxProbability = 0.0;
+        int pathBeginCount = pathBeginNodes.size();
+
+        for (Node sux : controlSplit.successors()) {
+            double probability = controlSplit.probability((BeginNode) sux);
+            if (probability > maxProbability) {
+                maxProbability = probability;
+                maxSux = sux;
+                truncate(pathBeginNodes, pathBeginCount);
+            } else if (probability == maxProbability) {
+                pathBeginNodes.add((FixedNode) sux);
+            }
+        }
+
+        return maxSux;
+    }
+
+    /**
+     * Returns the most probable loop exit. If multiple successors share the maximum probability,
+     * one is returned and the others are enqueued in pathBeginNodes.
+     */
+    private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList<FixedNode> pathBeginNodes) {
+        Node maxSux = null;
+        double maxProbability = 0.0;
+        int pathBeginCount = pathBeginNodes.size();
+
+        for (LoopExitNode sux : loopBegin.loopExits()) {
+            double probability = nodeProbabilities.applyAsDouble(sux);
+            if (probability > maxProbability) {
+                maxProbability = probability;
+                maxSux = sux;
+                truncate(pathBeginNodes, pathBeginCount);
+            } else if (probability == maxProbability) {
+                pathBeginNodes.add(sux);
+            }
+        }
+
+        return maxSux;
+    }
+
+    private static void truncate(ArrayList<FixedNode> pathBeginNodes, int pathBeginCount) {
+        for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
+            pathBeginNodes.remove(pathBeginNodes.size() - 1);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,599 @@
+/*
+ * 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.phases.common.inlining.walker;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.code.BailoutException;
+import com.oracle.graal.api.meta.JavaTypeProfile;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.compiler.common.GraalInternalError;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Graph;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.phases.OptimisticOptimizations;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.*;
+import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
+import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
+import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
+import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
+import com.oracle.graal.phases.tiers.HighTierContext;
+import com.oracle.graal.phases.util.Providers;
+
+import java.util.*;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+/**
+ * Holds the data for building the callee graphs recursively: graphs and invocations (each
+ * invocation can have multiple graphs).
+ */
+public class InliningData {
+
+    private static final CallsiteHolder DUMMY_CALLSITE_HOLDER = new CallsiteHolder(null, 1.0, 1.0);
+    // Metrics
+    private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
+    private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
+    private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
+
+    /**
+     * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
+     */
+    private final ArrayDeque<CallsiteHolder> graphQueue = new ArrayDeque<>();
+    private final ArrayDeque<MethodInvocation> invocationQueue = new ArrayDeque<>();
+    private final ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
+
+    private final HighTierContext context;
+    private final int maxMethodPerInlining;
+    private final CanonicalizerPhase canonicalizer;
+    private final InliningPolicy inliningPolicy;
+
+    private int maxGraphs;
+
+    public InliningData(StructuredGraph rootGraph, HighTierContext context, int maxMethodPerInlining, CanonicalizerPhase canonicalizer, InliningPolicy inliningPolicy) {
+        assert rootGraph != null;
+        this.context = context;
+        this.maxMethodPerInlining = maxMethodPerInlining;
+        this.canonicalizer = canonicalizer;
+        this.inliningPolicy = inliningPolicy;
+        this.maxGraphs = 1;
+
+        Assumptions rootAssumptions = context.getAssumptions();
+        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
+        pushGraph(rootGraph, 1.0, 1.0);
+    }
+
+    private String checkTargetConditionsHelper(ResolvedJavaMethod method) {
+        if (method == null) {
+            return "the method is not resolved";
+        } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(context.getReplacements(), method))) {
+            return "it is a non-intrinsic native method";
+        } else if (method.isAbstract()) {
+            return "it is an abstract method";
+        } else if (!method.getDeclaringClass().isInitialized()) {
+            return "the method's class is not initialized";
+        } else if (!method.canBeInlined()) {
+            return "it is marked non-inlinable";
+        } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
+            return "it exceeds the maximum recursive inlining depth";
+        } else if (new OptimisticOptimizations(method.getProfilingInfo()).lessOptimisticThan(context.getOptimisticOptimizations())) {
+            return "the callee uses less optimistic optimizations than caller";
+        } else {
+            return null;
+        }
+    }
+
+    private boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method) {
+        final String failureMessage = checkTargetConditionsHelper(method);
+        if (failureMessage == null) {
+            return true;
+        } else {
+            InliningUtil.logNotInlined(invoke, inliningDepth(), method, failureMessage);
+            return false;
+        }
+    }
+
+    /**
+     * Determines if inlining is possible at the given invoke node.
+     *
+     * @param invoke the invoke that should be inlined
+     * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
+     */
+    private InlineInfo getInlineInfo(Invoke invoke, Assumptions assumptions) {
+        final String failureMessage = InliningUtil.checkInvokeConditions(invoke);
+        if (failureMessage != null) {
+            InliningUtil.logNotInlinedMethod(invoke, failureMessage);
+            return null;
+        }
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+
+        if (callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
+            return getExactInlineInfo(invoke, targetMethod);
+        }
+
+        assert callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Virtual || callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Interface;
+
+        ResolvedJavaType holder = targetMethod.getDeclaringClass();
+        if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
+            return null;
+        }
+        ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp();
+        if (receiverStamp.alwaysNull()) {
+            // Don't inline if receiver is known to be null
+            return null;
+        }
+        ResolvedJavaType contextType = invoke.getContextType();
+        if (receiverStamp.type() != null) {
+            // the invoke target might be more specific than the holder (happens after inlining:
+            // parameters lose their declared type...)
+            ResolvedJavaType receiverType = receiverStamp.type();
+            if (receiverType != null && holder.isAssignableFrom(receiverType)) {
+                holder = receiverType;
+                if (receiverStamp.isExactType()) {
+                    assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
+                    ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType);
+                    if (resolvedMethod != null) {
+                        return getExactInlineInfo(invoke, resolvedMethod);
+                    }
+                }
+            }
+        }
+
+        if (holder.isArray()) {
+            // arrays can be treated as Objects
+            ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType);
+            if (resolvedMethod != null) {
+                return getExactInlineInfo(invoke, resolvedMethod);
+            }
+        }
+
+        if (assumptions.useOptimisticAssumptions()) {
+            ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
+            if (uniqueSubtype != null) {
+                ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod, contextType);
+                if (resolvedMethod != null) {
+                    return getAssumptionInlineInfo(invoke, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
+                }
+            }
+
+            ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
+            if (concrete != null) {
+                return getAssumptionInlineInfo(invoke, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
+            }
+        }
+
+        // type check based inlining
+        return getTypeCheckedInlineInfo(invoke, targetMethod);
+    }
+
+    private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
+        JavaTypeProfile typeProfile;
+        ValueNode receiver = invoke.callTarget().arguments().get(0);
+        if (receiver instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
+            typeProfile = typeProfileProxyNode.getProfile();
+        } else {
+            InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no type profile exists");
+            return null;
+        }
+
+        JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes();
+        if (ptypes == null || ptypes.length <= 0) {
+            InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no types in profile");
+            return null;
+        }
+        ResolvedJavaType contextType = invoke.getContextType();
+        double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
+        final OptimisticOptimizations optimisticOpts = context.getOptimisticOptimizations();
+        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
+            if (!optimisticOpts.inlineMonomorphicCalls()) {
+                InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
+                return null;
+            }
+
+            ResolvedJavaType type = ptypes[0].getType();
+            assert type.isArray() || !type.isAbstract();
+            ResolvedJavaMethod concrete = type.resolveMethod(targetMethod, contextType);
+            if (!checkTargetConditions(invoke, concrete)) {
+                return null;
+            }
+            return new TypeGuardInlineInfo(invoke, concrete, type);
+        } else {
+            invoke.setPolymorphic(true);
+
+            if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
+                return null;
+            }
+            if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
+                // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
+                // the number of types is lower than what can be recorded in a type profile
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
+                                notRecordedTypeProbability * 100);
+                return null;
+            }
+
+            // Find unique methods and their probabilities.
+            ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
+            ArrayList<Double> concreteMethodsProbabilities = new ArrayList<>();
+            for (int i = 0; i < ptypes.length; i++) {
+                ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod, contextType);
+                if (concrete == null) {
+                    InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "could not resolve method");
+                    return null;
+                }
+                int index = concreteMethods.indexOf(concrete);
+                double curProbability = ptypes[i].getProbability();
+                if (index < 0) {
+                    index = concreteMethods.size();
+                    concreteMethods.add(concrete);
+                    concreteMethodsProbabilities.add(curProbability);
+                } else {
+                    concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
+                }
+            }
+
+            // Clear methods that fall below the threshold.
+            if (notRecordedTypeProbability > 0) {
+                ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
+                ArrayList<Double> newConcreteMethodsProbabilities = new ArrayList<>();
+                for (int i = 0; i < concreteMethods.size(); ++i) {
+                    if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) {
+                        newConcreteMethods.add(concreteMethods.get(i));
+                        newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
+                    }
+                }
+
+                if (newConcreteMethods.isEmpty()) {
+                    // No method left that is worth inlining.
+                    InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
+                                    concreteMethods.size());
+                    return null;
+                }
+
+                concreteMethods = newConcreteMethods;
+                concreteMethodsProbabilities = newConcreteMethodsProbabilities;
+            }
+
+            if (concreteMethods.size() > maxMethodPerInlining) {
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
+                return null;
+            }
+
+            // Clean out types whose methods are no longer available.
+            ArrayList<JavaTypeProfile.ProfiledType> usedTypes = new ArrayList<>();
+            ArrayList<Integer> typesToConcretes = new ArrayList<>();
+            for (JavaTypeProfile.ProfiledType type : ptypes) {
+                ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod, contextType);
+                int index = concreteMethods.indexOf(concrete);
+                if (index == -1) {
+                    notRecordedTypeProbability += type.getProbability();
+                } else {
+                    assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete;
+                    usedTypes.add(type);
+                    typesToConcretes.add(index);
+                }
+            }
+
+            if (usedTypes.isEmpty()) {
+                // No type left that is worth checking for.
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
+                return null;
+            }
+
+            for (ResolvedJavaMethod concrete : concreteMethods) {
+                if (!checkTargetConditions(invoke, concrete)) {
+                    InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
+                    return null;
+                }
+            }
+            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
+        }
+    }
+
+    private InlineInfo getAssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumptions.Assumption takenAssumption) {
+        assert !concrete.isAbstract();
+        if (!checkTargetConditions(invoke, concrete)) {
+            return null;
+        }
+        return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
+    }
+
+    private InlineInfo getExactInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
+        assert !targetMethod.isAbstract();
+        if (!checkTargetConditions(invoke, targetMethod)) {
+            return null;
+        }
+        return new ExactInlineInfo(invoke, targetMethod);
+    }
+
+    private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, Assumptions callerAssumptions) {
+        StructuredGraph callerGraph = callerCallsiteHolder.graph();
+        InlineInfo calleeInfo = calleeInvocation.callee();
+        try {
+            try (Debug.Scope scope = Debug.scope("doInline", callerGraph)) {
+                Set<Node> canonicalizedNodes = new HashSet<>();
+                calleeInfo.invoke().asNode().usages().snapshotTo(canonicalizedNodes);
+                Collection<Node> parameterUsages = calleeInfo.inline(new Providers(context), callerAssumptions);
+                canonicalizedNodes.addAll(parameterUsages);
+                callerAssumptions.record(calleeInvocation.assumptions());
+                metricInliningRuns.increment();
+                Debug.dump(callerGraph, "after %s", calleeInfo);
+
+                if (OptCanonicalizer.getValue()) {
+                    Graph.Mark markBeforeCanonicalization = callerGraph.getMark();
+
+                    canonicalizer.applyIncremental(callerGraph, context, canonicalizedNodes);
+
+                    // process invokes that are possibly created during canonicalization
+                    for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
+                        if (newNode instanceof Invoke) {
+                            callerCallsiteHolder.pushInvoke((Invoke) newNode);
+                        }
+                    }
+                }
+
+                callerCallsiteHolder.computeProbabilities();
+
+                metricInliningPerformed.increment();
+            }
+        } catch (BailoutException bailout) {
+            throw bailout;
+        } catch (AssertionError | RuntimeException e) {
+            throw new GraalInternalError(e).addContext(calleeInfo.toString());
+        } catch (GraalInternalError e) {
+            throw e.addContext(calleeInfo.toString());
+        }
+    }
+
+    /**
+     * @return true iff inlining was actually performed
+     */
+    private boolean tryToInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, MethodInvocation parentInvocation, int inliningDepth) {
+        InlineInfo calleeInfo = calleeInvocation.callee();
+        Assumptions callerAssumptions = parentInvocation.assumptions();
+        metricInliningConsidered.increment();
+
+        if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), calleeInfo, inliningDepth, calleeInvocation.probability(), calleeInvocation.relevance(), true)) {
+            doInline(callerCallsiteHolder, calleeInvocation, callerAssumptions);
+            return true;
+        }
+
+        if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
+            calleeInfo.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
+        }
+
+        return false;
+    }
+
+    /**
+     * Process the next invoke and enqueue all its graphs for processing.
+     */
+    private void processNextInvoke() {
+        CallsiteHolder callsiteHolder = currentGraph();
+        Invoke invoke = callsiteHolder.popInvoke();
+        MethodInvocation callerInvocation = currentInvocation();
+        Assumptions parentAssumptions = callerInvocation.assumptions();
+        Assumptions calleeAssumptions = new Assumptions(parentAssumptions.useOptimisticAssumptions());
+        InlineInfo info = populateInlineInfo(invoke, parentAssumptions, calleeAssumptions);
+
+        if (info != null) {
+            double invokeProbability = callsiteHolder.invokeProbability(invoke);
+            double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
+            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance);
+            pushInvocationAndGraphs(methodInvocation);
+        }
+    }
+
+    private InlineInfo populateInlineInfo(Invoke invoke, Assumptions parentAssumptions, Assumptions calleeAssumptions) {
+        InlineInfo info = getInlineInfo(invoke, parentAssumptions);
+        if (info == null) {
+            return null;
+        }
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            Inlineable elem = Inlineable.getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeAssumptions), canonicalizer);
+            info.setInlinableElement(i, elem);
+        }
+        return info;
+    }
+
+    public int graphCount() {
+        return graphQueue.size();
+    }
+
+    private void pushGraph(StructuredGraph graph, double probability, double relevance) {
+        assert graph != null;
+        assert !contains(graph);
+        graphQueue.push(new CallsiteHolder(graph, probability, relevance));
+        assert graphQueue.size() <= maxGraphs;
+    }
+
+    private void pushDummyGraph() {
+        graphQueue.push(DUMMY_CALLSITE_HOLDER);
+        assert graphQueue.size() <= maxGraphs;
+    }
+
+    public boolean hasUnprocessedGraphs() {
+        return !graphQueue.isEmpty();
+    }
+
+    private CallsiteHolder currentGraph() {
+        return graphQueue.peek();
+    }
+
+    private void popGraph() {
+        graphQueue.pop();
+        assert graphQueue.size() <= maxGraphs;
+    }
+
+    private void popGraphs(int count) {
+        assert count >= 0;
+        for (int i = 0; i < count; i++) {
+            graphQueue.pop();
+        }
+    }
+
+    private static final Object[] NO_CONTEXT = {};
+
+    /**
+     * Gets the call hierarchy of this inlining from outer most call to inner most callee.
+     */
+    private Object[] inliningContext() {
+        if (!Debug.isDumpEnabled()) {
+            return NO_CONTEXT;
+        }
+        Object[] result = new Object[graphQueue.size()];
+        int i = 0;
+        for (CallsiteHolder g : graphQueue) {
+            result[i++] = g.method();
+        }
+        return result;
+    }
+
+    private MethodInvocation currentInvocation() {
+        return invocationQueue.peekFirst();
+    }
+
+    private void pushInvocationAndGraphs(MethodInvocation methodInvocation) {
+        invocationQueue.addFirst(methodInvocation);
+        InlineInfo info = methodInvocation.callee();
+        maxGraphs += info.numberOfMethods();
+        assert graphQueue.size() <= maxGraphs;
+        double invokeProbability = methodInvocation.probability();
+        double invokeRelevance = methodInvocation.relevance();
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            Inlineable elem = info.inlineableElementAt(i);
+            if (elem instanceof InlineableGraph) {
+                pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
+            } else {
+                assert elem instanceof InlineableMacroNode;
+                pushDummyGraph();
+            }
+        }
+    }
+
+    private void popInvocation() {
+        maxGraphs -= invocationQueue.peekFirst().callee().numberOfMethods();
+        assert graphQueue.size() <= maxGraphs;
+        invocationQueue.removeFirst();
+    }
+
+    public int countRecursiveInlining(ResolvedJavaMethod method) {
+        int count = 0;
+        for (CallsiteHolder callsiteHolder : graphQueue) {
+            if (method.equals(callsiteHolder.method())) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public int inliningDepth() {
+        assert invocationQueue.size() > 0;
+        return invocationQueue.size() - 1;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder("Invocations: ");
+
+        for (MethodInvocation invocation : invocationQueue) {
+            if (invocation.callee() != null) {
+                result.append(invocation.callee().numberOfMethods());
+                result.append("x ");
+                result.append(invocation.callee().invoke());
+                result.append("; ");
+            }
+        }
+
+        result.append("\nGraphs: ");
+        for (CallsiteHolder graph : graphQueue) {
+            result.append(graph.graph());
+            result.append("; ");
+        }
+
+        return result.toString();
+    }
+
+    private boolean contains(StructuredGraph graph) {
+        for (CallsiteHolder info : graphQueue) {
+            if (info.graph() == graph) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return true iff inlining was actually performed
+     */
+    public boolean moveForward() {
+
+        final MethodInvocation currentInvocation = currentInvocation();
+
+        final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), inliningDepth(),
+                        currentInvocation.probability(), currentInvocation.relevance(), false));
+        if (backtrack) {
+            int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
+            assert remainingGraphs > 0;
+            popGraphs(remainingGraphs);
+            popInvocation();
+            return false;
+        }
+
+        final boolean delve = currentGraph().hasRemainingInvokes() && inliningPolicy.continueInlining(currentGraph().graph());
+        if (delve) {
+            processNextInvoke();
+            return false;
+        }
+
+        popGraph();
+        if (currentInvocation.isRoot()) {
+            return false;
+        }
+
+        // try to inline
+        assert currentInvocation.callee().invoke().asNode().isAlive();
+        currentInvocation.incrementProcessedGraphs();
+        if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
+            popInvocation();
+            final MethodInvocation parentInvoke = currentInvocation();
+            try (Debug.Scope s = Debug.scope("Inlining", inliningContext())) {
+                return tryToInline(currentGraph(), currentInvocation, parentInvoke, inliningDepth() + 1);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningIterator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,130 @@
+/*
+ * 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.phases.common.inlining.walker;
+
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeBitMap;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.LinkedList;
+
+/**
+ * Given a graph, visit all fixed nodes in dominator-based order, collecting in the process the
+ * {@link Invoke} nodes with {@link MethodCallTargetNode}. Such list of callsites is returned by
+ * {@link #apply()}
+ */
+public class InliningIterator {
+
+    private final StartNode start;
+    private final Deque<FixedNode> nodeQueue;
+    private final NodeBitMap queuedNodes;
+
+    public InliningIterator(StructuredGraph graph) {
+        this.start = graph.start();
+        this.nodeQueue = new ArrayDeque<>();
+        this.queuedNodes = graph.createNodeBitMap();
+        assert start.isAlive();
+    }
+
+    public LinkedList<Invoke> apply() {
+        LinkedList<Invoke> invokes = new LinkedList<>();
+        FixedNode current;
+        forcedQueue(start);
+
+        while ((current = nextQueuedNode()) != null) {
+            assert current.isAlive();
+
+            if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
+                if (current != start) {
+                    invokes.addLast((Invoke) current);
+                }
+                queueSuccessors(current);
+            } else if (current instanceof LoopBeginNode) {
+                queueSuccessors(current);
+            } else if (current instanceof LoopEndNode) {
+                // nothing to do
+            } else if (current instanceof MergeNode) {
+                queueSuccessors(current);
+            } else if (current instanceof FixedWithNextNode) {
+                queueSuccessors(current);
+            } else if (current instanceof EndNode) {
+                queueMerge((EndNode) current);
+            } else if (current instanceof ControlSinkNode) {
+                // nothing to do
+            } else if (current instanceof ControlSplitNode) {
+                queueSuccessors(current);
+            } else {
+                assert false : current;
+            }
+        }
+
+        return invokes;
+    }
+
+    private void queueSuccessors(FixedNode x) {
+        for (Node node : x.successors()) {
+            queue(node);
+        }
+    }
+
+    private void queue(Node node) {
+        if (node != null && !queuedNodes.isMarked(node)) {
+            forcedQueue(node);
+        }
+    }
+
+    private void forcedQueue(Node node) {
+        queuedNodes.mark(node);
+        nodeQueue.addFirst((FixedNode) node);
+    }
+
+    private FixedNode nextQueuedNode() {
+        if (nodeQueue.isEmpty()) {
+            return null;
+        }
+
+        FixedNode result = nodeQueue.removeFirst();
+        assert queuedNodes.isMarked(result);
+        return result;
+    }
+
+    private void queueMerge(AbstractEndNode end) {
+        MergeNode merge = end.merge();
+        if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
+            queuedNodes.mark(merge);
+            nodeQueue.add(merge);
+        }
+    }
+
+    private boolean visitedAllEnds(MergeNode merge) {
+        for (int i = 0; i < merge.forwardEndCount(); i++) {
+            if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,95 @@
+/*
+ * 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.phases.common.inlining.walker;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.MetaUtil;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.nodes.CallTargetNode;
+import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+
+public class MethodInvocation {
+
+    private final InlineInfo callee;
+    private final Assumptions assumptions;
+    private final double probability;
+    private final double relevance;
+
+    private int processedGraphs;
+
+    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+        this.callee = info;
+        this.assumptions = assumptions;
+        this.probability = probability;
+        this.relevance = relevance;
+    }
+
+    public void incrementProcessedGraphs() {
+        processedGraphs++;
+        assert processedGraphs <= callee.numberOfMethods();
+    }
+
+    public int processedGraphs() {
+        assert processedGraphs <= callee.numberOfMethods();
+        return processedGraphs;
+    }
+
+    public int totalGraphs() {
+        return callee.numberOfMethods();
+    }
+
+    public InlineInfo callee() {
+        return callee;
+    }
+
+    public Assumptions assumptions() {
+        return assumptions;
+    }
+
+    public double probability() {
+        return probability;
+    }
+
+    public double relevance() {
+        return relevance;
+    }
+
+    public boolean isRoot() {
+        return callee == null;
+    }
+
+    @Override
+    public String toString() {
+        if (isRoot()) {
+            return "<root>";
+        }
+        CallTargetNode callTarget = callee.invoke().callTarget();
+        if (callTarget instanceof MethodCallTargetNode) {
+            ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
+            return MetaUtil.format("Invoke#%H.%n(%p)", calleeMethod);
+        } else {
+            return "Invoke#" + callTarget.targetName();
+        }
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Fri May 30 15:09:09 2014 +0200
@@ -26,7 +26,9 @@
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.DebugMemUseTracker.Closeable;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -38,8 +40,26 @@
 
     private CharSequence name;
 
-    private final DebugTimer phaseTimer;
-    private final DebugMetric phaseMetric;
+    /**
+     * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugTimer timer;
+
+    /**
+     * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugMetric executionCount;
+
+    /**
+     * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to
+     * {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugMetric inputNodesCount;
+
+    /**
+     * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}.
+     */
+    private final DebugMemUseTracker memUseTracker;
 
     private static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
 
@@ -49,15 +69,19 @@
     }
 
     protected BasePhase() {
-        phaseTimer = Debug.timer("PhaseTime_%s", getClass());
-        phaseMetric = Debug.metric("PhaseCount_%s", getClass());
+        timer = Debug.timer("PhaseTime_%s", getClass());
+        executionCount = Debug.metric("PhaseCount_%s", getClass());
+        memUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
+        inputNodesCount = Debug.metric("PhaseNodes_%s", getClass());
     }
 
     protected BasePhase(String name) {
         assert checkName(name);
         this.name = name;
-        phaseTimer = Debug.timer("PhaseTime_%s", getClass());
-        phaseMetric = Debug.metric("PhaseCount_%s", getClass());
+        timer = Debug.timer("PhaseTime_%s", getClass());
+        executionCount = Debug.metric("PhaseCount_%s", getClass());
+        memUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
+        inputNodesCount = Debug.metric("PhaseNodes_%s", getClass());
     }
 
     protected CharSequence getDetailedName() {
@@ -69,10 +93,11 @@
     }
 
     public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
-        try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this)) {
+        try (TimerCloseable a = timer.start(); Scope s = Debug.scope(getClass(), this); Closeable c = memUseTracker.start()) {
             BasePhase.this.run(graph, context);
-            phaseMetric.increment();
-            if (dumpGraph) {
+            executionCount.increment();
+            inputNodesCount.add(graph.getNodeCount());
+            if (dumpGraph && Debug.isDumpEnabled()) {
                 Debug.dump(graph, "After phase %s", getName());
             }
             assert graph.verify();
@@ -81,13 +106,17 @@
         }
     }
 
+    protected CharSequence createName() {
+        String s = BasePhase.this.getClass().getSimpleName();
+        if (s.endsWith("Phase")) {
+            s = s.substring(0, s.length() - "Phase".length());
+        }
+        return s;
+    }
+
     public final CharSequence getName() {
         if (name == null) {
-            String s = BasePhase.this.getClass().getSimpleName();
-            if (s.endsWith("Phase")) {
-                s = s.substring(0, s.length() - "Phase".length());
-            }
-            name = s;
+            name = createName();
         }
         return name;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/*
- * 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.phases;
-
-import com.oracle.graal.options.*;
-
-/**
- * This class encapsulates options that control the behavior of the Graal compiler.
- */
-// @formatter:off
-public final class GraalOptions {
-
-    @Option(help = "Use baseline compiler configuration")
-    public static final OptionValue<Boolean> UseBaselineCompiler = new OptionValue<>(false);
-    @Option(help = "Enable use of compiler intrinsics")
-    public static final OptionValue<Boolean> Intrinsify = new OptionValue<>(true);
-    @Option(help = "Enable inlining of monomorphic calls")
-    static final OptionValue<Boolean> InlineMonomorphicCalls = new OptionValue<>(true);
-    @Option(help = "Enable inlining of polymorphic calls")
-    static final OptionValue<Boolean> InlinePolymorphicCalls = new OptionValue<>(true);
-    @Option(help = "Enable inlining of megamorphic calls")
-    static final OptionValue<Boolean> InlineMegamorphicCalls = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Double> MegamorphicInliningMinMethodProbability = new OptionValue<>(0.33D);
-    @Option(help = "")
-    public static final OptionValue<Integer> MaximumDesiredSize = new OptionValue<>(20000);
-    @Option(help = "")
-    public static final OptionValue<Integer> MaximumRecursiveInlining = new OptionValue<>(5);
-
-    // inlining settings
-    @Option(help = "")
-    public static final OptionValue<Float> BoostInliningForEscapeAnalysis = new OptionValue<>(2f);
-    @Option(help = "")
-    public static final OptionValue<Float> RelevanceCapForInlining = new OptionValue<>(1f);
-    @Option(help = "")
-    public static final OptionValue<Float> CapInheritedRelevance = new OptionValue<>(1f);
-    @Option(help = "")
-    public static final OptionValue<Boolean> IterativeInlining = new OptionValue<>(false);
-
-    @Option(help = "")
-    public static final OptionValue<Integer> TrivialInliningSize = new OptionValue<>(10);
-    @Option(help = "")
-    public static final OptionValue<Integer> MaximumInliningSize = new OptionValue<>(300);
-    @Option(help = "")
-    public static final OptionValue<Integer> SmallCompiledLowLevelGraphSize = new OptionValue<>(300);
-    @Option(help = "")
-    public static final OptionValue<Double> LimitInlinedInvokes = new OptionValue<>(5.0);
-    @Option(help = "")
-    public static final OptionValue<Boolean> InlineEverything = new OptionValue<>(false);
-
-    // escape analysis settings
-    @Option(help = "")
-    public static final OptionValue<Boolean> PartialEscapeAnalysis = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Integer> EscapeAnalysisIterations = new OptionValue<>(2);
-    @Option(help = "")
-    public static final OptionValue<String> EscapeAnalyzeOnly = new OptionValue<>(null);
-    @Option(help = "")
-    public static final OptionValue<Integer> MaximumEscapeAnalysisArrayLength = new OptionValue<>(32);
-    @Option(help = "")
-    public static final OptionValue<Boolean> PEAInliningHints = new OptionValue<>(false);
-
-    @Option(help = "")
-    public static final OptionValue<Double> TailDuplicationProbability = new OptionValue<>(0.5);
-    @Option(help = "")
-    public static final OptionValue<Integer> TailDuplicationTrivialSize = new OptionValue<>(1);
-
-    // profiling information
-    @Option(help = "")
-    public static final OptionValue<Integer> DeoptsToDisableOptimisticOptimization = new OptionValue<>(40);
-
-    // graph caching
-    @Option(help = "")
-    public static final OptionValue<Boolean> CacheGraphs = new OptionValue<>(true);
-
-    //loop transform settings TODO (gd) tune
-    @Option(help = "")
-    public static final OptionValue<Boolean> LoopPeeling = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> ReassociateInvariants = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> FullUnroll = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> LoopUnswitch = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Integer> FullUnrollMaxNodes = new OptionValue<>(300);
-    @Option(help = "")
-    public static final OptionValue<Integer> ExactFullUnrollMaxNodes = new OptionValue<>(1200);
-    @Option(help = "")
-    public static final OptionValue<Float> MinimumPeelProbability = new OptionValue<>(0.35f);
-    @Option(help = "")
-    public static final OptionValue<Integer> LoopMaxUnswitch = new OptionValue<>(3);
-    @Option(help = "")
-    public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(50);
-    @Option(help = "")
-    public static final OptionValue<Integer> LoopUnswitchUncertaintyBoost = new OptionValue<>(5);
-    @Option(help = "")
-    public static final OptionValue<Boolean> UseLoopLimitChecks = new OptionValue<>(true);
-
-    // debugging settings
-    @Option(help = "")
-    public static final OptionValue<Boolean> ZapStackOnMethodEntry = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> DeoptALot = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> VerifyPhases = new OptionValue<>(false);
-
-    @Option(help = "")
-    public static final OptionValue<String> PrintFilter = new OptionValue<>(null);
-
-    // Debug settings:
-    @Option(help = "")
-    public static final OptionValue<Boolean> BootstrapReplacements = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Integer> GCDebugStartCycle = new OptionValue<>(-1);
-    // Ideal graph visualizer output settings
-    @Option(help = "Dump IdealGraphVisualizer output in binary format")
-    public static final OptionValue<Boolean> PrintBinaryGraphs = new OptionValue<>(true);
-    @Option(help = "Output probabilities for fixed nodes during binary graph dumping")
-    public static final OptionValue<Boolean> PrintGraphProbabilities = new OptionValue<>(false);
-    @Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.")
-    public static final OptionValue<Boolean> PrintCFG = new OptionValue<>(false);
-    @Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.")
-    public static final OptionValue<Boolean> PrintBackendCFG = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> PrintIdealGraphFile = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<String> PrintIdealGraphAddress = new OptionValue<>("127.0.0.1");
-    @Option(help = "")
-    public static final OptionValue<Integer> PrintIdealGraphPort = new OptionValue<>(4444);
-    @Option(help = "")
-    public static final OptionValue<Integer> PrintBinaryGraphPort = new OptionValue<>(4445);
-
-    // Other printing settings
-    @Option(help = "")
-    public static final OptionValue<Boolean> PrintCompilation = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> PrintAfterCompilation = new OptionValue<>(false);
-    @Option(help = "Print profiling information when parsing a method's bytecode")
-    public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> PrintCodeBytes = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> PrintBailout = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> TraceEscapeAnalysis = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> ExitVMOnBailout = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> ExitVMOnException = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> PrintStackTraceOnException = new OptionValue<>(false);
-    @Option(help = "Set a phase after which the decompiler dumps the graph, -G:Dump= required")
-    public static final OptionValue<String> DecompileAfterPhase = new OptionValue<>(null);
-
-    // HotSpot command line options
-    @Option(help = "")
-    public static final OptionValue<Boolean> HotSpotPrintCompilation = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> HotSpotCIPrintCompilerName = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> HotSpotPrintInlining = new OptionValue<>(false);
-
-    // Register allocator debugging
-    @Option(help = "")
-    public static final OptionValue<String> RegisterPressure = new OptionValue<>(null);
-
-    // Code generator settings
-    @Option(help = "")
-    public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> UseProfilingInformation = new OptionValue<>(true);
-    @Option(help = "")
-           static final OptionValue<Boolean> RemoveNeverExecutedCode = new OptionValue<>(true);
-           @Option(help = "")
-           static final OptionValue<Boolean> UseExceptionProbability = new OptionValue<>(true);
-           @Option(help = "")
-           static final OptionValue<Boolean> UseExceptionProbabilityForOperations = new OptionValue<>(true);
-           @Option(help = "")
-    public static final OptionValue<Boolean> OmitHotExceptionStacktrace = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> GenSafepoints = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> GenLoopSafepoints = new OptionValue<>(true);
-    @Option(help = "")
-           static final OptionValue<Boolean> UseTypeCheckHints = new OptionValue<>(true);
-           @Option(help = "")
-    public static final OptionValue<Boolean> InlineVTableStubs = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> AlwaysInlineVTableStubs = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> GenAssertionCode = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> AlignCallsForPatching = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> ResolveClassBeforeStaticInvoke = new OptionValue<>(false);
-    @Option(help = "")
-    public static final OptionValue<Boolean> CanOmitFrame = new OptionValue<>(true);
-
-    @Option(help = "")
-    public static final OptionValue<Boolean> MemoryAwareScheduling = new OptionValue<>(true);
-
-    // Translating tableswitch instructions
-    @Option(help = "")
-    public static final OptionValue<Integer> MinimumJumpTableSize = new OptionValue<>(5);
-    @Option(help = "")
-    public static final OptionValue<Integer> RangeTestsSwitchDensity = new OptionValue<>(5);
-    @Option(help = "")
-    public static final OptionValue<Double> MinTableSwitchDensity = new OptionValue<>(0.5);
-
-    // Ahead of time compilation
-    @Option(help = "Try to avoid emitting code where patching is required")
-    public static final OptionValue<Boolean> ImmutableCode = new OptionValue<>(false);
-
-    @Option(help = "")
-    public static final OptionValue<Boolean> CallArrayCopy = new OptionValue<>(true);
-
-    // Runtime settings
-    @Option(help = "")
-    public static final OptionValue<Boolean> SupportJsrBytecodes = new OptionValue<>(true);
-
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptAssumptions = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptConvertDeoptsToGuards = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptReadElimination = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptCanonicalizer = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptDeoptimizationGrouping = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptEliminateGuards = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptImplicitNullChecks = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptLivenessAnalysis = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptLoopTransform = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptFloatingReads = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptTailDuplication = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptEliminatePartiallyRedundantGuards = new OptionValue<>(true);
-    @Option(help = "")
-    public static final OptionValue<Boolean> OptFilterProfiledTypes = new OptionValue<>(true);
-    @Option(help = "")
-    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);
-
-
-    /**
-     * Counts the various paths taken through snippets.
-     */
-    @Option(help = "")
-    public static final OptionValue<Boolean> SnippetCounters = new OptionValue<>(false);
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Fri May 30 15:09:09 2014 +0200
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 
 public final class OptimisticOptimizations {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +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.phases.graph;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
-
-public class ComputeInliningRelevanceClosure {
-
-    private static final double EPSILON = 1d / Integer.MAX_VALUE;
-
-    private final StructuredGraph graph;
-    private final NodesToDoubles nodeProbabilities;
-    private final NodesToDoubles nodeRelevances;
-
-    public ComputeInliningRelevanceClosure(StructuredGraph graph, NodesToDoubles nodeProbabilities) {
-        this.graph = graph;
-        this.nodeProbabilities = nodeProbabilities;
-        this.nodeRelevances = new NodesToDoubles(graph.getNodeCount());
-    }
-
-    public NodesToDoubles apply() {
-        new ComputeInliningRelevanceIterator(graph).apply();
-        return nodeRelevances;
-    }
-
-    private class ComputeInliningRelevanceIterator extends ScopedPostOrderNodeIterator {
-
-        private final HashMap<FixedNode, Scope> scopes;
-        private double currentProbability;
-        private double parentRelevance;
-
-        public ComputeInliningRelevanceIterator(StructuredGraph graph) {
-            super(graph);
-            this.scopes = computeScopesAndProbabilities();
-        }
-
-        @Override
-        protected void initializeScope() {
-            Scope scope = scopes.get(currentScopeStart);
-            parentRelevance = getParentScopeRelevance(scope);
-            currentProbability = scope.probability;
-        }
-
-        private double getParentScopeRelevance(Scope scope) {
-            if (scope.start instanceof LoopBeginNode) {
-                assert scope.parent != null;
-                double parentProbability = 0;
-                for (AbstractEndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
-                    parentProbability += nodeProbabilities.get(end);
-                }
-                return parentProbability / scope.parent.probability;
-            } else {
-                assert scope.parent == null;
-                return 1.0;
-            }
-        }
-
-        @Override
-        protected void invoke(Invoke invoke) {
-            double probability = nodeProbabilities.get(invoke.asNode());
-            assert !Double.isNaN(probability);
-
-            double relevance = (probability / currentProbability) * Math.min(1.0, parentRelevance);
-            nodeRelevances.put(invoke.asNode(), relevance);
-            assert !Double.isNaN(relevance);
-        }
-
-        private HashMap<FixedNode, Scope> computeScopesAndProbabilities() {
-            HashMap<FixedNode, Scope> result = new HashMap<>();
-
-            for (Scope scope : computeScopes()) {
-                double lowestPathProbability = computeLowestPathProbability(scope);
-                scope.probability = Math.max(EPSILON, lowestPathProbability);
-                result.put(scope.start, scope);
-            }
-
-            return result;
-        }
-
-        private Scope[] computeScopes() {
-            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
-
-            List<Loop<Block>> loops = cfg.getLoops();
-            HashMap<Loop<Block>, Scope> processedScopes = new HashMap<>();
-            Scope[] result = new Scope[loops.size() + 1];
-            Scope methodScope = new Scope(graph.start(), null);
-            processedScopes.put(null, methodScope);
-
-            result[0] = methodScope;
-            for (int i = 0; i < loops.size(); i++) {
-                result[i + 1] = createScope(loops.get(i), processedScopes);
-            }
-
-            return result;
-        }
-
-        private Scope createScope(Loop<Block> loop, HashMap<Loop<Block>, Scope> processedLoops) {
-            Scope parent = processedLoops.get(loop.parent);
-            if (parent == null) {
-                parent = createScope(loop.parent, processedLoops);
-            }
-            Scope result = new Scope(loop.header.getBeginNode(), parent);
-            processedLoops.put(loop, result);
-            return result;
-        }
-    }
-
-    private double computeLowestPathProbability(Scope scope) {
-        FixedNode scopeStart = scope.start;
-        ArrayList<FixedNode> pathBeginNodes = new ArrayList<>();
-        pathBeginNodes.add(scopeStart);
-        double minPathProbability = nodeProbabilities.get(scopeStart);
-        boolean isLoopScope = scopeStart instanceof LoopBeginNode;
-
-        do {
-            Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
-            do {
-                if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
-                    return minPathProbability;
-                } else if (current instanceof LoopBeginNode && current != scopeStart) {
-                    current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
-                    minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
-                } else if (current instanceof ControlSplitNode) {
-                    current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
-                    minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
-                } else {
-                    assert current.successors().count() <= 1;
-                    current = current.successors().first();
-                }
-            } while (current != null);
-        } while (!pathBeginNodes.isEmpty());
-
-        return minPathProbability;
-    }
-
-    private double getMinPathProbability(FixedNode current, double minPathProbability) {
-        if (current != null && nodeProbabilities.get(current) < minPathProbability) {
-            return nodeProbabilities.get(current);
-        }
-        return minPathProbability;
-    }
-
-    private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList<FixedNode> pathBeginNodes) {
-        Node maxSux = null;
-        double maxProbability = 0.0;
-        int pathBeginCount = pathBeginNodes.size();
-
-        for (Node sux : controlSplit.successors()) {
-            double probability = controlSplit.probability((BeginNode) sux);
-            if (probability > maxProbability) {
-                maxProbability = probability;
-                maxSux = sux;
-                truncate(pathBeginNodes, pathBeginCount);
-            } else if (probability == maxProbability) {
-                pathBeginNodes.add((FixedNode) sux);
-            }
-        }
-
-        return maxSux;
-    }
-
-    private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList<FixedNode> pathBeginNodes) {
-        Node maxSux = null;
-        double maxProbability = 0.0;
-        int pathBeginCount = pathBeginNodes.size();
-
-        for (LoopExitNode sux : loopBegin.loopExits()) {
-            double probability = nodeProbabilities.get(sux);
-            if (probability > maxProbability) {
-                maxProbability = probability;
-                maxSux = sux;
-                truncate(pathBeginNodes, pathBeginCount);
-            } else if (probability == maxProbability) {
-                pathBeginNodes.add(sux);
-            }
-        }
-
-        return maxSux;
-    }
-
-    private static void truncate(ArrayList<FixedNode> pathBeginNodes, int pathBeginCount) {
-        for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
-            pathBeginNodes.remove(pathBeginNodes.size() - 1);
-        }
-    }
-
-    private static class Scope {
-
-        public final FixedNode start;
-        public final Scope parent;
-        public double probability;
-
-        public Scope(FixedNode start, Scope parent) {
-            this.start = start;
-            this.parent = parent;
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,295 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.graph;
-
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.util.*;
-
-/**
- * Computes probabilities for nodes in a graph.
- * <p>
- * The computation of absolute probabilities works in three steps:
- * <ol>
- * <li>{@link PropagateProbability} traverses the graph in post order (merges after their ends, ...)
- * and keeps track of the "probability state". Whenever it encounters a {@link ControlSplitNode} it
- * uses the split's probability information to divide the probability upon the successors. Whenever
- * it encounters an {@link Invoke} it assumes that the exception edge is unlikely and propagates the
- * whole probability to the normal successor. Whenever it encounters a {@link MergeNode} it sums up
- * the probability of all predecessors. It also maintains a set of active loops (whose
- * {@link LoopBeginNode} has been visited) and builds def/use information for step 2.</li>
- * <li></li>
- * <li>{@link PropagateLoopFrequency} propagates the loop frequencies and multiplies each
- * {@link FixedNode}'s probability with its loop frequency.</li>
- * </ol>
- */
-public class ComputeProbabilityClosure {
-
-    private static final double EPSILON = Double.MIN_NORMAL;
-
-    private final StructuredGraph graph;
-    private final NodesToDoubles nodeProbabilities;
-    private final Set<LoopInfo> loopInfos;
-    private final Map<MergeNode, Set<LoopInfo>> mergeLoops;
-
-    public ComputeProbabilityClosure(StructuredGraph graph) {
-        this.graph = graph;
-        this.nodeProbabilities = new NodesToDoubles(graph.getNodeCount());
-        this.loopInfos = new ArraySet<>();
-        this.mergeLoops = new IdentityHashMap<>();
-    }
-
-    public NodesToDoubles apply() {
-        // adjustControlSplitProbabilities();
-        new PropagateProbability(graph.start()).apply();
-        computeLoopFactors();
-        new PropagateLoopFrequency(graph.start()).apply();
-        // assert verifyProbabilities();
-        return nodeProbabilities;
-    }
-
-    private void computeLoopFactors() {
-        for (LoopInfo info : loopInfos) {
-            double frequency = info.loopFrequency(nodeProbabilities);
-            assert frequency != -1;
-        }
-    }
-
-    public static class LoopInfo {
-
-        public final LoopBeginNode loopBegin;
-
-        public final NodeMap<Set<LoopInfo>> requires;
-
-        private double loopFrequency = -1.0;
-        public boolean ended = false;
-
-        public LoopInfo(LoopBeginNode loopBegin) {
-            this.loopBegin = loopBegin;
-            this.requires = loopBegin.graph().createNodeMap();
-        }
-
-        public double loopFrequency(NodesToDoubles nodeProbabilities) {
-            // loopFrequency is initialized with -1.0
-            if (loopFrequency < 0.0 && ended) {
-                double backEdgeProb = 0.0;
-                for (LoopEndNode le : loopBegin.loopEnds()) {
-                    double factor = 1;
-                    Set<LoopInfo> requireds = requires.get(le);
-                    for (LoopInfo required : requireds) {
-                        double t = required.loopFrequency(nodeProbabilities);
-                        if (t == -1) {
-                            return -1;
-                        }
-                        factor = multiplySaturate(factor, t);
-                    }
-                    backEdgeProb += nodeProbabilities.get(le) * factor;
-                }
-                double entryProb = nodeProbabilities.get(loopBegin);
-                double d = entryProb - backEdgeProb;
-                if (d <= EPSILON) {
-                    d = EPSILON;
-                }
-                loopFrequency = entryProb / d;
-                loopBegin.setLoopFrequency(loopFrequency);
-            }
-            return loopFrequency;
-        }
-    }
-
-    /**
-     * Multiplies a and b and saturates the result to 1/{@link Double#MIN_NORMAL}.
-     * 
-     * @param a
-     * @param b
-     * @return a times b saturated to 1/{@link Double#MIN_NORMAL}
-     */
-    public static double multiplySaturate(double a, double b) {
-        double r = a * b;
-        if (r > 1 / Double.MIN_NORMAL) {
-            return 1 / Double.MIN_NORMAL;
-        }
-        return r;
-    }
-
-    private class Probability extends MergeableState<Probability> implements Cloneable {
-
-        public double probability;
-        public Set<LoopInfo> loops;
-        public LoopInfo loopInfo;
-
-        public Probability(double probability, Set<LoopInfo> loops) {
-            assert probability >= 0.0;
-            this.probability = probability;
-            this.loops = new ArraySet<>(4);
-            if (loops != null) {
-                this.loops.addAll(loops);
-            }
-        }
-
-        @Override
-        public Probability clone() {
-            return new Probability(probability, loops);
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<Probability> withStates) {
-            if (merge.forwardEndCount() > 1) {
-                Set<LoopInfo> intersection = new ArraySet<>(loops);
-                for (Probability other : withStates) {
-                    intersection.retainAll(other.loops);
-                }
-                for (LoopInfo info : loops) {
-                    if (!intersection.contains(info)) {
-                        double loopFrequency = info.loopFrequency(nodeProbabilities);
-                        if (loopFrequency == -1) {
-                            return false;
-                        }
-                        probability = multiplySaturate(probability, loopFrequency);
-                        assert probability >= 0;
-                    }
-                }
-                for (Probability other : withStates) {
-                    double prob = other.probability;
-                    for (LoopInfo info : other.loops) {
-                        if (!intersection.contains(info)) {
-                            double loopFrequency = info.loopFrequency(nodeProbabilities);
-                            if (loopFrequency == -1) {
-                                return false;
-                            }
-                            prob = multiplySaturate(prob, loopFrequency);
-                            assert prob >= 0;
-                        }
-                    }
-                    probability += prob;
-                    assert probability >= 0;
-                }
-                loops = intersection;
-                mergeLoops.put(merge, new ArraySet<>(intersection));
-                probability = Math.max(0.0, probability);
-            }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            loopInfo = new LoopInfo(loopBegin);
-            loopInfos.add(loopInfo);
-            loops.add(loopInfo);
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<Probability> loopEndStates) {
-            assert loopInfo != null;
-            List<LoopEndNode> loopEnds = loopBegin.orderedLoopEnds();
-            int i = 0;
-            for (Probability proba : loopEndStates) {
-                LoopEndNode loopEnd = loopEnds.get(i++);
-                Set<LoopInfo> requires = loopInfo.requires.get(loopEnd);
-                if (requires == null) {
-                    requires = new HashSet<>();
-                    loopInfo.requires.set(loopEnd, requires);
-                }
-                for (LoopInfo innerLoop : proba.loops) {
-                    if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) {
-                        requires.add(innerLoop);
-                    }
-                }
-            }
-            loopInfo.ended = true;
-        }
-
-        @Override
-        public void afterSplit(BeginNode node) {
-            assert node.predecessor() != null;
-            Node pred = node.predecessor();
-            ControlSplitNode x = (ControlSplitNode) pred;
-            double nodeProbability = x.probability(node);
-            assert nodeProbability >= 0.0 : "Node " + x + " provided negative probability for begin " + node + ": " + nodeProbability;
-            probability *= nodeProbability;
-            assert probability >= 0.0;
-        }
-    }
-
-    private class PropagateProbability extends PostOrderNodeIterator<Probability> {
-
-        public PropagateProbability(FixedNode start) {
-            super(start, new Probability(1d, null));
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            nodeProbabilities.put(node, state.probability);
-        }
-    }
-
-    private class LoopCount extends MergeableState<LoopCount> implements Cloneable {
-
-        public double count;
-
-        public LoopCount(double count) {
-            this.count = count;
-        }
-
-        @Override
-        public LoopCount clone() {
-            return new LoopCount(count);
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<LoopCount> withStates) {
-            assert merge.forwardEndCount() == withStates.size() + 1;
-            if (merge.forwardEndCount() > 1) {
-                Set<LoopInfo> loops = mergeLoops.get(merge);
-                assert loops != null;
-                double countProd = 1;
-                for (LoopInfo loop : loops) {
-                    countProd = multiplySaturate(countProd, loop.loopFrequency(nodeProbabilities));
-                }
-                count = countProd;
-            }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            count = multiplySaturate(count, loopBegin.loopFrequency());
-        }
-    }
-
-    private class PropagateLoopFrequency extends PostOrderNodeIterator<LoopCount> {
-
-        public PropagateLoopFrequency(FixedNode start) {
-            super(start, new LoopCount(1d));
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            nodeProbabilities.put(node, nodeProbabilities.get(node) * state.count);
-        }
-
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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.phases.graph;
+
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Compute probabilities for fixed nodes on the fly and cache at {@link BeginNode}s and
+ * {@link ControlSplitNode}s.
+ */
+public class FixedNodeProbabilityCache implements ToDoubleFunction<FixedNode> {
+
+    private static final DebugMetric metricComputeNodeProbability = Debug.metric("ComputeNodeProbability");
+
+    private final Map<FixedNode, Double> cache = newIdentityMap();
+
+    public double applyAsDouble(FixedNode node) {
+        assert node != null;
+        metricComputeNodeProbability.increment();
+
+        FixedNode current = node;
+        while (true) {
+            if (current == null) {
+                return 1D;
+            }
+            Node predecessor = current.predecessor();
+            if (current instanceof BeginNode) {
+                if (predecessor == null) {
+                    break;
+                } else if (predecessor.successors().count() != 1) {
+                    assert predecessor instanceof ControlSplitNode : "a FixedNode with multiple successors needs to be a ControlSplitNode: " + current + " / " + predecessor;
+                    break;
+                }
+            } else if (predecessor == null) {
+                // this should only appear for dead code
+                return 1D;
+            }
+            current = (FixedNode) predecessor;
+        }
+
+        Double cachedValue = cache.get(current);
+        if (cachedValue != null) {
+            return cachedValue;
+        }
+
+        double probability;
+        if (current.predecessor() == null) {
+            if (current instanceof MergeNode) {
+                probability = ((MergeNode) current).forwardEnds().stream().mapToDouble(this::applyAsDouble).sum();
+                if (current instanceof LoopBeginNode) {
+                    probability *= ((LoopBeginNode) current).loopFrequency();
+                }
+            } else {
+                assert current instanceof StartNode;
+                probability = 1D;
+            }
+        } else {
+            ControlSplitNode split = (ControlSplitNode) current.predecessor();
+            probability = split.probability((BeginNode) current) * applyAsDouble(split);
+        }
+        cache.put(current, probability);
+        return probability;
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.phases.graph;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public class InferStamps {
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Fri May 30 15:09:09 2014 +0200
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.util.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -37,22 +38,23 @@
  * <p>
  * While iterating it maintains a user-defined state by calling the methods available in
  * {@link MergeableState}.
- * 
+ *
  * @param <T> the type of {@link MergeableState} handled by this PostOrderNodeIterator
  */
 public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
 
     private final NodeBitMap visitedEnds;
     private final Deque<BeginNode> nodeQueue;
-    private final IdentityHashMap<FixedNode, T> nodeStates;
+    private final Map<FixedNode, T> nodeStates;
     private final FixedNode start;
 
     protected T state;
 
     public PostOrderNodeIterator(FixedNode start, T initialState) {
-        visitedEnds = start.graph().createNodeBitMap();
+        StructuredGraph graph = start.graph();
+        visitedEnds = graph.createNodeBitMap();
         nodeQueue = new ArrayDeque<>();
-        nodeStates = new IdentityHashMap<>();
+        nodeStates = CollectionsAccess.newNodeIdentityMap();
         this.start = start;
         this.state = initialState;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.graph;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
@@ -32,8 +34,13 @@
 
     public static class LoopInfo<StateT> {
 
-        public final List<StateT> endStates = new ArrayList<>();
-        public final List<StateT> exitStates = new ArrayList<>();
+        public final List<StateT> endStates;
+        public final List<StateT> exitStates;
+
+        public LoopInfo(int endCount, int exitCount) {
+            endStates = new ArrayList<>(endCount);
+            exitStates = new ArrayList<>(exitCount);
+        }
     }
 
     public abstract static class BlockIteratorClosure<StateT> {
@@ -54,18 +61,18 @@
     }
 
     public static <StateT> LoopInfo<StateT> processLoop(BlockIteratorClosure<StateT> closure, Loop<Block> loop, StateT initialState) {
-        IdentityHashMap<FixedNode, StateT> blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks));
+        Map<FixedNode, StateT> blockEndStates = apply(closure, loop.getHeader(), initialState, new HashSet<>(loop.getBlocks()));
 
-        LoopInfo<StateT> info = new LoopInfo<>();
-        List<Block> predecessors = loop.header.getPredecessors();
+        List<Block> predecessors = loop.getHeader().getPredecessors();
+        LoopInfo<StateT> info = new LoopInfo<>(predecessors.size() - 1, loop.getExits().size());
         for (int i = 1; i < predecessors.size(); i++) {
             StateT endState = blockEndStates.get(predecessors.get(i).getEndNode());
             // make sure all end states are unique objects
             info.endStates.add(closure.cloneState(endState));
         }
-        for (Block loopExit : loop.exits) {
+        for (Block loopExit : loop.getExits()) {
             assert loopExit.getPredecessorCount() == 1;
-            assert blockEndStates.containsKey(loopExit.getBeginNode());
+            assert blockEndStates.containsKey(loopExit.getBeginNode()) : loopExit.getBeginNode() + " " + blockEndStates;
             StateT exitState = blockEndStates.get(loopExit.getBeginNode());
             // make sure all exit states are unique objects
             info.exitStates.add(closure.cloneState(exitState));
@@ -77,18 +84,20 @@
         apply(closure, start, closure.getInitialState(), null);
     }
 
-    public static <StateT> IdentityHashMap<FixedNode, StateT> apply(BlockIteratorClosure<StateT> closure, Block start, StateT initialState, Set<Block> boundary) {
+    public static <StateT> Map<FixedNode, StateT> apply(BlockIteratorClosure<StateT> closure, Block start, StateT initialState, Set<Block> boundary) {
         Deque<Block> blockQueue = new ArrayDeque<>();
         /*
          * States are stored on EndNodes before merges, and on BeginNodes after ControlSplitNodes.
          */
-        IdentityHashMap<FixedNode, StateT> states = new IdentityHashMap<>();
+        Map<FixedNode, StateT> states = newNodeIdentityMap();
 
         StateT state = initialState;
         Block current = start;
 
         while (true) {
-            if (boundary == null || boundary.contains(current)) {
+            if (boundary != null && !boundary.contains(current)) {
+                states.put(current.getBeginNode(), state);
+            } else {
                 state = closure.processBlock(current, state);
 
                 if (current.getSuccessors().isEmpty()) {
@@ -103,57 +112,59 @@
                         } else {
                             // recurse into the loop
                             Loop<Block> loop = successor.getLoop();
-                            LoopBeginNode loopBegin = (LoopBeginNode) loop.header.getBeginNode();
+                            LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode();
                             assert successor.getBeginNode() == loopBegin;
 
                             List<StateT> exitStates = closure.processLoop(loop, state);
 
                             int i = 0;
-                            assert loop.exits.size() == exitStates.size();
-                            for (Block exit : loop.exits) {
+                            assert loop.getExits().size() == exitStates.size();
+                            for (Block exit : loop.getExits()) {
                                 states.put(exit.getBeginNode(), exitStates.get(i++));
                                 blockQueue.addFirst(exit);
                             }
                         }
-                    } else {
-                        if (successor.getBeginNode() instanceof LoopExitNode) {
-                            assert successor.getPredecessors().size() == 1;
-                            states.put(successor.getBeginNode(), state);
+                    } else if (current.getEndNode() instanceof AbstractEndNode) {
+                        assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode();
+                        AbstractEndNode end = (AbstractEndNode) current.getEndNode();
+
+                        // add the end node and see if the merge is ready for processing
+                        MergeNode merge = end.merge();
+                        boolean endsVisited = true;
+                        for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
+                            if (forwardEnd != current.getEndNode() && !states.containsKey(forwardEnd)) {
+                                endsVisited = false;
+                                break;
+                            }
+                        }
+                        if (endsVisited) {
+                            ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
+                            for (Block predecessor : successor.getPredecessors()) {
+                                assert predecessor == current || states.containsKey(predecessor.getEndNode());
+                                StateT endState = predecessor == current ? state : states.remove(predecessor.getEndNode());
+                                mergedStates.add(endState);
+                            }
+                            state = closure.merge(successor, mergedStates);
                             current = successor;
                             continue;
                         } else {
-                            if (current.getEndNode() instanceof AbstractEndNode) {
-                                assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode();
-                                AbstractEndNode end = (AbstractEndNode) current.getEndNode();
-
-                                // add the end node and see if the merge is ready for processing
-                                assert !states.containsKey(end);
-                                states.put(end, state);
-                                MergeNode merge = end.merge();
-                                boolean endsVisited = true;
-                                for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
-                                    if (!states.containsKey(forwardEnd)) {
-                                        endsVisited = false;
-                                        break;
-                                    }
-                                }
-                                if (endsVisited) {
-                                    blockQueue.addFirst(successor);
-                                }
-                            } else {
-                                assert successor.getPredecessors().size() == 1 : "invalid block schedule at " + successor.getBeginNode();
-                                current = successor;
-                                continue;
-                            }
+                            assert !states.containsKey(end);
+                            states.put(end, state);
                         }
+                    } else {
+                        assert successor.getPredecessors().size() == 1 : "invalid block schedule at " + successor.getBeginNode();
+                        current = successor;
+                        continue;
                     }
                 } else {
                     assert current.getSuccessors().size() > 1;
-                    for (int i = 0; i < current.getSuccessors().size(); i++) {
+                    for (int i = 1; i < current.getSuccessors().size(); i++) {
                         Block successor = current.getSuccessors().get(i);
                         blockQueue.addFirst(successor);
-                        states.put(successor.getBeginNode(), i == 0 ? state : closure.cloneState(state));
+                        states.put(successor.getBeginNode(), closure.cloneState(state));
                     }
+                    current = current.getSuccessors().get(0);
+                    continue;
                 }
             }
 
@@ -162,20 +173,9 @@
                 return states;
             } else {
                 current = blockQueue.removeFirst();
-                if (current.getPredecessors().size() == 1) {
-                    assert states.containsKey(current.getBeginNode());
-                    state = states.get(current.getBeginNode());
-                } else {
-                    assert current.getPredecessors().size() > 1;
-                    MergeNode merge = (MergeNode) current.getBeginNode();
-                    ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
-                    for (Block predecessor : current.getPredecessors()) {
-                        AbstractEndNode end = (AbstractEndNode) predecessor.getEndNode();
-                        mergedStates.add(states.get(end));
-                    }
-                    state = closure.merge(current, mergedStates);
-                    states.put(merge, state);
-                }
+                assert current.getPredecessorCount() == 1;
+                assert states.containsKey(current.getBeginNode());
+                state = states.remove(current.getBeginNode());
             }
         }
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.graph;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.graph.NodeClass.NodeClassIterator;
@@ -31,8 +33,13 @@
 
     public static class LoopInfo<StateT> {
 
-        public final Map<LoopEndNode, StateT> endStates = new IdentityHashMap<>(4);
-        public final Map<LoopExitNode, StateT> exitStates = new IdentityHashMap<>(2);
+        public final Map<LoopEndNode, StateT> endStates;
+        public final Map<LoopExitNode, StateT> exitStates;
+
+        public LoopInfo(int endCount, int exitCount) {
+            endStates = newNodeIdentityMap(endCount);
+            exitStates = newNodeIdentityMap(exitCount);
+        }
     }
 
     public abstract static class NodeIteratorClosure<StateT> {
@@ -47,7 +54,7 @@
 
         /**
          * Determine whether iteration should continue in the current state.
-         * 
+         *
          * @param currentState
          */
         protected boolean continueIteration(StateT currentState) {
@@ -60,13 +67,9 @@
     }
 
     public static <StateT> LoopInfo<StateT> processLoop(NodeIteratorClosure<StateT> closure, LoopBeginNode loop, StateT initialState) {
-        HashSet<FixedNode> boundary = new HashSet<>();
-        for (LoopExitNode exit : loop.loopExits()) {
-            boundary.add(exit);
-        }
-        Map<FixedNode, StateT> blockEndStates = apply(closure, loop, initialState, boundary);
+        Map<FixedNode, StateT> blockEndStates = apply(closure, loop, initialState, loop);
 
-        LoopInfo<StateT> info = new LoopInfo<>();
+        LoopInfo<StateT> info = new LoopInfo<>(loop.loopEnds().count(), loop.loopExits().count());
         for (LoopEndNode end : loop.loopEnds()) {
             if (blockEndStates.containsKey(end)) {
                 info.endStates.put(end, blockEndStates.get(end));
@@ -80,15 +83,20 @@
         return info;
     }
 
-    public static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, Set<FixedNode> boundary) {
+    public static <StateT> void apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState) {
+        apply(closure, start, initialState, null);
+    }
+
+    private static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, LoopBeginNode boundary) {
+        assert start != null;
         Deque<BeginNode> nodeQueue = new ArrayDeque<>();
-        IdentityHashMap<FixedNode, StateT> blockEndStates = new IdentityHashMap<>();
+        Map<FixedNode, StateT> blockEndStates = newNodeIdentityMap();
 
         StateT state = initialState;
         FixedNode current = start;
         do {
             while (current instanceof FixedWithNextNode) {
-                if (boundary != null && boundary.contains(current)) {
+                if (boundary != null && current instanceof LoopExitNode && ((LoopExitNode) current).loopBegin() == boundary) {
                     blockEndStates.put(current, state);
                     current = null;
                 } else {
@@ -116,11 +124,9 @@
                                     nodeQueue.add(entry.getKey());
                                 }
                             } else {
-                                assert !blockEndStates.containsKey(current);
-                                blockEndStates.put(current, state);
                                 boolean endsVisited = true;
                                 for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
-                                    if (!blockEndStates.containsKey(forwardEnd)) {
+                                    if (forwardEnd != current && !blockEndStates.containsKey(forwardEnd)) {
                                         endsVisited = false;
                                         break;
                                     }
@@ -129,13 +135,16 @@
                                     ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
                                     for (int i = 0; i < merge.forwardEndCount(); i++) {
                                         AbstractEndNode forwardEnd = merge.forwardEndAt(i);
-                                        assert blockEndStates.containsKey(forwardEnd);
-                                        StateT other = blockEndStates.get(forwardEnd);
+                                        assert forwardEnd == current || blockEndStates.containsKey(forwardEnd);
+                                        StateT other = forwardEnd == current ? state : blockEndStates.remove(forwardEnd);
                                         states.add(other);
                                     }
                                     state = closure.merge(merge, states);
                                     current = closure.continueIteration(state) ? merge : null;
                                     continue;
+                                } else {
+                                    assert !blockEndStates.containsKey(current);
+                                    blockEndStates.put(current, state);
                                 }
                             }
                         }
@@ -145,14 +154,15 @@
                             current = firstSuccessor;
                             continue;
                         } else {
-                            while (successors.hasNext()) {
+                            do {
                                 BeginNode successor = (BeginNode) successors.next();
                                 StateT successorState = closure.afterSplit(successor, state);
                                 if (closure.continueIteration(successorState)) {
                                     blockEndStates.put(successor, successorState);
                                     nodeQueue.add(successor);
                                 }
-                            }
+                            } while (successors.hasNext());
+
                             state = closure.afterSplit((BeginNode) firstSuccessor, state);
                             current = closure.continueIteration(state) ? firstSuccessor : null;
                             continue;
@@ -166,7 +176,8 @@
                 return blockEndStates;
             } else {
                 current = nodeQueue.removeFirst();
-                state = blockEndStates.get(current);
+                assert blockEndStates.containsKey(current);
+                state = blockEndStates.remove(current);
                 assert !(current instanceof MergeNode) && current instanceof BeginNode;
             }
         } while (true);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.graph;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.util.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A SinglePassNodeIterator iterates the fixed nodes of the graph in post order starting from its
+ * start node. Unlike in iterative dataflow analysis, a single pass is performed, which allows
+ * keeping a smaller working set of pending {@link MergeableState}. This iteration scheme requires:
+ * <ul>
+ * <li>{@link MergeableState#merge(MergeNode, List)} to always return <code>true</code> (an
+ * assertion checks this)</li>
+ * <li>{@link #controlSplit(ControlSplitNode)} to always return all successors (otherwise, not all
+ * associated {@link EndNode} will be visited. In turn, visiting all the end nodes for a given
+ * {@link MergeNode} is a precondition before that merge node can be visited)</li>
+ * </ul>
+ *
+ * <p>
+ * For this iterator the CFG is defined by the classical CFG nodes (
+ * {@link com.oracle.graal.nodes.ControlSplitNode}, {@link com.oracle.graal.nodes.MergeNode}...) and
+ * the {@link com.oracle.graal.nodes.FixedWithNextNode#next() next} pointers of
+ * {@link com.oracle.graal.nodes.FixedWithNextNode}.
+ * </p>
+ *
+ * <p>
+ * The lifecycle that single-pass node iterators go through is described in {@link #apply()}
+ * </p>
+ *
+ * @param <T> the type of {@link MergeableState} handled by this SinglePassNodeIterator
+ */
+public abstract class SinglePassNodeIterator<T extends MergeableState<T>> {
+
+    private final NodeBitMap visitedEnds;
+
+    /**
+     * @see SinglePassNodeIterator.PathStart
+     */
+    private final Deque<PathStart<T>> nodeQueue;
+
+    /**
+     * The keys in this map may be:
+     * <ul>
+     * <li>loop-begins and loop-ends, see {@link #finishLoopEnds(LoopEndNode)}</li>
+     * <li>forward-ends of merge-nodes, see {@link #queueMerge(EndNode)}</li>
+     * </ul>
+     *
+     * <p>
+     * It's tricky to answer whether the state an entry contains is the pre-state or the post-state
+     * for the key in question, because states are mutable. Thus an entry may be created to contain
+     * a pre-state (at the time, as done for a loop-begin in {@link #apply()}) only to make it a
+     * post-state soon after (continuing with the loop-begin example, also in {@link #apply()}). In
+     * any case, given that keys are limited to the nodes mentioned in the previous paragraph, in
+     * all cases an entry can be considered to hold a post-state by the time such entry is
+     * retrieved.
+     * </p>
+     *
+     * <p>
+     * The only method that makes this map grow is {@link #keepForLater(FixedNode, MergeableState)}
+     * and the only one that shrinks it is {@link #pruneEntry(FixedNode)}. To make sure no entry is
+     * left behind inadvertently, asserts in {@link #finished()} are in place.
+     * </p>
+     */
+    private final Map<FixedNode, T> nodeStates;
+
+    private final StartNode start;
+
+    protected T state;
+
+    /**
+     * An item queued in {@link #nodeQueue} can be used to continue with the single-pass visit after
+     * the previous path can't be followed anymore. Such items are:
+     * <ul>
+     * <li>de-queued via {@link #nextQueuedNode()}</li>
+     * <li>en-queued via {@link #queueMerge(EndNode)} and {@link #queueSuccessors(FixedNode)}</li>
+     * </ul>
+     *
+     * <p>
+     * Correspondingly each item may stand for:
+     * <ul>
+     * <li>a {@link MergeNode} whose pre-state results from merging those of its forward-ends, see
+     * {@link #nextQueuedNode()}</li>
+     * <li>a successor of a control-split node, in which case the state on entry to it (the
+     * successor) is also stored in the item, see {@link #nextQueuedNode()}</li>
+     * </ul>
+     * </p>
+     */
+    private static class PathStart<U> {
+        private final BeginNode node;
+        private final U stateOnEntry;
+
+        private PathStart(BeginNode node, U stateOnEntry) {
+            this.node = node;
+            this.stateOnEntry = stateOnEntry;
+            assert repOK();
+        }
+
+        /**
+         * @return true iff this instance is internally consistent (ie, its "representation is OK")
+         */
+        private boolean repOK() {
+            if (node == null) {
+                return false;
+            }
+            if (node instanceof MergeNode) {
+                return stateOnEntry == null;
+            }
+            return (stateOnEntry != null);
+        }
+    }
+
+    public SinglePassNodeIterator(StartNode start, T initialState) {
+        StructuredGraph graph = start.graph();
+        visitedEnds = graph.createNodeBitMap();
+        nodeQueue = new ArrayDeque<>();
+        nodeStates = CollectionsAccess.newNodeIdentityMap();
+        this.start = start;
+        this.state = initialState;
+    }
+
+    /**
+     * Performs a single-pass iteration.
+     *
+     * <p>
+     * After this method has been invoked, the {@link SinglePassNodeIterator} instance can't be used
+     * again. This saves clearing up fields in {@link #finished()}, the assumption being that this
+     * instance will be garbage-collected soon afterwards.
+     * </p>
+     */
+    public void apply() {
+        FixedNode current = start;
+
+        do {
+            if (current instanceof InvokeWithExceptionNode) {
+                invoke((Invoke) current);
+                queueSuccessors(current);
+                current = nextQueuedNode();
+            } else if (current instanceof LoopBeginNode) {
+                state.loopBegin((LoopBeginNode) current);
+                keepForLater(current, state);
+                state = state.clone();
+                loopBegin((LoopBeginNode) current);
+                current = ((LoopBeginNode) current).next();
+                assert current != null;
+            } else if (current instanceof LoopEndNode) {
+                loopEnd((LoopEndNode) current);
+                finishLoopEnds((LoopEndNode) current);
+                current = nextQueuedNode();
+            } else if (current instanceof MergeNode) {
+                merge((MergeNode) current);
+                current = ((MergeNode) current).next();
+                assert current != null;
+            } else if (current instanceof FixedWithNextNode) {
+                FixedNode next = ((FixedWithNextNode) current).next();
+                assert next != null : current;
+                node(current);
+                current = next;
+            } else if (current instanceof EndNode) {
+                end((EndNode) current);
+                queueMerge((EndNode) current);
+                current = nextQueuedNode();
+            } else if (current instanceof ControlSinkNode) {
+                node(current);
+                current = nextQueuedNode();
+            } else if (current instanceof ControlSplitNode) {
+                controlSplit((ControlSplitNode) current);
+                queueSuccessors(current);
+                current = nextQueuedNode();
+            } else {
+                assert false : current;
+            }
+        } while (current != null);
+        finished();
+    }
+
+    /**
+     * Two methods enqueue items in {@link #nodeQueue}. Of them, only this method enqueues items
+     * with non-null state (the other method being {@link #queueMerge(EndNode)}).
+     *
+     * <p>
+     * A space optimization is made: the state is cloned for all successors except the first. Given
+     * that right after invoking this method, {@link #nextQueuedNode()} is invoked, that single
+     * non-cloned state instance is in effect "handed over" to its next owner (thus realizing an
+     * owner-is-mutator access protocol).
+     * </p>
+     */
+    private void queueSuccessors(FixedNode x) {
+        Iterator<Node> iter = x.successors().nonNull().iterator();
+        if (iter.hasNext()) {
+            BeginNode begin = (BeginNode) iter.next();
+            // the current state isn't cloned for the first successor
+            // conceptually, the state is handed over to it
+            nodeQueue.addFirst(new PathStart<>(begin, state));
+        }
+        while (iter.hasNext()) {
+            BeginNode begin = (BeginNode) iter.next();
+            // for all other successors it is cloned
+            nodeQueue.addFirst(new PathStart<>(begin, state.clone()));
+        }
+    }
+
+    /**
+     * This method is invoked upon not having a (single) next {@link FixedNode} to visit. This
+     * method picks such next-node-to-visit from {@link #nodeQueue} and updates {@link #state} with
+     * the pre-state for that node.
+     *
+     * <p>
+     * Upon reaching a {@link MergeNode}, some entries are pruned from {@link #nodeStates} (ie, the
+     * entries associated to forward-ends for that merge-node).
+     * </p>
+     */
+    private FixedNode nextQueuedNode() {
+        if (nodeQueue.isEmpty()) {
+            return null;
+        }
+        PathStart<T> elem = nodeQueue.removeFirst();
+        if (elem.node instanceof MergeNode) {
+            MergeNode merge = (MergeNode) elem.node;
+            state = pruneEntry(merge.forwardEndAt(0));
+            ArrayList<T> states = new ArrayList<>(merge.forwardEndCount() - 1);
+            for (int i = 1; i < merge.forwardEndCount(); i++) {
+                T other = pruneEntry(merge.forwardEndAt(i));
+                states.add(other);
+            }
+            boolean ready = state.merge(merge, states);
+            assert ready : "Not a single-pass iterator after all";
+            return merge;
+        } else {
+            BeginNode begin = elem.node;
+            assert begin.predecessor() != null;
+            state = elem.stateOnEntry;
+            state.afterSplit(begin);
+            return begin;
+        }
+    }
+
+    /**
+     * Once all loop-end-nodes for a given loop-node have been visited:
+     * <ul>
+     * <li>the state for that loop-node is updated based on the states of the loop-end-nodes</li>
+     * <li>entries in {@link #nodeStates} are pruned for the loop (they aren't going to be looked up
+     * again, anyway)</li>
+     * </ul>
+     *
+     * <p>
+     * The entries removed by this method were inserted:
+     * <ul>
+     * <li>for the loop-begin, by {@link #apply()}</li>
+     * <li>for loop-ends, by (previous) invocations of this method</li>
+     * </ul>
+     * </p>
+     */
+    private void finishLoopEnds(LoopEndNode end) {
+        assert !visitedEnds.isMarked(end);
+        visitedEnds.mark(end);
+        keepForLater(end, state);
+        LoopBeginNode begin = end.loopBegin();
+        boolean endsVisited = true;
+        for (LoopEndNode le : begin.loopEnds()) {
+            if (!visitedEnds.isMarked(le)) {
+                endsVisited = false;
+                break;
+            }
+        }
+        if (endsVisited) {
+            ArrayList<T> states = new ArrayList<>(begin.loopEnds().count());
+            for (LoopEndNode le : begin.orderedLoopEnds()) {
+                T leState = pruneEntry(le);
+                states.add(leState);
+            }
+            T loopBeginState = pruneEntry(begin);
+            loopBeginState.loopEnds(begin, states);
+        }
+    }
+
+    /**
+     * Once all end-nodes for a given merge-node have been visited, that merge-node is added to the
+     * {@link #nodeQueue}
+     *
+     * <p>
+     * {@link #nextQueuedNode()} is in charge of pruning entries (held by {@link #nodeStates}) for
+     * the forward-ends inserted by this method.
+     * </p>
+     */
+    private void queueMerge(EndNode end) {
+        assert !visitedEnds.isMarked(end);
+        visitedEnds.mark(end);
+        keepForLater(end, state);
+        MergeNode merge = end.merge();
+        boolean endsVisited = true;
+        for (int i = 0; i < merge.forwardEndCount(); i++) {
+            if (!visitedEnds.isMarked(merge.forwardEndAt(i))) {
+                endsVisited = false;
+                break;
+            }
+        }
+        if (endsVisited) {
+            nodeQueue.add(new PathStart<>(merge, null));
+        }
+    }
+
+    protected abstract void node(FixedNode node);
+
+    protected void end(EndNode endNode) {
+        node(endNode);
+    }
+
+    protected void merge(MergeNode merge) {
+        node(merge);
+    }
+
+    protected void loopBegin(LoopBeginNode loopBegin) {
+        node(loopBegin);
+    }
+
+    protected void loopEnd(LoopEndNode loopEnd) {
+        node(loopEnd);
+    }
+
+    protected void controlSplit(ControlSplitNode controlSplit) {
+        node(controlSplit);
+    }
+
+    protected void invoke(Invoke invoke) {
+        node(invoke.asNode());
+    }
+
+    /**
+     * The lifecycle that single-pass node iterators go through is described in {@link #apply()}
+     *
+     * <p>
+     * When overriding this method don't forget to invoke this implementation, otherwise the
+     * assertions will be skipped.
+     * </p>
+     */
+    protected void finished() {
+        assert nodeQueue.isEmpty();
+        assert nodeStates.isEmpty();
+    }
+
+    private void keepForLater(FixedNode x, T s) {
+        assert !nodeStates.containsKey(x);
+        assert (x instanceof LoopBeginNode) || (x instanceof LoopEndNode) || (x instanceof EndNode);
+        assert s != null;
+        nodeStates.put(x, s);
+    }
+
+    private T pruneEntry(FixedNode x) {
+        T result = nodeStates.remove(x);
+        assert result != null;
+        return result;
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,8 @@
 package com.oracle.graal.phases.schedule;
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.nodes.cfg.ControlFlowGraph.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
 
@@ -83,32 +83,56 @@
     }
 
     private class KillSet implements Iterable<LocationIdentity> {
-        private final Set<LocationIdentity> set;
+        private List<LocationIdentity> list;
 
         public KillSet() {
-            this.set = new ArraySet<>();
+            list = null;
         }
 
         public KillSet(KillSet other) {
-            this.set = new HashSet<>(other.set);
+            if (other.list != null && other.list.size() > 0) {
+                list = new ArrayList<>(other.list);
+            }
+        }
+
+        private void initSet() {
+            if (list == null) {
+                list = new ArrayList<>(4);
+            }
         }
 
         public void add(LocationIdentity locationIdentity) {
-            set.add(locationIdentity);
+            if (list == null || !list.contains(locationIdentity)) {
+                initSet();
+                list.add(locationIdentity);
+            }
         }
 
         public void addAll(KillSet other) {
-            set.addAll(other.set);
+            if (other.list == null) {
+                return;
+            }
+            initSet();
+            for (LocationIdentity locationIdentity : other) {
+                if (!list.contains(locationIdentity)) {
+                    list.add(locationIdentity);
+                }
+            }
         }
 
         public Iterator<LocationIdentity> iterator() {
-            return set.iterator();
+            if (list == null) {
+                return Collections.emptyIterator();
+            }
+            return list.iterator();
         }
 
         public boolean isKilled(LocationIdentity locationIdentity) {
-            return set.contains(locationIdentity);
+            if (list == null) {
+                return false;
+            }
+            return list.contains(locationIdentity);
         }
-
     }
 
     private class NewMemoryScheduleClosure extends BlockIteratorClosure<KillSet> {
@@ -157,8 +181,8 @@
         protected List<KillSet> processLoop(Loop<Block> loop, KillSet state) {
             LoopInfo<KillSet> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(state));
 
-            assert loop.header.getBeginNode() instanceof LoopBeginNode;
-            KillSet headerState = merge(loop.header, info.endStates);
+            assert loop.getHeader().getBeginNode() instanceof LoopBeginNode;
+            KillSet headerState = merge(loop.getHeader(), info.endStates);
 
             // second iteration, for propagating information to loop exits
             info = ReentrantBlockIterator.processLoop(this, loop, cloneState(headerState));
@@ -211,18 +235,17 @@
             if (!foundExcludeNode && node == excludeNode) {
                 foundExcludeNode = true;
             }
-            if (node == startNode) {
-                continue;
+            if (node != startNode) {
+                if (node instanceof MemoryCheckpoint.Single) {
+                    LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+                    accm.add(identity);
+                } else if (node instanceof MemoryCheckpoint.Multi) {
+                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                        accm.add(identity);
+                    }
+                }
+                assert MemoryCheckpoint.TypeAssertion.correctType(node);
             }
-            if (node instanceof MemoryCheckpoint.Single) {
-                LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
-                accm.add(identity);
-            } else if (node instanceof MemoryCheckpoint.Multi) {
-                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
-                    accm.add(identity);
-                }
-            }
-            assert MemoryCheckpoint.TypeAssertion.correctType(node);
 
             if (foundExcludeNode) {
                 accm = set;
@@ -888,37 +911,114 @@
         return true;
     }
 
+    private static class SortState {
+        private Block block;
+        private NodeBitMap visited;
+        private NodeBitMap beforeLastLocation;
+        private List<ScheduledNode> sortedInstructions;
+        private List<FloatingReadNode> reads;
+
+        SortState(Block block, NodeBitMap visited, NodeBitMap beforeLastLocation, List<ScheduledNode> sortedInstructions) {
+            this.block = block;
+            this.visited = visited;
+            this.beforeLastLocation = beforeLastLocation;
+            this.sortedInstructions = sortedInstructions;
+            this.reads = null;
+        }
+
+        public Block currentBlock() {
+            return block;
+        }
+
+        void markVisited(Node n) {
+            visited.mark(n);
+        }
+
+        boolean isVisited(Node n) {
+            return visited.isMarked(n);
+        }
+
+        void markBeforeLastLocation(FloatingReadNode n) {
+            beforeLastLocation.mark(n);
+        }
+
+        void clearBeforeLastLocation(FloatingReadNode frn) {
+            beforeLastLocation.clear(frn);
+        }
+
+        boolean isBeforeLastLocation(FloatingReadNode n) {
+            return beforeLastLocation.isMarked(n);
+        }
+
+        void addRead(FloatingReadNode n) {
+            if (reads == null) {
+                reads = new ArrayList<>();
+            }
+            reads.add(n);
+        }
+
+        int readsSize() {
+            if (reads == null) {
+                return 0;
+            }
+            return reads.size();
+        }
+
+        void removeRead(ScheduledNode i) {
+            assert reads != null;
+            reads.remove(i);
+        }
+
+        List<FloatingReadNode> readsSnapshot() {
+            assert reads != null;
+            return new ArrayList<>(reads);
+        }
+
+        List<ScheduledNode> getSortedInstructions() {
+            return sortedInstructions;
+        }
+
+        boolean containsInstruction(ScheduledNode i) {
+            return sortedInstructions.contains(i);
+        }
+
+        void addInstruction(ScheduledNode i) {
+            sortedInstructions.add(i);
+        }
+    }
+
     /**
      * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over
      * all inputs. This means that a node is added to the list after all its inputs have been
      * processed.
      */
     private List<ScheduledNode> sortNodesWithinBlockLatest(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation) {
+        SortState state = new SortState(b, visited, beforeLastLocation, new ArrayList<>(blockToNodesMap.get(b).size() + 2));
         List<ScheduledNode> instructions = blockToNodesMap.get(b);
-        List<ScheduledNode> sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2);
-        List<FloatingReadNode> reads = new ArrayList<>();
 
         if (memsched == MemoryScheduling.OPTIMAL) {
             for (ScheduledNode i : instructions) {
                 if (i instanceof FloatingReadNode) {
                     FloatingReadNode frn = (FloatingReadNode) i;
                     if (frn.location().getLocationIdentity() != FINAL_LOCATION) {
-                        reads.add(frn);
+                        state.addRead(frn);
                         if (nodesFor(b).contains(frn.getLastLocationAccess())) {
-                            assert !beforeLastLocation.isMarked(frn);
-                            beforeLastLocation.mark(frn);
+                            assert !state.isBeforeLastLocation(frn);
+                            state.markBeforeLastLocation(frn);
                         }
                     }
                 }
             }
         }
+
         for (ScheduledNode i : instructions) {
-            addToLatestSorting(b, i, sortedInstructions, visited, reads, beforeLastLocation);
+            addToLatestSorting(i, state);
         }
-        assert reads.size() == 0 : "not all reads are scheduled";
+        assert state.readsSize() == 0 : "not all reads are scheduled";
 
         // Make sure that last node gets really last (i.e. when a frame state successor hangs off
         // it).
+        List<ScheduledNode> sortedInstructions = state.getSortedInstructions();
         Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1);
         if (lastSorted != b.getEndNode()) {
             int idx = sortedInstructions.indexOf(b.getEndNode());
@@ -944,40 +1044,39 @@
         return sortedInstructions;
     }
 
-    private void processKillLocation(Block b, Node node, LocationIdentity identity, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads,
-                    NodeBitMap beforeLastLocation) {
-        for (FloatingReadNode frn : new ArrayList<>(reads)) { // TODO: change to iterator?
+    private void processKillLocation(Node node, LocationIdentity identity, SortState state) {
+        for (FloatingReadNode frn : state.readsSnapshot()) {
             LocationIdentity readLocation = frn.location().getLocationIdentity();
             assert readLocation != FINAL_LOCATION;
             if (frn.getLastLocationAccess() == node) {
                 assert identity == ANY_LOCATION || readLocation == identity : "location doesn't match: " + readLocation + ", " + identity;
-                beforeLastLocation.clear(frn);
-            } else if (!beforeLastLocation.isMarked(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
-                reads.remove(frn);
-                addToLatestSorting(b, frn, sortedInstructions, visited, reads, beforeLastLocation);
+                state.clearBeforeLastLocation(frn);
+            } else if (!state.isBeforeLastLocation(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
+                state.removeRead(frn);
+                addToLatestSorting(frn, state);
             }
         }
     }
 
-    private void addUnscheduledToLatestSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) {
+    private void addUnscheduledToLatestSorting(VirtualState state, SortState sortState) {
         if (state != null) {
             // UnscheduledNodes should never be marked as visited.
-            if (visited.isMarked(state)) {
+            if (sortState.isVisited(state)) {
                 throw new SchedulingError();
             }
 
             for (Node input : state.inputs()) {
                 if (input instanceof VirtualState) {
-                    addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addUnscheduledToLatestSorting((VirtualState) input, sortState);
                 } else {
-                    addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addToLatestSorting((ScheduledNode) input, sortState);
                 }
             }
         }
     }
 
-    private void addToLatestSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) {
-        if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode) {
+    private void addToLatestSorting(ScheduledNode i, SortState state) {
+        if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) {
             return;
         }
 
@@ -986,39 +1085,47 @@
             stateAfter = ((StateSplit) i).stateAfter();
         }
 
+        if (i instanceof LoopExitNode) {
+            for (ProxyNode proxy : ((LoopExitNode) i).proxies()) {
+                addToLatestSorting(proxy, state);
+            }
+        }
+
         for (Node input : i.inputs()) {
             if (input instanceof FrameState) {
                 if (input != stateAfter) {
-                    addUnscheduledToLatestSorting(b, (FrameState) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addUnscheduledToLatestSorting((FrameState) input, state);
                 }
             } else {
-                addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+                if (!(i instanceof ProxyNode && input instanceof LoopExitNode)) {
+                    addToLatestSorting((ScheduledNode) input, state);
+                }
             }
         }
 
-        if (memsched == MemoryScheduling.OPTIMAL && reads.size() != 0) {
+        if (memsched == MemoryScheduling.OPTIMAL && state.readsSize() != 0) {
             if (i instanceof MemoryCheckpoint.Single) {
                 LocationIdentity identity = ((MemoryCheckpoint.Single) i).getLocationIdentity();
-                processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+                processKillLocation(i, identity, state);
             } else if (i instanceof MemoryCheckpoint.Multi) {
                 for (LocationIdentity identity : ((MemoryCheckpoint.Multi) i).getLocationIdentities()) {
-                    processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+                    processKillLocation(i, identity, state);
                 }
             }
             assert MemoryCheckpoint.TypeAssertion.correctType(i);
         }
 
-        addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited, reads, beforeLastLocation);
-        visited.mark(i);
-        addUnscheduledToLatestSorting(b, stateAfter, sortedInstructions, visited, reads, beforeLastLocation);
+        addToLatestSorting((ScheduledNode) i.predecessor(), state);
+        state.markVisited(i);
+        addUnscheduledToLatestSorting(stateAfter, state);
 
         // Now predecessors and inputs are scheduled => we can add this node.
-        if (!sortedInstructions.contains(i)) {
-            sortedInstructions.add(i);
+        if (!state.containsInstruction(i)) {
+            state.addInstruction(i);
         }
 
-        if (i instanceof FloatingReadNode) {
-            reads.remove(i);
+        if (state.readsSize() != 0 && i instanceof FloatingReadNode) {
+            state.removeRead(i);
         }
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.phases.tiers;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.phases.*;
 
-public interface CompilerConfiguration {
+public interface CompilerConfiguration extends Service {
 
     PhaseSuite<HighTierContext> createHighTier();
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
@@ -65,7 +66,7 @@
         CompilerConfiguration nonBasic = null;
         int nonBasicCount = 0;
 
-        for (CompilerConfiguration config : ServiceLoader.loadInstalled(CompilerConfiguration.class)) {
+        for (CompilerConfiguration config : Services.load(CompilerConfiguration.class)) {
             String name = config.getClass().getSimpleName();
             if (name.endsWith("CompilerConfiguration")) {
                 name = name.substring(0, name.length() - "CompilerConfiguration".length());
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/ArraySet.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/ArraySet.java	Fri May 30 15:09:09 2014 +0200
@@ -47,7 +47,7 @@
     public boolean add(E e) {
         // avoid duplicated entries
         if (contains(e)) {
-            return true;
+            return false;
         }
         return super.add(e);
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.util;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.compiler.common.*;
@@ -30,6 +32,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 import com.oracle.graal.phases.schedule.*;
@@ -135,7 +138,7 @@
     public static boolean assertSchedulableGraph(final StructuredGraph graph) {
         try {
             final SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, MemoryScheduling.NONE);
-            final IdentityHashMap<LoopBeginNode, NodeBitMap> loopEntryStates = new IdentityHashMap<>();
+            final Map<LoopBeginNode, NodeBitMap> loopEntryStates = newNodeIdentityMap();
             schedule.apply(graph, false);
 
             BlockIteratorClosure<NodeBitMap> closure = new BlockIteratorClosure<NodeBitMap>() {
@@ -164,7 +167,8 @@
                         if (pendingStateAfter != null && node instanceof FixedNode) {
                             pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
                                 public void apply(Node usage, Node nonVirtualNode) {
-                                    assert currentState.isMarked(nonVirtualNode) : nonVirtualNode + " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list;
+                                    assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode : nonVirtualNode + " not available at virtualstate " + usage +
+                                                    " before " + node + " in block " + block + " \n" + list;
                                 }
                             });
                             pendingStateAfter = null;
@@ -199,7 +203,7 @@
                                             assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list;
                                         });
                                     } else {
-                                        assert currentState.isMarked(input) : input + " not available at " + node + " in block " + block + "\n" + list;
+                                        assert currentState.isMarked(input) || input instanceof VirtualObjectNode : input + " not available at " + node + " in block " + block + "\n" + list;
                                     }
                                 }
                             }
@@ -220,7 +224,8 @@
                     if (pendingStateAfter != null) {
                         pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
                             public void apply(Node usage, Node nonVirtualNode) {
-                                assert currentState.isMarked(nonVirtualNode) : nonVirtualNode + " not available at virtualstate " + usage + " at end of block " + block + " \n" + list;
+                                assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode : nonVirtualNode + " not available at virtualstate " + usage +
+                                                " at end of block " + block + " \n" + list;
                             }
                         });
                     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Providers.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Providers.java	Fri May 30 15:09:09 2014 +0200
@@ -24,13 +24,14 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
  * A set of providers, some of which may not be present (i.e., null).
  */
-public class Providers {
+public class Providers implements CodeGenProviders {
 
     private final MetaAccessProvider metaAccess;
     private final CodeCacheProvider codeCache;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.phases.verify;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
@@ -45,7 +46,7 @@
     private boolean isAssignableType(ValueNode node, MetaAccessProvider metaAccess) {
         if (node.stamp() instanceof ObjectStamp) {
             ResolvedJavaType valueType = metaAccess.lookupJavaType(klass);
-            ResolvedJavaType nodeType = ObjectStamp.typeOrNull(node);
+            ResolvedJavaType nodeType = StampTool.typeOrNull(node);
 
             if (nodeType != null && valueType.isAssignableFrom(nodeType)) {
                 return true;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.printer;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.io.*;
 import java.nio.*;
 import java.nio.channels.*;
 import java.util.*;
 import java.util.Map.Entry;
+import java.util.function.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
@@ -36,7 +37,6 @@
 import com.oracle.graal.graph.NodeClass.Position;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 
@@ -137,7 +137,7 @@
         }
         ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
         BlockMap<List<ScheduledNode>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
-        Block[] blocks = cfg == null ? null : cfg.getBlocks();
+        List<Block> blocks = cfg == null ? null : cfg.getBlocks();
         writeNodes(graph);
         writeBlocks(blocks, blockToNodes);
     }
@@ -394,10 +394,10 @@
     }
 
     private void writeNodes(Graph graph) throws IOException {
-        NodesToDoubles probabilities = null;
+        ToDoubleFunction<FixedNode> probabilities = null;
         if (PrintGraphProbabilities.getValue()) {
             try {
-                probabilities = new ComputeProbabilityClosure((StructuredGraph) graph).apply();
+                probabilities = new FixedNodeProbabilityCache();
             } catch (Throwable t) {
             }
         }
@@ -408,8 +408,8 @@
         for (Node node : graph.getNodes()) {
             NodeClass nodeClass = node.getNodeClass();
             node.getDebugProperties(props);
-            if (probabilities != null && node instanceof FixedNode && probabilities.contains((FixedNode) node)) {
-                props.put("probability", probabilities.get((FixedNode) node));
+            if (probabilities != null && node instanceof FixedNode) {
+                props.put("probability", probabilities.applyAsDouble((FixedNode) node));
             }
             writeInt(getNodeId(node));
             writePoolObject(nodeClass);
@@ -460,9 +460,9 @@
         }
     }
 
-    private void writeBlocks(Block[] blocks, BlockMap<List<ScheduledNode>> blockToNodes) throws IOException {
+    private void writeBlocks(List<Block> blocks, BlockMap<List<ScheduledNode>> blockToNodes) throws IOException {
         if (blocks != null) {
-            writeInt(blocks.length);
+            writeInt(blocks.size());
             for (Block block : blocks) {
                 List<ScheduledNode> nodes = blockToNodes.get(block);
                 writeInt(block.getId());
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Fri May 30 15:09:09 2014 +0200
@@ -256,8 +256,8 @@
         out.println();
 
         if (block.getLoop() != null) {
-            out.print("loop_index ").println(block.getLoop().index);
-            out.print("loop_depth ").println(block.getLoop().depth);
+            out.print("loop_index ").println(block.getLoop().getIndex());
+            out.print("loop_depth ").println(block.getLoop().getDepth());
         }
     }
 
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Fri May 30 15:09:09 2014 +0200
@@ -174,7 +174,7 @@
                 StructuredGraph graph = (StructuredGraph) object;
                 cfgPrinter.cfg = ControlFlowGraph.compute(graph, true, true, true, false);
             }
-            cfgPrinter.printCFG(message, Arrays.asList(cfgPrinter.cfg.getBlocks()), true);
+            cfgPrinter.printCFG(message, cfgPrinter.cfg.getBlocks(), true);
 
         } else if (object instanceof CompilationResult) {
             final CompilationResult compResult = (CompilationResult) object;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Fri May 30 15:09:09 2014 +0200
@@ -23,17 +23,23 @@
 package com.oracle.graal.printer;
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.io.*;
 import java.util.*;
 
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.debug.*;
 
 public class DebugEnvironment {
 
     public static GraalDebugConfig initialize(PrintStream log) {
+
+        // Ensure Graal runtime is initialized prior to Debug being initialized as the former
+        // included processing command line options used by the latter.
+        Graal.getRuntime();
+
         if (!Debug.isEnabled()) {
             log.println("WARNING: Scope debugging needs to be enabled with -esa or -D" + Debug.Initialization.INITIALIZER_PROPERTY_NAME + "=true");
             return null;
@@ -49,7 +55,7 @@
         if (DecompileAfterPhase.getValue() != null) {
             dumpHandlers.add(new DecompilerDebugDumpHandler());
         }
-        GraalDebugConfig debugConfig = new GraalDebugConfig(Log.getValue(), Meter.getValue(), Time.getValue(), Dump.getValue(), MethodFilter.getValue(), log, dumpHandlers);
+        GraalDebugConfig debugConfig = new GraalDebugConfig(Log.getValue(), Meter.getValue(), TrackMemUse.getValue(), Time.getValue(), Dump.getValue(), MethodFilter.getValue(), log, dumpHandlers);
         Debug.setConfig(debugConfig);
         return debugConfig;
     }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DecompilerDebugDumpHandler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DecompilerDebugDumpHandler.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.printer;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.io.*;
 import java.util.concurrent.atomic.*;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.printer;
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.io.*;
 import java.net.*;
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,11 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
 import com.oracle.graal.nodes.spi.*;
 
 /**
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -23,10 +23,13 @@
 
 package com.oracle.graal.replacements.amd64;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
@@ -37,10 +40,10 @@
 @ServiceProvider(ReplacementsProvider.class)
 public class AMD64Substitutions implements ReplacementsProvider {
 
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         if (Intrinsify.getValue()) {
-            replacements.registerSubstitutions(ArraysSubstitutions.class);
-            replacements.registerSubstitutions(StringSubstitutions.class);
+            replacements.registerSubstitutions(Arrays.class, ArraysSubstitutions.class);
+            replacements.registerSubstitutions(String.class, StringSubstitutions.class);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,14 +24,15 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.hsail.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This node implements HSAIL intrinsics for specific {@link Math} routines.
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Fri May 30 15:09:09 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
@@ -78,9 +79,9 @@
             Object arg1 = args1[i];
             Object arg2 = args2[i];
             // Verify that the original method and the substitution produce the same value
-            assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
+            assertDeepEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
             // Verify that the generated code and the original produce the same value
-            assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
+            assertDeepEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2));
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.replacements.test;
 
+import org.junit.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of checkcast, allowing profiling information to be manually specified.
@@ -41,7 +42,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("asNumber", profile(), 111);
         test("asNumber", profile(Integer.class), 111);
@@ -51,7 +52,7 @@
         test("asNumberExt", profile(Long.class, Short.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("asString", profile(), "111");
         test("asString", profile(String.class), "111");
@@ -67,27 +68,27 @@
         test("asStringExt", profile(String.class), "111");
     }
 
-    @LongTest
+    @Test
     public void test3() {
         test("asNumber", profile(), "111");
     }
 
-    @LongTest
+    @Test
     public void test4() {
         test("asString", profile(String.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test5() {
         test("asNumberExt", profile(), "111");
     }
 
-    @LongTest
+    @Test
     public void test6() {
         test("asStringExt", profile(String.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test7() {
         Throwable throwable = new Exception();
         test("asThrowable", profile(), throwable);
@@ -95,12 +96,12 @@
         test("asThrowable", profile(Exception.class, Error.class), throwable);
     }
 
-    @LongTest
+    @Test
     public void test8() {
         test("arrayStore", new Object[100], "111");
     }
 
-    @LongTest
+    @Test
     public void test801() {
         test("arrayFill", new Object[100], "111");
     }
@@ -197,7 +198,7 @@
         return (Cloneable) o;
     }
 
-    @LongTest
+    @Test
     public void test9() {
         Object o = new Depth13();
         test("asDepth12", profile(), o);
@@ -205,7 +206,7 @@
         test("asDepth12", profile(Depth13.class, Depth14.class), o);
     }
 
-    @LongTest
+    @Test
     public void test10() {
         Object o = new Depth13[3][];
         test("asDepth12Arr", o);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.replacements.test;
 
+import org.junit.*;
+
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests for {@link InstanceOfDynamicNode}.
@@ -35,7 +36,7 @@
         return value;
     }
 
-    @LongTest
+    @Test
     public void test100() {
         final Object nul = null;
         test("isStringDynamic", nul);
@@ -43,7 +44,7 @@
         test("isStringDynamic", Object.class);
     }
 
-    @LongTest
+    @Test
     public void test101() {
         final Object nul = null;
         test("isStringIntDynamic", nul);
@@ -51,7 +52,7 @@
         test("isStringIntDynamic", Object.class);
     }
 
-    @LongTest
+    @Test
     public void test103() {
         test("isInstanceDynamic", String.class, null);
         test("isInstanceDynamic", String.class, "object");
@@ -61,7 +62,7 @@
         test("isInstanceDynamic", int.class, Object.class);
     }
 
-    @LongTest
+    @Test
     public void test104() {
         test("isInstanceIntDynamic", String.class, null);
         test("isInstanceIntDynamic", String.class, "object");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.Mark;
 import com.oracle.graal.api.code.CompilationResult.Site;
@@ -34,7 +36,6 @@
 import com.oracle.graal.replacements.test.CheckCastTest.Depth12;
 import com.oracle.graal.replacements.test.CheckCastTest.Depth13;
 import com.oracle.graal.replacements.test.CheckCastTest.Depth14;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of instanceof, allowing profiling information to be manually specified.
@@ -54,7 +55,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("isString", profile(), "object");
         test("isString", profile(String.class), "object");
@@ -63,7 +64,7 @@
         test("isString", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("isStringInt", profile(), "object");
         test("isStringInt", profile(String.class), "object");
@@ -72,7 +73,7 @@
         test("isStringInt", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test201() {
         test("isStringIntComplex", profile(), "object");
         test("isStringIntComplex", profile(String.class), "object");
@@ -81,7 +82,7 @@
         test("isStringIntComplex", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test3() {
         Throwable throwable = new Exception();
         test("isThrowable", profile(), throwable);
@@ -93,7 +94,7 @@
         test("isThrowable", profile(Exception.class, Error.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test301() {
         onlyFirstIsException(new Exception(), new Error());
         test("onlyFirstIsException", profile(), new Exception(), new Error());
@@ -102,7 +103,7 @@
         test("onlyFirstIsException", profile(), new Error(), new Error());
     }
 
-    @LongTest
+    @Test
     public void test4() {
         Throwable throwable = new Exception();
         test("isThrowableInt", profile(), throwable);
@@ -114,7 +115,7 @@
         test("isThrowableInt", profile(Exception.class, Error.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test5() {
         Map<?, ?> map = new HashMap<>();
         test("isMap", profile(), map);
@@ -127,7 +128,7 @@
         test("isMap", profile(String.class, HashMap.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test6() {
         Map<?, ?> map = new HashMap<>();
         test("isMapInt", profile(), map);
@@ -139,7 +140,7 @@
         test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test7() {
         Object o = new Depth13();
         test("isDepth12", profile(), o);
@@ -153,7 +154,7 @@
         test("isDepth12", profile(String.class, HashMap.class), o);
     }
 
-    @LongTest
+    @Test
     public void test8() {
         Object o = new Depth13();
         test("isDepth12Int", profile(), o);
@@ -259,7 +260,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test9() {
         MyCall callAt63 = new MyCall(63);
         MyMark markAt63 = new MyMark(63);
@@ -276,11 +277,10 @@
         return s1.offset - s2.offset;
     }
 
-    @LongTest
+    @Test
     public void test10() {
-        Mark[] noMarks = {};
         Call callAt63 = new Call(null, 63, 5, true, null);
-        Mark markAt63 = new Mark(63, "1", noMarks);
+        Mark markAt63 = new Mark(63, "1");
         test("compareSites", callAt63, callAt63);
         test("compareSites", callAt63, markAt63);
         test("compareSites", markAt63, callAt63);
@@ -301,7 +301,7 @@
      * The test exists in this source file as the transformation was originally motivated by the
      * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}.
      */
-    @LongTest
+    @Test
     public void testRemoveIntermediateMaterialization() {
         List<String> list = Arrays.asList("1", "2", "3", "4");
         test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no");
@@ -356,7 +356,7 @@
         return o instanceof D[];
     }
 
-    @LongTest
+    @Test
     public void testArray() {
         Object aArray = new A[10];
         test("isArrayOfA", aArray);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.replacements.test;
 
 import static org.junit.Assert.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.test.*;
@@ -33,6 +32,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java	Fri May 30 15:09:09 2014 +0200
@@ -25,7 +25,6 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of {@code [A]NEWARRAY}.
@@ -33,10 +32,10 @@
 public class NewArrayTest extends GraalCompilerTest {
 
     @Override
-    protected void assertEquals(Object expected, Object actual) {
+    protected void assertDeepEquals(Object expected, Object actual) {
         Assert.assertTrue(expected != null);
         Assert.assertTrue(actual != null);
-        super.assertEquals(expected.getClass(), actual.getClass());
+        super.assertDeepEquals(expected.getClass(), actual.getClass());
         if (expected instanceof int[]) {
             Assert.assertArrayEquals((int[]) expected, (int[]) actual);
         } else if (expected instanceof byte[]) {
@@ -58,7 +57,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) {
             test("new" + type + "Array7");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java	Fri May 30 15:09:09 2014 +0200
@@ -27,7 +27,6 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of {@code NEW}.
@@ -35,10 +34,10 @@
 public class NewInstanceTest extends GraalCompilerTest {
 
     @Override
-    protected void assertEquals(Object expected, Object actual) {
+    protected void assertDeepEquals(Object expected, Object actual) {
         Assert.assertTrue(expected != null);
         Assert.assertTrue(actual != null);
-        super.assertEquals(expected.getClass(), actual.getClass());
+        super.assertDeepEquals(expected.getClass(), actual.getClass());
 
         if (expected instanceof Object[]) {
             Assert.assertTrue(actual instanceof Object[]);
@@ -46,23 +45,23 @@
             Object[] aArr = (Object[]) actual;
             Assert.assertTrue(eArr.length == aArr.length);
             for (int i = 0; i < eArr.length; i++) {
-                assertEquals(eArr[i], aArr[i]);
+                assertDeepEquals(eArr[i], aArr[i]);
             }
         } else if (expected.getClass() != Object.class) {
             try {
                 expected.getClass().getDeclaredMethod("equals", Object.class);
-                super.assertEquals(expected, actual);
+                super.assertDeepEquals(expected, actual);
             } catch (Exception e) {
             }
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("newObject");
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("newObjectTwice");
     }
@@ -71,37 +70,37 @@
         return new Object();
     }
 
-    @LongTest
+    @Test
     public void test3() {
         test("newObjectLoop", 100);
     }
 
-    @LongTest
+    @Test
     public void test4() {
         test("newBigObject");
     }
 
-    @LongTest
+    @Test
     public void test5() {
         test("newSomeObject");
     }
 
-    @LongTest
+    @Test
     public void test6() {
         test("newEmptyString");
     }
 
-    @LongTest
+    @Test
     public void test7() {
         test("newString", "value");
     }
 
-    @LongTest
+    @Test
     public void test8() {
         test("newHashMap", 31);
     }
 
-    @LongTest
+    @Test
     public void test9() {
         test("newRegression", true);
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Fri May 30 15:09:09 2014 +0200
@@ -25,12 +25,13 @@
 import java.lang.reflect.*;
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the lowering of the MULTIANEWARRAY instruction.
@@ -86,7 +87,7 @@
     Class<?> bottomClass;
     int[] dimensions;
 
-    @LongTest
+    @Test
     public void test1() {
         for (Class<?> clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) {
             bottomClass = clazz;
@@ -117,7 +118,7 @@
         return new Object[10][9][8];
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("newMultiArrayException");
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Fri May 30 15:09:09 2014 +0200
@@ -127,7 +127,7 @@
         JavaWriteNode write = (JavaWriteNode) graph.start().next();
         Assert.assertEquals(graph.getParameter(2), write.value());
         Assert.assertEquals(graph.getParameter(0), write.object());
-        Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci);
+        Assert.assertEquals(BytecodeFrame.AFTER_BCI, write.stateAfter().bci);
 
         IndexedLocationNode location = (IndexedLocationNode) write.location();
         Assert.assertEquals(kind, location.getValueKind());
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Fri May 30 15:09:09 2014 +0200
@@ -139,7 +139,7 @@
 
         JavaWriteNode write = (JavaWriteNode) cast.next();
         Assert.assertEquals(graph.getParameter(2), write.value());
-        Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci);
+        Assert.assertEquals(BytecodeFrame.AFTER_BCI, write.stateAfter().bci);
 
         Assert.assertEquals(cast, write.object());
         Assert.assertEquals(graph.getParameter(0), cast.getInput());
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,16 +22,10 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
-import static com.oracle.graal.replacements.UnsafeSubstitutions.*;
-
 import java.lang.reflect.*;
-import java.util.concurrent.atomic.*;
 
 import org.junit.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
@@ -44,299 +38,18 @@
  */
 public class StandardMethodSubstitutionsTest extends MethodSubstitutionTest {
 
-    static long off(Object o, String name) {
-        try {
-            return unsafe.objectFieldOffset(o.getClass().getDeclaredField(name));
-        } catch (Exception e) {
-            Assert.fail(e.toString());
-            return 0L;
-        }
-    }
-
-    static class Foo {
-
-        boolean z;
-        byte b;
-        short s;
-        char c;
-        int i;
-        long l;
-        float f;
-        double d;
-        Object o;
-
-        void testGet(Field field, long offset, String getName, Object value) throws Exception {
-            field.set(this, value);
-            Method m1 = Unsafe.class.getDeclaredMethod(getName, Object.class, long.class);
-            Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, Object.class, long.class);
-            Object expected = m1.invoke(unsafe, this, offset);
-            Object actual = m2.invoke(null, unsafe, this, offset);
-            Assert.assertEquals(expected, actual);
-        }
-
-        void testDirect(Field field, long offset, String type, Object value) throws Exception {
-            if (type.equals("Boolean") || type.equals("Object")) {
-                // No direct memory access for these types
-                return;
-            }
-
-            long address = unsafe.allocateMemory(offset + 16);
-
-            String getName = "get" + type;
-            String putName = "put" + type;
-            Method m1 = Unsafe.class.getDeclaredMethod(putName, long.class, field.getType());
-            Method m2 = Unsafe.class.getDeclaredMethod(getName, long.class);
-
-            Method m3 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, long.class, field.getType());
-            Method m4 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, long.class);
-
-            m1.invoke(unsafe, address + offset, value);
-            Object expected = m2.invoke(unsafe, address + offset);
-
-            m3.invoke(null, unsafe, address + offset, value);
-            Object actual = m4.invoke(null, unsafe, address + offset);
-
-            unsafe.freeMemory(address);
-            Assert.assertEquals(expected, actual);
-        }
-
-        void testPut(Field field, long offset, String putName, Object value) throws Exception {
-            Object initialValue = field.get(new Foo());
-            field.set(this, initialValue);
-
-            try {
-                Method m1 = Unsafe.class.getDeclaredMethod(putName, Object.class, long.class, field.getType());
-                Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, Object.class, long.class, field.getType());
-                m1.invoke(unsafe, this, offset, value);
-                Object expected = field.get(this);
-                m2.invoke(null, unsafe, this, offset, value);
-                Object actual = field.get(this);
-                Assert.assertEquals(expected, actual);
-            } catch (NoSuchMethodException e) {
-                if (!putName.startsWith("putOrdered")) {
-                    throw e;
-                }
-            }
-        }
-
-        void test(String fieldName, String typeSuffix, Object value) {
-            try {
-                Field field = Foo.class.getDeclaredField(fieldName);
-                long offset = unsafe.objectFieldOffset(field);
-                testGet(field, offset, "get" + typeSuffix, value);
-                testGet(field, offset, "get" + typeSuffix + "Volatile", value);
-                testPut(field, offset, "put" + typeSuffix, value);
-                testPut(field, offset, "put" + typeSuffix + "Volatile", value);
-                testPut(field, offset, "putOrdered" + typeSuffix, value);
-                testDirect(field, offset, typeSuffix, value);
-            } catch (Exception e) {
-                throw new AssertionError(e);
-            }
-        }
-    }
-
-    @Test
-    public void testUnsafeSubstitutions() throws Exception {
-        test("unsafeCompareAndSwapInt");
-        test("unsafeCompareAndSwapLong");
-        test("unsafeCompareAndSwapObject");
-
-        test("unsafeGetBoolean");
-        test("unsafeGetByte");
-        test("unsafeGetShort");
-        test("unsafeGetChar");
-        test("unsafeGetInt");
-        test("unsafeGetLong");
-        test("unsafeGetFloat");
-        test("unsafeGetDouble");
-        test("unsafeGetObject");
-
-        test("unsafePutBoolean");
-        test("unsafePutByte");
-        test("unsafePutShort");
-        test("unsafePutChar");
-        test("unsafePutInt");
-        test("unsafePutFloat");
-        test("unsafePutDouble");
-        test("unsafePutObject");
-
-        test("unsafeDirectMemoryRead");
-        test("unsafeDirectMemoryWrite");
-
-        AtomicInteger a1 = new AtomicInteger(42);
-        AtomicInteger a2 = new AtomicInteger(42);
-        assertEquals(unsafe.compareAndSwapInt(a1, off(a1, "value"), 42, 53), compareAndSwapInt(unsafe, a2, off(a2, "value"), 42, 53));
-        assertEquals(a1.get(), a2.get());
-
-        AtomicLong l1 = new AtomicLong(42);
-        AtomicLong l2 = new AtomicLong(42);
-        assertEquals(unsafe.compareAndSwapLong(l1, off(l1, "value"), 42, 53), compareAndSwapLong(unsafe, l2, off(l2, "value"), 42, 53));
-        assertEquals(l1.get(), l2.get());
-
-        AtomicReference<String> o1 = new AtomicReference<>("42");
-        AtomicReference<String> o2 = new AtomicReference<>("42");
-        assertEquals(unsafe.compareAndSwapObject(o1, off(o1, "value"), "42", "53"), compareAndSwapObject(unsafe, o2, off(o2, "value"), "42", "53"));
-        assertEquals(o1.get(), o2.get());
-
-        Foo f1 = new Foo();
-        f1.test("z", "Boolean", Boolean.TRUE);
-        f1.test("b", "Byte", Byte.MIN_VALUE);
-        f1.test("s", "Short", Short.MAX_VALUE);
-        f1.test("c", "Char", '!');
-        f1.test("i", "Int", 1010010);
-        f1.test("f", "Float", -34.5F);
-        f1.test("l", "Long", 99999L);
-        f1.test("d", "Double", 1234.5678D);
-        f1.test("o", "Object", "object");
-    }
-
-    @SuppressWarnings("all")
-    public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.compareAndSwapInt(obj, offset, 0, 1);
-    }
-
-    @SuppressWarnings("all")
-    public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.compareAndSwapLong(obj, offset, 0, 1);
-    }
-
-    @SuppressWarnings("all")
-    public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.compareAndSwapObject(obj, offset, null, new Object());
-    }
-
-    @SuppressWarnings("all")
-    public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) {
-        return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) {
-        unsafe.putBoolean(obj, offset, value);
-        unsafe.putBooleanVolatile(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) {
-        unsafe.putByte(obj, offset, value);
-        unsafe.putByteVolatile(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) {
-        unsafe.putShort(obj, offset, value);
-        unsafe.putShortVolatile(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) {
-        unsafe.putChar(obj, offset, value);
-        unsafe.putCharVolatile(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) {
-        unsafe.putInt(obj, offset, value);
-        unsafe.putIntVolatile(obj, offset, value);
-        unsafe.putOrderedInt(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) {
-        unsafe.putLong(obj, offset, value);
-        unsafe.putLongVolatile(obj, offset, value);
-        unsafe.putOrderedLong(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) {
-        unsafe.putFloat(obj, offset, value);
-        unsafe.putFloatVolatile(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) {
-        unsafe.putDouble(obj, offset, value);
-        unsafe.putDoubleVolatile(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) {
-        unsafe.putObject(obj, offset, value);
-        unsafe.putObjectVolatile(obj, offset, value);
-        unsafe.putOrderedObject(obj, offset, value);
-    }
-
-    @SuppressWarnings("all")
-    public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) {
-        // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist
-        return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address);
-    }
-
-    @SuppressWarnings("all")
-    public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) {
-        // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist
-        unsafe.putByte(address, value);
-        unsafe.putShort(address, value);
-        unsafe.putChar(address, (char) value);
-        unsafe.putInt(address, value);
-        unsafe.putLong(address, value);
-        unsafe.putFloat(address, value);
-        unsafe.putDouble(address, value);
-    }
-
     @Test
     public void testMathSubstitutions() {
         assertInGraph(assertNotInGraph(test("mathAbs"), IfNode.class), MathIntrinsicNode.class);     // Java
         test("math");
 
         double value = 34567.891D;
-        assertEquals(Math.sqrt(value), MathSubstitutionsX86.sqrt(value));
-        assertEquals(Math.log(value), MathSubstitutionsX86.log(value));
-        assertEquals(Math.log10(value), MathSubstitutionsX86.log10(value));
-        assertEquals(Math.sin(value), MathSubstitutionsX86.sin(value));
-        assertEquals(Math.cos(value), MathSubstitutionsX86.cos(value));
-        assertEquals(Math.tan(value), MathSubstitutionsX86.tan(value));
+        assertDeepEquals(Math.sqrt(value), MathSubstitutionsX86.sqrt(value));
+        assertDeepEquals(Math.log(value), MathSubstitutionsX86.log(value));
+        assertDeepEquals(Math.log10(value), MathSubstitutionsX86.log10(value));
+        assertDeepEquals(Math.sin(value), MathSubstitutionsX86.sin(value));
+        assertDeepEquals(Math.cos(value), MathSubstitutionsX86.cos(value));
+        assertDeepEquals(Math.tan(value), MathSubstitutionsX86.tan(value));
     }
 
     @SuppressWarnings("all")
@@ -385,9 +98,9 @@
         assert optional || code != null;
         for (Object l : args) {
             // Verify that the original method and the substitution produce the same value
-            assertEquals(invokeSafe(testMethod, l), invokeSafe(realMethod, l));
+            assertDeepEquals(invokeSafe(testMethod, l), invokeSafe(realMethod, l));
             // Verify that the generated code and the original produce the same value
-            assertEquals(executeVarargsSafe(code, l), invokeSafe(realMethod, l));
+            assertDeepEquals(executeVarargsSafe(code, l), invokeSafe(realMethod, l));
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java	Fri May 30 15:09:09 2014 +0200
@@ -73,9 +73,9 @@
             Object arg1 = args1[i];
             Object arg2 = args2[i];
             // Verify that the original method and the substitution produce the same value
-            assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
+            assertDeepEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
             // Verify that the generated code and the original produce the same value
-            assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
+            assertDeepEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, arg1, arg2));
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,451 @@
+/*
+ * 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.replacements.test;
+
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+import static com.oracle.graal.replacements.UnsafeSubstitutions.*;
+
+import java.lang.reflect.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * Tests the VM independent {@link UnsafeSubstitutions}.
+ */
+public class UnsafeSubstitutionsTest extends MethodSubstitutionTest {
+
+    private static Object executeVarargsSafe(InstalledCode code, Object... args) {
+        try {
+            return code.executeVarargs(args);
+        } catch (InvalidInstalledCodeException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static Object invokeSafe(Method method, Object receiver, Object... args) {
+        method.setAccessible(true);
+        try {
+            return method.invoke(receiver, args);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void testSubstitution(String testMethodName, Class<?> holder, String methodName, Class<?>[] parameterTypes, Object receiver, Object[] args1, Object[] args2) {
+        Method originalMethod = getMethod(holder, methodName, parameterTypes);
+        Method testMethod = getMethod(testMethodName);
+
+        // Force compilation
+        InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(testMethod), parse(testMethod));
+        assert code != null;
+
+        // Verify that the original method and the substitution produce the same value
+        {
+            Object expected = invokeSafe(originalMethod, receiver, args1);
+            Object actual = invokeSafe(testMethod, null, args2);
+            assertDeepEquals(expected, actual);
+        }
+
+        // Verify that the generated code and the original produce the same value
+        {
+            Object expected = invokeSafe(originalMethod, receiver, args1);
+            Object actual = executeVarargsSafe(code, args2);
+            assertDeepEquals(expected, actual);
+        }
+    }
+
+    static long off(Object o, String name) {
+        try {
+            return unsafe.objectFieldOffset(o.getClass().getDeclaredField(name));
+        } catch (Exception e) {
+            Assert.fail(e.toString());
+            return 0L;
+        }
+    }
+
+    static class Foo {
+
+        boolean z;
+        byte b;
+        short s;
+        char c;
+        int i;
+        long l;
+        float f;
+        double d;
+        Object o;
+
+        void testGet(Field field, long offset, String getName, Object value) throws Exception {
+            field.set(this, value);
+            Method m1 = Unsafe.class.getDeclaredMethod(getName, Object.class, long.class);
+            Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, Object.class, long.class);
+            Object expected = m1.invoke(unsafe, this, offset);
+            Object actual = m2.invoke(null, unsafe, this, offset);
+            Assert.assertEquals(expected, actual);
+        }
+
+        void testDirect(Field field, long offset, String type, Object value) throws Exception {
+            if (type.equals("Boolean") || type.equals("Object")) {
+                // No direct memory access for these types
+                return;
+            }
+
+            long address = unsafe.allocateMemory(offset + 16);
+
+            String getName = "get" + type;
+            String putName = "put" + type;
+            Method m1 = Unsafe.class.getDeclaredMethod(putName, long.class, field.getType());
+            Method m2 = Unsafe.class.getDeclaredMethod(getName, long.class);
+
+            Method m3 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, long.class, field.getType());
+            Method m4 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, long.class);
+
+            m1.invoke(unsafe, address + offset, value);
+            Object expected = m2.invoke(unsafe, address + offset);
+
+            m3.invoke(null, unsafe, address + offset, value);
+            Object actual = m4.invoke(null, unsafe, address + offset);
+
+            unsafe.freeMemory(address);
+            Assert.assertEquals(expected, actual);
+        }
+
+        void testPut(Field field, long offset, String putName, Object value) throws Exception {
+            Object initialValue = field.get(new Foo());
+            field.set(this, initialValue);
+
+            try {
+                Method m1 = Unsafe.class.getDeclaredMethod(putName, Object.class, long.class, field.getType());
+                Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, Object.class, long.class, field.getType());
+                m1.invoke(unsafe, this, offset, value);
+                Object expected = field.get(this);
+                m2.invoke(null, unsafe, this, offset, value);
+                Object actual = field.get(this);
+                Assert.assertEquals(expected, actual);
+            } catch (NoSuchMethodException e) {
+                if (!putName.startsWith("putOrdered")) {
+                    throw e;
+                }
+            }
+        }
+
+        void test(String fieldName, String typeSuffix, Object value) {
+            try {
+                Field field = Foo.class.getDeclaredField(fieldName);
+                long offset = unsafe.objectFieldOffset(field);
+                testGet(field, offset, "get" + typeSuffix, value);
+                testGet(field, offset, "get" + typeSuffix + "Volatile", value);
+                testPut(field, offset, "put" + typeSuffix, value);
+                testPut(field, offset, "put" + typeSuffix + "Volatile", value);
+                testPut(field, offset, "putOrdered" + typeSuffix, value);
+                testDirect(field, offset, typeSuffix, value);
+            } catch (Exception e) {
+                throw new AssertionError(e);
+            }
+        }
+    }
+
+    @Test
+    public void testUnsafeSubstitutions() throws Exception {
+        test("unsafeCompareAndSwapInt");
+        test("unsafeCompareAndSwapLong");
+        test("unsafeCompareAndSwapObject");
+
+        test("unsafeGetBoolean");
+        test("unsafeGetByte");
+        test("unsafeGetShort");
+        test("unsafeGetChar");
+        test("unsafeGetInt");
+        test("unsafeGetLong");
+        test("unsafeGetFloat");
+        test("unsafeGetDouble");
+        test("unsafeGetObject");
+
+        test("unsafePutBoolean");
+        test("unsafePutByte");
+        test("unsafePutShort");
+        test("unsafePutChar");
+        test("unsafePutInt");
+        test("unsafePutFloat");
+        test("unsafePutDouble");
+        test("unsafePutObject");
+
+        test("unsafeDirectMemoryRead");
+        test("unsafeDirectMemoryWrite");
+
+        AtomicInteger a1 = new AtomicInteger(42);
+        AtomicInteger a2 = new AtomicInteger(42);
+        assertDeepEquals(unsafe.compareAndSwapInt(a1, off(a1, "value"), 42, 53), compareAndSwapInt(unsafe, a2, off(a2, "value"), 42, 53));
+        assertDeepEquals(a1.get(), a2.get());
+
+        AtomicLong l1 = new AtomicLong(42);
+        AtomicLong l2 = new AtomicLong(42);
+        assertDeepEquals(unsafe.compareAndSwapLong(l1, off(l1, "value"), 42, 53), compareAndSwapLong(unsafe, l2, off(l2, "value"), 42, 53));
+        assertDeepEquals(l1.get(), l2.get());
+
+        AtomicReference<String> o1 = new AtomicReference<>("42");
+        AtomicReference<String> o2 = new AtomicReference<>("42");
+        assertDeepEquals(unsafe.compareAndSwapObject(o1, off(o1, "value"), "42", "53"), compareAndSwapObject(unsafe, o2, off(o2, "value"), "42", "53"));
+        assertDeepEquals(o1.get(), o2.get());
+
+        Foo f1 = new Foo();
+        f1.test("z", "Boolean", Boolean.TRUE);
+        f1.test("b", "Byte", Byte.MIN_VALUE);
+        f1.test("s", "Short", Short.MAX_VALUE);
+        f1.test("c", "Char", '!');
+        f1.test("i", "Int", 1010010);
+        f1.test("f", "Float", -34.5F);
+        f1.test("l", "Long", 99999L);
+        f1.test("d", "Double", 1234.5678D);
+        f1.test("o", "Object", "object");
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.compareAndSwapInt(obj, offset, 0, 1);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.compareAndSwapLong(obj, offset, 0, 1);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.compareAndSwapObject(obj, offset, null, new Object());
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) {
+        return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) {
+        unsafe.putBoolean(obj, offset, value);
+        unsafe.putBooleanVolatile(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) {
+        unsafe.putByte(obj, offset, value);
+        unsafe.putByteVolatile(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) {
+        unsafe.putShort(obj, offset, value);
+        unsafe.putShortVolatile(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) {
+        unsafe.putChar(obj, offset, value);
+        unsafe.putCharVolatile(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) {
+        unsafe.putInt(obj, offset, value);
+        unsafe.putIntVolatile(obj, offset, value);
+        unsafe.putOrderedInt(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) {
+        unsafe.putLong(obj, offset, value);
+        unsafe.putLongVolatile(obj, offset, value);
+        unsafe.putOrderedLong(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) {
+        unsafe.putFloat(obj, offset, value);
+        unsafe.putFloatVolatile(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) {
+        unsafe.putDouble(obj, offset, value);
+        unsafe.putDoubleVolatile(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) {
+        unsafe.putObject(obj, offset, value);
+        unsafe.putObjectVolatile(obj, offset, value);
+        unsafe.putOrderedObject(obj, offset, value);
+    }
+
+    @SuppressWarnings("all")
+    public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) {
+        // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist
+        return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address);
+    }
+
+    @SuppressWarnings("all")
+    public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) {
+        // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist
+        unsafe.putByte(address, value);
+        unsafe.putShort(address, value);
+        unsafe.putChar(address, (char) value);
+        unsafe.putInt(address, value);
+        unsafe.putLong(address, value);
+        unsafe.putFloat(address, value);
+        unsafe.putDouble(address, value);
+    }
+
+    @Test
+    public void testGetAndAddInt() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "i");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, int.class};
+        for (int delta = Integer.MAX_VALUE - 10; delta < Integer.MAX_VALUE; delta++) {
+            Object[] args1 = new Object[]{f1, offset, delta};
+            Object[] args2 = new Object[]{f2, offset, delta};
+            testSubstitution("getAndAddInt", Unsafe.class, "getAndAddInt", parameterTypes, unsafe, args1, args2);
+        }
+    }
+
+    public static int getAndAddInt(Object obj, long offset, int delta) {
+        return unsafe.getAndAddInt(obj, offset, delta);
+    }
+
+    @Test
+    public void testGetAndAddLong() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "l");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, long.class};
+        for (long delta = Long.MAX_VALUE - 10; delta < Long.MAX_VALUE; delta++) {
+            Object[] args1 = new Object[]{f1, offset, delta};
+            Object[] args2 = new Object[]{f2, offset, delta};
+            testSubstitution("getAndAddLong", Unsafe.class, "getAndAddLong", parameterTypes, unsafe, args1, args2);
+        }
+    }
+
+    public static long getAndAddLong(Object obj, long offset, long delta) {
+        return unsafe.getAndAddLong(obj, offset, delta);
+    }
+
+    @Test
+    public void testGetAndSetInt() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "i");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, int.class};
+        for (int delta = Integer.MAX_VALUE - 10; delta < Integer.MAX_VALUE; delta++) {
+            Object[] args1 = new Object[]{f1, offset, delta};
+            Object[] args2 = new Object[]{f2, offset, delta};
+            testSubstitution("getAndSetInt", Unsafe.class, "getAndSetInt", parameterTypes, unsafe, args1, args2);
+        }
+    }
+
+    public static int getAndSetInt(Object obj, long offset, int newValue) {
+        return unsafe.getAndSetInt(obj, offset, newValue);
+    }
+
+    @Test
+    public void testGetAndSetLong() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "l");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, long.class};
+        for (long newValue = Long.MAX_VALUE - 10; newValue < Long.MAX_VALUE; newValue++) {
+            Object[] args1 = new Object[]{f1, offset, newValue};
+            Object[] args2 = new Object[]{f2, offset, newValue};
+            testSubstitution("getAndSetLong", Unsafe.class, "getAndSetLong", parameterTypes, unsafe, args1, args2);
+        }
+    }
+
+    public static long getAndSetLong(Object obj, long offset, long newValue) {
+        return unsafe.getAndSetLong(obj, offset, newValue);
+    }
+
+    @Test
+    public void testGetAndSetObject() throws Exception {
+        Foo f1 = new Foo();
+        Foo f2 = new Foo();
+        long offset = off(f1, "o");
+        Class<?>[] parameterTypes = new Class<?>[]{Object.class, long.class, Object.class};
+        for (long i = 0; i < 10; i++) {
+            Object o = new Object();
+            Object[] args1 = new Object[]{f1, offset, o};
+            Object[] args2 = new Object[]{f2, offset, o};
+            testSubstitution("getAndSetObject", Unsafe.class, "getAndSetObject", parameterTypes, unsafe, args1, args2);
+            System.gc();
+        }
+    }
+
+    public static Object getAndSetObject(Object obj, long offset, Object newValue) {
+        return unsafe.getAndSetObject(obj, offset, newValue);
+    }
+
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,8 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
@@ -31,7 +33,6 @@
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
-import com.oracle.graal.test.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -53,7 +54,7 @@
         return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
-    @LongTest
+    @Test
     public void construction() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
                         Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -65,7 +66,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void testArithmetic() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
                         Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -102,7 +103,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void testCompare() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE};
         for (long word1 : words) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Fri May 30 15:09:09 2014 +0200
@@ -22,22 +22,21 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.Snippet.Fold;
@@ -57,7 +56,7 @@
 
         @Override
         public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) {
-            if (Modifier.isNative(method.getModifiers())) {
+            if (method.isNative()) {
                 return false;
             }
             if (method.getAnnotation(Fold.class) != null) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 
 public class BoxingSubstitutions {
 
@@ -140,8 +141,14 @@
         }
     }
 
-    public static Class<?>[] getClasses() {
-        return new Class<?>[]{BooleanSubstitutions.class, ByteSubstitutions.class, CharacterSubstitutions.class, DoubleSubstitutions.class, FloatSubstitutions.class, IntegerSubstitutions.class,
-                        LongSubstitutions.class, ShortSubstitutions.class};
+    public static void registerReplacements(Replacements replacements) {
+        replacements.registerSubstitutions(Boolean.class, BooleanSubstitutions.class);
+        replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class);
+        replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class);
+        replacements.registerSubstitutions(Byte.class, ByteSubstitutions.class);
+        replacements.registerSubstitutions(Float.class, FloatSubstitutions.class);
+        replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class);
+        replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
+        replacements.registerSubstitutions(Long.class, LongSubstitutions.class);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
@@ -33,13 +34,13 @@
 import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 
 /**
- * This phase ensures that there's a single {@linkplain FrameState#AFTER_BCI collapsed frame state}
- * per path.
- * 
+ * This phase ensures that there's a single {@linkplain BytecodeFrame#AFTER_BCI collapsed frame
+ * state} per path.
+ *
  * Removes other frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes
- * in the graph, and replaces them with {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid frame
- * states}.
- * 
+ * in the graph, and replaces them with {@linkplain BytecodeFrame#INVALID_FRAMESTATE_BCI invalid
+ * frame states}.
+ *
  * The invalid frame states ensure that no deoptimization to a snippet frame state will happen.
  */
 public class CollapseFrameForSingleSideEffectPhase extends Phase {
@@ -111,7 +112,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         CollapseFrameForSingleSideEffectClosure closure = new CollapseFrameForSingleSideEffectClosure();
-        ReentrantNodeIterator.apply(closure, graph.start(), new IterationState(), null);
+        ReentrantNodeIterator.apply(closure, graph.start(), new IterationState());
         closure.finishProcessing(graph);
     }
 
@@ -176,7 +177,7 @@
                 if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) {
                     StateSplit split = (StateSplit) returnSideEffect;
                     if (split.stateAfter() != null) {
-                        split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI)));
+                        split.setStateAfter(graph.add(new FrameState(BytecodeFrame.AFTER_BCI)));
                     }
                 }
             }
@@ -185,7 +186,7 @@
                 if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) {
                     StateSplit split = (StateSplit) unwindSideEffect;
                     if (split.stateAfter() != null) {
-                        split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_EXCEPTION_BCI)));
+                        split.setStateAfter(graph.add(new FrameState(BytecodeFrame.AFTER_EXCEPTION_BCI)));
                     }
                 }
             }
@@ -214,7 +215,7 @@
         }
 
         private static FrameState createInvalidFrameState(FixedNode node) {
-            return node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI));
+            return node.graph().add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,691 @@
+/*
+ * 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.replacements;
+
+import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.util.*;
+
+/**
+ * VM-independent lowerings for standard Java nodes. VM-specific methods are abstract and must be
+ * implemented by VM-specific subclasses.
+ */
+public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
+
+    protected final MetaAccessProvider metaAccess;
+    protected final TargetDescription target;
+
+    private BoxingSnippets.Templates boxingSnippets;
+
+    public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, TargetDescription target) {
+        this.metaAccess = metaAccess;
+        this.target = target;
+    }
+
+    public void initialize(Providers providers, SnippetReflectionProvider snippetReflection) {
+        boxingSnippets = new BoxingSnippets.Templates(providers, snippetReflection, target);
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        if (n instanceof LoadFieldNode) {
+            lowerLoadFieldNode((LoadFieldNode) n, tool);
+        } else if (n instanceof StoreFieldNode) {
+            lowerStoreFieldNode((StoreFieldNode) n, tool);
+        } else if (n instanceof LoadIndexedNode) {
+            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
+        } else if (n instanceof StoreIndexedNode) {
+            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
+        } else if (n instanceof ArrayLengthNode) {
+            lowerArrayLengthNode((ArrayLengthNode) n, tool);
+        } else if (n instanceof LoadHubNode) {
+            lowerLoadHubNode((LoadHubNode) n);
+        } else if (n instanceof CompareAndSwapNode) {
+            lowerCompareAndSwapNode((CompareAndSwapNode) n);
+        } else if (n instanceof AtomicReadAndWriteNode) {
+            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
+        } else if (n instanceof UnsafeLoadNode) {
+            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
+        } else if (n instanceof UnsafeStoreNode) {
+            lowerUnsafeStoreNode((UnsafeStoreNode) n);
+        } else if (n instanceof JavaReadNode) {
+            lowerJavaReadNode((JavaReadNode) n);
+        } else if (n instanceof JavaWriteNode) {
+            lowerJavaWriteNode((JavaWriteNode) n);
+        } else if (n instanceof CommitAllocationNode) {
+            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
+        } else if (n instanceof BoxNode) {
+            boxingSnippets.lower((BoxNode) n, tool);
+        } else if (n instanceof UnboxNode) {
+            boxingSnippets.lower((UnboxNode) n, tool);
+        } else {
+            throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
+        }
+    }
+
+    protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
+        assert loadField.getKind() != Kind.Illegal;
+        StructuredGraph graph = loadField.graph();
+        ResolvedJavaField field = loadField.field();
+        ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
+        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind(), true);
+        ConstantLocationNode location = createFieldLocation(graph, field, false);
+        assert location != null : "Field that is loaded must not be eliminated";
+
+        ReadNode memoryRead = graph.add(new ReadNode(object, location, loadStamp, fieldLoadBarrierType(field)));
+        ValueNode readValue = implicitLoadConvert(graph, field.getKind(), memoryRead);
+        loadField.replaceAtUsages(readValue);
+        graph.replaceFixed(loadField, memoryRead);
+
+        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
+
+        if (loadField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+            graph.addBeforeFixed(memoryRead, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
+            graph.addAfterFixed(memoryRead, postMembar);
+        }
+    }
+
+    protected void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
+        StructuredGraph graph = storeField.graph();
+        ResolvedJavaField field = storeField.field();
+        ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
+        ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
+        ConstantLocationNode location = createFieldLocation(graph, field, false);
+
+        if (location == null) {
+            /* Field has been eliminated, so no write necessary. */
+            assert !storeField.isVolatile() : "missing memory barriers";
+            graph.removeFixed(storeField);
+            return;
+        }
+        WriteNode memoryWrite = graph.add(new WriteNode(object, value, location, fieldStoreBarrierType(storeField.field())));
+        memoryWrite.setStateAfter(storeField.stateAfter());
+        graph.replaceFixedWithFixed(storeField, memoryWrite);
+        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
+
+        if (storeField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            graph.addBeforeFixed(memoryWrite, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+            graph.addAfterFixed(memoryWrite, postMembar);
+        }
+    }
+
+    protected void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
+        StructuredGraph graph = loadIndexed.graph();
+        Kind elementKind = loadIndexed.elementKind();
+        LocationNode location = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
+        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind, true);
+
+        ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), location, loadStamp, BarrierType.NONE));
+        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
+
+        memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
+
+        loadIndexed.replaceAtUsages(readValue);
+        graph.replaceFixed(loadIndexed, memoryRead);
+    }
+
+    protected void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
+        StructuredGraph graph = storeIndexed.graph();
+        GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+        Kind elementKind = storeIndexed.elementKind();
+        LocationNode location = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
+
+        ValueNode value = storeIndexed.value();
+        ValueNode array = storeIndexed.array();
+        FixedWithNextNode checkCastNode = null;
+        if (elementKind == Kind.Object && !StampTool.isObjectAlwaysNull(value)) {
+            /* Array store check. */
+            ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+            if (arrayType != null && StampTool.isExactType(array)) {
+                ResolvedJavaType elementType = arrayType.getComponentType();
+                if (!MetaUtil.isJavaLangObject(elementType)) {
+                    checkCastNode = graph.add(new CheckCastNode(elementType, value, null, true));
+                    graph.addBeforeFixed(storeIndexed, checkCastNode);
+                    value = checkCastNode;
+                }
+            } else {
+                ValueNode arrayClass = createReadHub(graph, array, boundsCheck);
+                ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed);
+                checkCastNode = graph.add(new CheckCastDynamicNode(componentHub, value, true));
+                graph.addBeforeFixed(storeIndexed, checkCastNode);
+                value = checkCastNode;
+            }
+        }
+
+        WriteNode memoryWrite = graph.add(new WriteNode(array, implicitStoreConvert(graph, elementKind, value), location, arrayStoreBarrierType(storeIndexed.elementKind())));
+        memoryWrite.setGuard(boundsCheck);
+        memoryWrite.setStateAfter(storeIndexed.stateAfter());
+        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
+
+        if (checkCastNode instanceof Lowerable) {
+            /* Recursive lowering of the store check node. */
+            ((Lowerable) checkCastNode).lower(tool);
+        }
+    }
+
+    protected void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
+        StructuredGraph graph = arrayLengthNode.graph();
+        ValueNode array = arrayLengthNode.array();
+        ConstantLocationNode location = ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, arrayLengthOffset(), graph);
+
+        ReadNode arrayLengthRead = graph.add(new ReadNode(array, location, StampFactory.positiveInt(), BarrierType.NONE));
+        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
+        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
+    }
+
+    protected void lowerLoadHubNode(LoadHubNode loadHub) {
+        StructuredGraph graph = loadHub.graph();
+        if (graph.getGuardsStage().ordinal() < StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
+            return;
+        }
+        ValueNode hub = createReadHub(graph, loadHub.object(), loadHub.getGuard());
+        graph.replaceFloating(loadHub, hub);
+    }
+
+    protected void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
+        StructuredGraph graph = cas.graph();
+        Kind valueKind = cas.getValueKind();
+        LocationNode location = createLocation(cas.offset(), cas.getLocationIdentity(), valueKind);
+
+        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected());
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue());
+
+        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, expectedValue, newValue, compareAndSwapBarrierType(cas)));
+        atomicNode.setStateAfter(cas.stateAfter());
+        graph.replaceFixedWithFixed(cas, atomicNode);
+    }
+
+    protected void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
+        StructuredGraph graph = n.graph();
+        Kind valueKind = n.getValueKind();
+        LocationNode location = IndexedLocationNode.create(n.getLocationIdentity(), valueKind, 0, n.offset(), graph, 1);
+
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
+
+        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(n.object(), location, newValue, atomicReadAndWriteBarrierType(n)));
+        memoryRead.setStateAfter(n.stateAfter());
+
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
+        n.replaceAtUsages(readValue);
+        graph.replaceFixedWithFixed(n, memoryRead);
+    }
+
+    protected void lowerUnsafeLoadNode(UnsafeLoadNode load, @SuppressWarnings("unused") LoweringTool tool) {
+        StructuredGraph graph = load.graph();
+        if (load.getGuardingCondition() != null) {
+            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
+            ReadNode memoryRead = createUnsafeRead(graph, load, valueAnchorNode);
+            graph.replaceFixedWithFixed(load, valueAnchorNode);
+            graph.addAfterFixed(valueAnchorNode, memoryRead);
+        } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
+            assert load.getKind() != Kind.Illegal;
+            ReadNode memoryRead = createUnsafeRead(graph, load, null);
+            // An unsafe read must not float outside its block otherwise
+            // it may float above an explicit null check on its object.
+            memoryRead.setGuard(BeginNode.prevBegin(load));
+            graph.replaceFixedWithFixed(load, memoryRead);
+        }
+    }
+
+    protected ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
+        boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+        Kind readKind = load.accessKind();
+        LocationNode location = createLocation(load);
+        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
+        ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, loadStamp, guard, BarrierType.NONE));
+        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
+        load.replaceAtUsages(readValue);
+        return memoryRead;
+    }
+
+    protected void lowerUnsafeStoreNode(UnsafeStoreNode store) {
+        StructuredGraph graph = store.graph();
+        LocationNode location = createLocation(store);
+        ValueNode object = store.object();
+        boolean compressible = store.value().getKind() == Kind.Object;
+        Kind valueKind = store.accessKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
+        WriteNode write = graph.add(new WriteNode(object, value, location, unsafeStoreBarrierType(store)));
+        write.setStateAfter(store.stateAfter());
+        graph.replaceFixedWithFixed(store, write);
+    }
+
+    protected void lowerJavaReadNode(JavaReadNode read) {
+        StructuredGraph graph = read.graph();
+        Kind valueKind = read.location().getValueKind();
+        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
+
+        ReadNode memoryRead = graph.add(new ReadNode(read.object(), read.location(), loadStamp, read.getBarrierType()));
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
+        memoryRead.setGuard(read.getGuard());
+        read.replaceAtUsages(readValue);
+        graph.replaceFixed(read, memoryRead);
+    }
+
+    protected void lowerJavaWriteNode(JavaWriteNode write) {
+        StructuredGraph graph = write.graph();
+        Kind valueKind = write.location().getValueKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
+
+        WriteNode memoryWrite = graph.add(new WriteNode(write.object(), value, write.location(), write.getBarrierType(), write.isInitialization()));
+        memoryWrite.setStateAfter(write.stateAfter());
+        graph.replaceFixedWithFixed(write, memoryWrite);
+        memoryWrite.setGuard(write.getGuard());
+    }
+
+    protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
+        StructuredGraph graph = commit.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            List<AbstractNewObjectNode> recursiveLowerings = new ArrayList<>();
+
+            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+            BitSet omittedValues = new BitSet();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                AbstractNewObjectNode newObject;
+                if (virtual instanceof VirtualInstanceNode) {
+                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
+                } else {
+                    newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
+                }
+                recursiveLowerings.add(newObject);
+                graph.addBeforeFixed(commit, newObject);
+                allocations[objIndex] = newObject;
+                for (int i = 0; i < entryCount; i++) {
+                    ValueNode value = commit.getValues().get(valuePos);
+                    if (value instanceof VirtualObjectNode) {
+                        value = allocations[commit.getVirtualObjects().indexOf(value)];
+                    }
+                    if (value == null) {
+                        omittedValues.set(valuePos);
+                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                        // Constant.illegal is always the defaultForKind, so it is skipped
+                        Kind valueKind = value.getKind();
+                        Kind entryKind = virtual.entryKind(i);
+
+                        // Truffle requires some leniency in terms of what can be put where:
+                        Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
+                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
+                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
+                        ConstantLocationNode location = null;
+                        BarrierType barrierType = null;
+                        if (virtual instanceof VirtualInstanceNode) {
+                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
+                            long offset = fieldOffset(field);
+                            if (offset >= 0) {
+                                location = ConstantLocationNode.create(initLocationIdentity(), accessKind, offset, graph);
+                                barrierType = fieldInitializationBarrier(entryKind);
+                            }
+                        } else {
+                            location = ConstantLocationNode.create(initLocationIdentity(), accessKind, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind), graph);
+                            barrierType = arrayInitializationBarrier(entryKind);
+                        }
+                        if (location != null) {
+                            WriteNode write = new WriteNode(newObject, implicitStoreConvert(graph, entryKind, value), location, barrierType);
+                            graph.addAfterFixed(newObject, graph.add(write));
+                        }
+                    }
+                    valuePos++;
+
+                }
+            }
+            valuePos = 0;
+
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                ValueNode newObject = allocations[objIndex];
+                for (int i = 0; i < entryCount; i++) {
+                    if (omittedValues.get(valuePos)) {
+                        ValueNode value = commit.getValues().get(valuePos);
+                        assert value instanceof VirtualObjectNode;
+                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
+                            LocationNode location;
+                            BarrierType barrierType;
+                            if (virtual instanceof VirtualInstanceNode) {
+                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+                                location = createFieldLocation(graph, virtualInstance.field(i), true);
+                                barrierType = BarrierType.IMPRECISE;
+                            } else {
+                                location = createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph), true);
+                                barrierType = BarrierType.PRECISE;
+                            }
+                            if (location != null) {
+                                WriteNode write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), location, barrierType);
+                                graph.addBeforeFixed(commit, graph.add(write));
+                            }
+                        }
+                    }
+                    valuePos++;
+                }
+            }
+
+            finishAllocatedObjects(tool, commit, allocations);
+            graph.removeFixed(commit);
+
+            for (AbstractNewObjectNode recursiveLowering : recursiveLowerings) {
+                recursiveLowering.lower(tool);
+            }
+        }
+    }
+
+    public static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
+        StructuredGraph graph = commit.graph();
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+            allocations[objIndex] = anchor;
+            graph.addBeforeFixed(commit, anchor);
+        }
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
+                graph.addBeforeFixed(commit, enter);
+                enter.lower(tool);
+            }
+        }
+        for (Node usage : commit.usages().snapshot()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+            graph.replaceFloating(addObject, allocations[index]);
+        }
+    }
+
+    protected BarrierType fieldLoadBarrierType(@SuppressWarnings("unused") ResolvedJavaField field) {
+        return BarrierType.NONE;
+    }
+
+    protected BarrierType fieldStoreBarrierType(ResolvedJavaField field) {
+        if (field.getKind() == Kind.Object) {
+            return BarrierType.IMPRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    protected BarrierType arrayStoreBarrierType(Kind elementKind) {
+        if (elementKind == Kind.Object) {
+            return BarrierType.PRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    protected BarrierType fieldInitializationBarrier(Kind entryKind) {
+        return entryKind == Kind.Object ? BarrierType.IMPRECISE : BarrierType.NONE;
+    }
+
+    protected BarrierType arrayInitializationBarrier(Kind entryKind) {
+        return entryKind == Kind.Object ? BarrierType.PRECISE : BarrierType.NONE;
+    }
+
+    protected BarrierType unsafeStoreBarrierType(UnsafeStoreNode store) {
+        return storeBarrierType(store.object(), store.value());
+    }
+
+    protected BarrierType compareAndSwapBarrierType(CompareAndSwapNode cas) {
+        return storeBarrierType(cas.object(), cas.expected());
+    }
+
+    protected BarrierType atomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
+        return storeBarrierType(n.object(), n.newValue());
+    }
+
+    protected BarrierType storeBarrierType(ValueNode object, ValueNode value) {
+        if (value.getKind() == Kind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(object);
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    protected abstract int fieldOffset(ResolvedJavaField field);
+
+    protected abstract ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField field);
+
+    protected abstract int arrayLengthOffset();
+
+    protected abstract int arrayBaseOffset(Kind elementKind);
+
+    public int arrayScalingFactor(Kind elementKind) {
+        return target.getSizeInBytes(elementKind);
+    }
+
+    protected abstract LocationIdentity initLocationIdentity();
+
+    protected Stamp loadStamp(Stamp stamp, Kind kind, @SuppressWarnings("unused") boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return StampTool.narrowingConversion(stamp, 8);
+            case Char:
+            case Short:
+                return StampTool.narrowingConversion(stamp, 16);
+        }
+        return stamp;
+    }
+
+    public ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value) {
+        return implicitLoadConvert(graph, kind, value, true);
+
+    }
+
+    protected ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
+        switch (kind) {
+            case Byte:
+            case Short:
+                return graph.unique(new SignExtendNode(value, 32));
+            case Boolean:
+            case Char:
+                return graph.unique(new ZeroExtendNode(value, 32));
+        }
+        return value;
+    }
+
+    public ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value) {
+        return implicitStoreConvert(graph, kind, value, true);
+    }
+
+    protected ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return graph.unique(new NarrowNode(value, 8));
+            case Char:
+            case Short:
+                return graph.unique(new NarrowNode(value, 16));
+        }
+        return value;
+    }
+
+    protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard);
+
+    protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
+
+    protected ConstantLocationNode createFieldLocation(StructuredGraph graph, ResolvedJavaField field, boolean initialization) {
+        int offset = fieldOffset(field);
+        if (offset >= 0) {
+            LocationIdentity loc = initialization ? initLocationIdentity() : field;
+            return ConstantLocationNode.create(loc, field.getKind(), offset, graph);
+        } else {
+            return null;
+        }
+    }
+
+    protected LocationNode createLocation(UnsafeAccessNode access) {
+        return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind());
+    }
+
+    protected LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind) {
+        ValueNode offset = offsetNode;
+        if (offset.isConstant()) {
+            long offsetValue = offset.asConstant().asLong();
+            return ConstantLocationNode.create(locationIdentity, accessKind, offsetValue, offset.graph());
+        }
+
+        long displacement = 0;
+        int indexScaling = 1;
+        boolean signExtend = false;
+        if (offset instanceof SignExtendNode) {
+            SignExtendNode extend = (SignExtendNode) offset;
+            if (extend.getResultBits() == 64) {
+                signExtend = true;
+                offset = extend.getInput();
+            }
+        }
+        if (offset instanceof IntegerAddNode) {
+            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
+            if (integerAddNode.y() instanceof ConstantNode) {
+                displacement = integerAddNode.y().asConstant().asLong();
+                offset = integerAddNode.x();
+            }
+        }
+
+        if (offset instanceof LeftShiftNode) {
+            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
+            if (leftShiftNode.y() instanceof ConstantNode) {
+                long shift = leftShiftNode.y().asConstant().asLong();
+                if (shift >= 1 && shift <= 3) {
+                    if (shift == 1) {
+                        indexScaling = 2;
+                    } else if (shift == 2) {
+                        indexScaling = 4;
+                    } else {
+                        indexScaling = 8;
+                    }
+                    offset = leftShiftNode.x();
+                }
+            }
+        }
+        if (signExtend) {
+            // If we were using sign extended values before restore the sign extension.
+            offset = offset.graph().addOrUnique(new SignExtendNode(offset, 64));
+        }
+        return IndexedLocationNode.create(locationIdentity, accessKind, displacement, offset, offset.graph(), indexScaling);
+    }
+
+    public IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
+        LocationIdentity loc = initialization ? initLocationIdentity() : NamedLocationIdentity.getArrayLocation(elementKind);
+        return IndexedLocationNode.create(loc, elementKind, arrayBaseOffset(elementKind), index, graph, arrayScalingFactor(elementKind));
+    }
+
+    protected GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
+        StructuredGraph graph = n.graph();
+        ValueNode array = n.array();
+        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
+        if (arrayLength == null) {
+            Stamp stamp = StampFactory.positiveInt();
+            ReadNode readArrayLength = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, arrayLengthOffset(), graph), stamp, BarrierType.NONE));
+            graph.addBeforeFixed(n, readArrayLength);
+            readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
+            arrayLength = readArrayLength;
+        }
+
+        if (arrayLength.isConstant() && n.index().isConstant()) {
+            int l = arrayLength.asConstant().asInt();
+            int i = n.index().asConstant().asInt();
+            if (i >= 0 && i < l) {
+                // unneeded range check
+                return null;
+            }
+        }
+
+        return tool.createGuard(n, graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+    }
+
+    protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
+        if (StampTool.isObjectNonNull(object)) {
+            return null;
+        }
+        return tool.createGuard(before, before.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+    }
+
+    @Override
+    public ValueNode reconstructArrayIndex(LocationNode location) {
+        Kind elementKind = location.getValueKind();
+        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
+
+        long base;
+        ValueNode index;
+        int scale = arrayScalingFactor(elementKind);
+
+        if (location instanceof ConstantLocationNode) {
+            base = ((ConstantLocationNode) location).getDisplacement();
+            index = null;
+        } else if (location instanceof IndexedLocationNode) {
+            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
+            assert indexedLocation.getIndexScaling() == scale;
+            base = indexedLocation.getDisplacement();
+            index = indexedLocation.getIndex();
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        base -= arrayBaseOffset(elementKind);
+        assert base >= 0 && base % scale == 0;
+
+        base /= scale;
+        assert NumUtil.isInt(base);
+
+        StructuredGraph graph = location.graph();
+        if (index == null) {
+            return ConstantNode.forInt((int) base, graph);
+        } else {
+            if (base == 0) {
+                return index;
+            } else {
+                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.lang.reflect.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -35,21 +38,18 @@
 @ServiceProvider(ReplacementsProvider.class)
 public class GraalMethodSubstitutions implements ReplacementsProvider {
 
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
-        for (Class<?> clazz : BoxingSubstitutions.getClasses()) {
-            replacements.registerSubstitutions(clazz);
-        }
-
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
+        BoxingSubstitutions.registerReplacements(replacements);
         if (Intrinsify.getValue()) {
-            replacements.registerSubstitutions(ArraySubstitutions.class);
-            replacements.registerSubstitutions(MathSubstitutionsX86.class);
-            replacements.registerSubstitutions(DoubleSubstitutions.class);
-            replacements.registerSubstitutions(FloatSubstitutions.class);
-            replacements.registerSubstitutions(LongSubstitutions.class);
-            replacements.registerSubstitutions(IntegerSubstitutions.class);
-            replacements.registerSubstitutions(CharacterSubstitutions.class);
-            replacements.registerSubstitutions(ShortSubstitutions.class);
-            replacements.registerSubstitutions(UnsignedMathSubstitutions.class);
+            replacements.registerSubstitutions(Array.class, ArraySubstitutions.class);
+            replacements.registerSubstitutions(Math.class, MathSubstitutionsX86.class);
+            replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class);
+            replacements.registerSubstitutions(Float.class, FloatSubstitutions.class);
+            replacements.registerSubstitutions(Long.class, LongSubstitutions.class);
+            replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class);
+            replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class);
+            replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
+            replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class);
         }
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Fri May 30 15:09:09 2014 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.phases.*;
@@ -72,7 +73,7 @@
 
     /**
      * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}.
-     * 
+     *
      * @return a node similar to {@code node} if one exists, otherwise {@code node}
      */
     public <T extends FloatingNode> T unique(T node) {
@@ -96,13 +97,13 @@
     }
 
     public InvokeNode createInvoke(Class<?> declaringClass, String name, ValueNode... args) {
-        return createInvoke(declaringClass, name, InvokeKind.Static, null, FrameState.UNKNOWN_BCI, args);
+        return createInvoke(declaringClass, name, InvokeKind.Static, null, BytecodeFrame.UNKNOWN_BCI, args);
     }
 
     /**
      * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
      * arguments. The method is looked up via reflection based on the declaring class and name.
-     * 
+     *
      * @param declaringClass the class declaring the invoked method
      * @param name the name of the invoked method
      * @param args the arguments to the invocation
@@ -125,7 +126,7 @@
      * arguments.
      */
     public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
-        assert Modifier.isStatic(method.getModifiers()) == (invokeKind == InvokeKind.Static);
+        assert method.isStatic() == (invokeKind == InvokeKind.Static);
         Signature signature = method.getSignature();
         JavaType returnType = signature.getReturnType(null);
         assert checkArgs(method, args);
@@ -150,14 +151,14 @@
 
     /**
      * Determines if a given set of arguments is compatible with the signature of a given method.
-     * 
+     *
      * @return true if {@code args} are compatible with the signature if {@code method}
      * @throws AssertionError if {@code args} are not compatible with the signature if
      *             {@code method}
      */
     public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
         Signature signature = method.getSignature();
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        boolean isStatic = method.isStatic();
         if (signature.getParameterCount(!isStatic) != args.length) {
             throw new AssertionError(graph + ": wrong number of arguments to " + method);
         }
@@ -185,16 +186,17 @@
     }
 
     /**
-     * {@linkplain #inline Inlines} all invocations currently in the graph.
+     * Recursively {@linkplain #inline inlines} all invocations currently in the graph.
      */
     public void inlineInvokes(SnippetReflectionProvider snippetReflection) {
-        for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
-            inline(invoke, snippetReflection);
+        while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) {
+            for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
+                inline(invoke, snippetReflection);
+            }
         }
 
         // Clean up all code that is now dead after inlining.
         new DeadCodeEliminationPhase().apply(graph);
-        assert graph.getNodes().filter(InvokeNode.class).isEmpty();
     }
 
     /**
@@ -239,7 +241,7 @@
      * emitting the code executed when the condition hold; and a call to {@link #elsePart} to start
      * emititng the code when the condition does not hold. It must be followed by a call to
      * {@link #endIf} to close the if-block.
-     * 
+     *
      * @param condition The condition for the if-block
      * @param trueProbability The estimated probability the the condition is true
      */
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -42,7 +42,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.util.*;
@@ -82,7 +81,7 @@
         NodeIntrinsic intrinsic = getIntrinsic(target);
         if (intrinsic != null) {
             assert target.getAnnotation(Fold.class) == null;
-            assert Modifier.isStatic(target.getModifiers()) : "node intrinsic must be static: " + target;
+            assert target.isStatic() : "node intrinsic must be static: " + target;
 
             ResolvedJavaType[] parameterTypes = resolveJavaTypes(signatureToTypes(target), declaringClass);
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -24,11 +24,12 @@
 
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
 
 import sun.misc.*;
 
@@ -49,6 +50,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy;
@@ -67,28 +69,165 @@
      */
     protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
 
-    // These data structures are all fully initialized during single-threaded
-    // compiler startup and so do not need to be concurrent.
-    protected final Map<ResolvedJavaMethod, ResolvedJavaMethod> registeredMethodSubstitutions;
-    private final Map<ResolvedJavaMethod, Class<? extends FixedWithNextNode>> registeredMacroSubstitutions;
-    private final Set<ResolvedJavaMethod> forcedSubstitutions;
+    /**
+     * Encapsulates method and macro substitutions for a single class.
+     */
+    protected class ClassReplacements {
+        protected final Map<ResolvedJavaMethod, ResolvedJavaMethod> methodSubstitutions = new HashMap<>();
+        private final Map<ResolvedJavaMethod, Class<? extends FixedWithNextNode>> macroSubstitutions = new HashMap<>();
+        private final Set<ResolvedJavaMethod> forcedSubstitutions = new HashSet<>();
+
+        public ClassReplacements(Class<?>[] substitutionClasses, AtomicReference<ClassReplacements> ref) {
+            for (Class<?> substitutionClass : substitutionClasses) {
+                ClassSubstitution classSubstitution = substitutionClass.getAnnotation(ClassSubstitution.class);
+                assert !Snippets.class.isAssignableFrom(substitutionClass);
+                SubstitutionGuard defaultGuard = getGuard(classSubstitution.defaultGuard());
+                for (Method substituteMethod : substitutionClass.getDeclaredMethods()) {
+                    if (ref.get() != null) {
+                        // Bail if another thread beat us creating the substitutions
+                        return;
+                    }
+                    MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class);
+                    MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class);
+                    if (methodSubstitution == null && macroSubstitution == null) {
+                        continue;
+                    }
+
+                    int modifiers = substituteMethod.getModifiers();
+                    if (!Modifier.isStatic(modifiers)) {
+                        throw new GraalInternalError("Substitution methods must be static: " + substituteMethod);
+                    }
+
+                    if (methodSubstitution != null) {
+                        SubstitutionGuard guard = getGuard(methodSubstitution.guard());
+                        if (guard == null) {
+                            guard = defaultGuard;
+                        }
+
+                        if (macroSubstitution != null && macroSubstitution.isStatic() != methodSubstitution.isStatic()) {
+                            throw new GraalInternalError("Macro and method substitution must agree on isStatic attribute: " + substituteMethod);
+                        }
+                        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+                            throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod);
+                        }
+                        String originalName = originalName(substituteMethod, methodSubstitution.value());
+                        JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
+                        Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
+                        if (originalMethod != null && (guard == null || guard.execute())) {
+                            ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod);
+                            if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
+                                forcedSubstitutions.add(original);
+                            }
+                        }
+                    }
+                    // We don't have per method guards for macro substitutions but at
+                    // least respect the defaultGuard if there is one.
+                    if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) {
+                        String originalName = originalName(substituteMethod, macroSubstitution.value());
+                        JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
+                        Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
+                        if (originalMethod != null) {
+                            ResolvedJavaMethod original = registerMacroSubstitution(this, originalMethod, macroSubstitution.macro());
+                            if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
+                                forcedSubstitutions.add(original);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private JavaSignature originalSignature(Method substituteMethod, String methodSubstitution, boolean isStatic) {
+            Class<?>[] parameters;
+            Class<?> returnType;
+            if (methodSubstitution.isEmpty()) {
+                parameters = substituteMethod.getParameterTypes();
+                if (!isStatic) {
+                    assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter";
+                    parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
+                }
+                returnType = substituteMethod.getReturnType();
+            } else {
+                Signature signature = providers.getMetaAccess().parseMethodDescriptor(methodSubstitution);
+                parameters = new Class[signature.getParameterCount(false)];
+                for (int i = 0; i < parameters.length; i++) {
+                    parameters[i] = resolveClass(signature.getParameterType(i, null));
+                }
+                returnType = resolveClass(signature.getReturnType(null));
+            }
+            return new JavaSignature(returnType, parameters);
+        }
+
+        private Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
+            Class<?> originalClass = classSubstitution.value();
+            if (originalClass == ClassSubstitution.class) {
+                originalClass = resolveClass(classSubstitution.className(), classSubstitution.optional());
+                if (originalClass == null) {
+                    // optional class was not found
+                    return null;
+                }
+            }
+            try {
+                if (name.equals("<init>")) {
+                    assert signature.returnType.equals(void.class) : signature;
+                    Constructor<?> original = originalClass.getDeclaredConstructor(signature.parameters);
+                    return original;
+                } else {
+                    Method original = originalClass.getDeclaredMethod(name, signature.parameters);
+                    if (!original.getReturnType().equals(signature.returnType)) {
+                        throw new NoSuchMethodException(originalClass.getName() + "." + name + signature);
+                    }
+                    return original;
+                }
+            } catch (NoSuchMethodException | SecurityException e) {
+                if (optional) {
+                    return null;
+                }
+                throw new GraalInternalError(e);
+            }
+        }
+    }
+
+    /**
+     * Per-class replacements. The entries in these maps are all fully initialized during
+     * single-threaded compiler startup and so do not need to be concurrent.
+     */
+    private final Map<String, AtomicReference<ClassReplacements>> classReplacements;
+    private final Map<String, Class<?>[]> internalNameToSubstitutionClasses;
+
     private final Map<Class<? extends SnippetTemplateCache>, SnippetTemplateCache> snippetTemplateCache;
 
     public ReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, Assumptions assumptions, TargetDescription target) {
         this.providers = providers.copyWith(this);
+        this.classReplacements = new HashMap<>();
+        this.internalNameToSubstitutionClasses = new HashMap<>();
         this.snippetReflection = snippetReflection;
         this.target = target;
         this.assumptions = assumptions;
         this.graphs = new ConcurrentHashMap<>();
-        this.registeredMethodSubstitutions = new HashMap<>();
-        this.registeredMacroSubstitutions = new HashMap<>();
-        this.forcedSubstitutions = new HashSet<>();
         this.snippetTemplateCache = new HashMap<>();
     }
 
     private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true"));
     private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime");
 
+    /**
+     * Gets the method and macro replacements for a given class. This method will parse the
+     * replacements in the substitution classes associated with {@code internalName} the first time
+     * this method is called for {@code internalName}.
+     */
+    protected ClassReplacements getClassReplacements(String internalName) {
+        Class<?>[] substitutionClasses = internalNameToSubstitutionClasses.get(internalName);
+        if (substitutionClasses != null) {
+            AtomicReference<ClassReplacements> crRef = classReplacements.get(internalName);
+            if (crRef.get() == null) {
+                crRef.compareAndSet(null, new ClassReplacements(substitutionClasses, crRef));
+            }
+            return crRef.get();
+        }
+        return null;
+    }
+
     public StructuredGraph getSnippet(ResolvedJavaMethod method) {
         return getSnippet(method, null);
     }
@@ -96,7 +235,7 @@
     @Override
     public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry) {
         assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
-        assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : "Snippet must not be abstract or native";
+        assert !method.isAbstract() && !method.isNative() : "Snippet must not be abstract or native";
 
         StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null;
         if (graph == null) {
@@ -132,7 +271,8 @@
 
     @Override
     public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) {
-        ResolvedJavaMethod substitute = registeredMethodSubstitutions.get(original);
+        ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName());
+        ResolvedJavaMethod substitute = cr == null ? null : cr.methodSubstitutions.get(original);
         if (substitute == null) {
             return null;
         }
@@ -149,7 +289,8 @@
     }
 
     public Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method) {
-        return registeredMacroSubstitutions.get(method);
+        ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName());
+        return cr == null ? null : cr.macroSubstitutions.get(method);
     }
 
     public Assumptions getAssumptions() {
@@ -167,59 +308,29 @@
         return null;
     }
 
-    public void registerSubstitutions(Class<?> substitutions) {
-        ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class);
-        assert classSubstitution != null;
-        assert !Snippets.class.isAssignableFrom(substitutions);
-        SubstitutionGuard defaultGuard = getGuard(classSubstitution.defaultGuard());
-        for (Method substituteMethod : substitutions.getDeclaredMethods()) {
-            MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class);
-            MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class);
-            if (methodSubstitution == null && macroSubstitution == null) {
-                continue;
-            }
-
-            int modifiers = substituteMethod.getModifiers();
-            if (!Modifier.isStatic(modifiers)) {
-                throw new GraalInternalError("Substitution methods must be static: " + substituteMethod);
-            }
-
-            if (methodSubstitution != null) {
-                SubstitutionGuard guard = getGuard(methodSubstitution.guard());
-                if (guard == null) {
-                    guard = defaultGuard;
-                }
+    private static String getOriginalInternalName(Class<?> substitutions) {
+        ClassSubstitution cs = substitutions.getAnnotation(ClassSubstitution.class);
+        assert cs != null : substitutions + " must be annotated by " + ClassSubstitution.class.getSimpleName();
+        if (cs.value() == ClassSubstitution.class) {
+            return toInternalName(cs.className());
+        }
+        return toInternalName(cs.value().getName());
+    }
 
-                if (macroSubstitution != null && macroSubstitution.isStatic() != methodSubstitution.isStatic()) {
-                    throw new GraalInternalError("Macro and method substitution must agree on isStatic attribute: " + substituteMethod);
-                }
-                if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-                    throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod);
-                }
-                String originalName = originalName(substituteMethod, methodSubstitution.value());
-                JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
-                Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
-                if (originalMethod != null && (guard == null || guard.execute())) {
-                    ResolvedJavaMethod original = registerMethodSubstitution(originalMethod, substituteMethod);
-                    if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
-                        forcedSubstitutions.add(original);
-                    }
-                }
-            }
-            // We don't have per method guards for macro substitutions but at
-            // least respect the defaultGuard if there is one.
-            if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) {
-                String originalName = originalName(substituteMethod, macroSubstitution.value());
-                JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
-                Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
-                if (originalMethod != null) {
-                    ResolvedJavaMethod original = registerMacroSubstitution(originalMethod, macroSubstitution.macro());
-                    if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
-                        forcedSubstitutions.add(original);
-                    }
-                }
-            }
+    public void registerSubstitutions(Type original, Class<?> substitutionClass) {
+        String internalName = toInternalName(original.getTypeName());
+        assert getOriginalInternalName(substitutionClass).equals(internalName) : getOriginalInternalName(substitutionClass) + " != " + (internalName);
+        Class<?>[] classes = internalNameToSubstitutionClasses.get(internalName);
+        if (classes == null) {
+            classes = new Class<?>[]{substitutionClass};
+        } else {
+            assert !Arrays.asList(classes).contains(substitutionClass);
+            classes = Arrays.copyOf(classes, classes.length + 1);
+            classes[classes.length - 1] = substitutionClass;
         }
+        internalNameToSubstitutionClasses.put(internalName, classes);
+        AtomicReference<ClassReplacements> existing = classReplacements.put(internalName, new AtomicReference<>());
+        assert existing == null || existing.get() == null;
     }
 
     /**
@@ -229,7 +340,7 @@
      * @param substituteMethod the substitute method
      * @return the original method
      */
-    protected ResolvedJavaMethod registerMethodSubstitution(Member originalMember, Method substituteMethod) {
+    protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMember, Method substituteMethod) {
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         ResolvedJavaMethod substitute = metaAccess.lookupJavaMethod(substituteMethod);
         ResolvedJavaMethod original;
@@ -242,7 +353,7 @@
             Debug.log("substitution: %s --> %s", MetaUtil.format("%H.%n(%p) %r", original), MetaUtil.format("%H.%n(%p) %r", substitute));
         }
 
-        registeredMethodSubstitutions.put(original, substitute);
+        cr.methodSubstitutions.put(original, substitute);
         return original;
     }
 
@@ -253,7 +364,7 @@
      * @param macro the substitute macro node class
      * @return the original method
      */
-    protected ResolvedJavaMethod registerMacroSubstitution(Member originalMethod, Class<? extends FixedWithNextNode> macro) {
+    protected ResolvedJavaMethod registerMacroSubstitution(ClassReplacements cr, Member originalMethod, Class<? extends FixedWithNextNode> macro) {
         ResolvedJavaMethod originalJavaMethod;
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         if (originalMethod instanceof Method) {
@@ -261,7 +372,7 @@
         } else {
             originalJavaMethod = metaAccess.lookupJavaConstructor((Constructor<?>) originalMethod);
         }
-        registeredMacroSubstitutions.put(originalJavaMethod, macro);
+        cr.macroSubstitutions.put(originalJavaMethod, macro);
         return originalJavaMethod;
     }
 
@@ -532,7 +643,7 @@
     }
 
     private static boolean isInlinable(final ResolvedJavaMethod method) {
-        return !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers());
+        return !method.isAbstract() && !method.isNative();
     }
 
     private static String originalName(Method substituteMethod, String methodSubstitution) {
@@ -550,7 +661,7 @@
      * @param optional if true, resolution failure returns null
      * @return the resolved class or null if resolution fails and {@code optional} is true
      */
-    static Class<?> resolveType(String className, boolean optional) {
+    static Class<?> resolveClass(String className, boolean optional) {
         try {
             // Need to use launcher class path to handle classes
             // that are not on the boot class path
@@ -564,7 +675,7 @@
         }
     }
 
-    private static Class<?> resolveType(JavaType type) {
+    private static Class<?> resolveClass(JavaType type) {
         JavaType base = type;
         int dimensions = 0;
         while (base.getComponentType() != null) {
@@ -572,7 +683,7 @@
             dimensions++;
         }
 
-        Class<?> baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false);
+        Class<?> baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveClass(toJavaName(base), false);
         return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass();
     }
 
@@ -598,67 +709,21 @@
         }
     }
 
-    private JavaSignature originalSignature(Method substituteMethod, String methodSubstitution, boolean isStatic) {
-        Class<?>[] parameters;
-        Class<?> returnType;
-        if (methodSubstitution.isEmpty()) {
-            parameters = substituteMethod.getParameterTypes();
-            if (!isStatic) {
-                assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter";
-                parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
-            }
-            returnType = substituteMethod.getReturnType();
-        } else {
-            Signature signature = providers.getMetaAccess().parseMethodDescriptor(methodSubstitution);
-            parameters = new Class[signature.getParameterCount(false)];
-            for (int i = 0; i < parameters.length; i++) {
-                parameters[i] = resolveType(signature.getParameterType(i, null));
-            }
-            returnType = resolveType(signature.getReturnType(null));
-        }
-        return new JavaSignature(returnType, parameters);
-    }
-
-    private static Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
-        Class<?> originalClass = classSubstitution.value();
-        if (originalClass == ClassSubstitution.class) {
-            originalClass = resolveType(classSubstitution.className(), classSubstitution.optional());
-            if (originalClass == null) {
-                // optional class was not found
-                return null;
-            }
-        }
-        try {
-            if (name.equals("<init>")) {
-                assert signature.returnType.equals(void.class) : signature;
-                Constructor<?> original = originalClass.getDeclaredConstructor(signature.parameters);
-                return original;
-            } else {
-                Method original = originalClass.getDeclaredMethod(name, signature.parameters);
-                if (!original.getReturnType().equals(signature.returnType)) {
-                    throw new NoSuchMethodException(originalClass.getName() + "." + name + signature);
-                }
-                return original;
-            }
-        } catch (NoSuchMethodException | SecurityException e) {
-            if (optional) {
-                return null;
-            }
-            throw new GraalInternalError(e);
-        }
-    }
-
     @Override
     public Collection<ResolvedJavaMethod> getAllReplacements() {
         HashSet<ResolvedJavaMethod> result = new HashSet<>();
-        result.addAll(registeredMethodSubstitutions.keySet());
-        result.addAll(registeredMacroSubstitutions.keySet());
+        for (String internalName : classReplacements.keySet()) {
+            ClassReplacements cr = getClassReplacements(internalName);
+            result.addAll(cr.methodSubstitutions.keySet());
+            result.addAll(cr.macroSubstitutions.keySet());
+        }
         return result;
     }
 
     @Override
     public boolean isForcedSubstitution(ResolvedJavaMethod method) {
-        return forcedSubstitutions.contains(method);
+        ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName());
+        return cr != null && cr.forcedSubstitutions.contains(method);
     }
 
     @Override
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,6 @@
 package com.oracle.graal.replacements;
 
 import java.lang.annotation.*;
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.replacements.nodes.*;
@@ -89,7 +87,7 @@
 
         @Override
         public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) {
-            if (Modifier.isNative(method.getModifiers())) {
+            if (method.isNative()) {
                 return false;
             }
             if (method.getAnnotation(Fold.class) != null) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Fri May 30 15:09:09 2014 +0200
@@ -24,7 +24,7 @@
 
 //JaCoCo Exclude
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.io.*;
 import java.util.*;
@@ -32,15 +32,13 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.replacements.Snippet.Fold;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
 
 /**
  * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering
  * snippet specific metrics.
  */
 public class SnippetCounter implements Comparable<SnippetCounter> {
-    private static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
-
     /**
      * A group of related counters.
      */
@@ -107,7 +105,7 @@
 
     /**
      * Creates a counter.
-     * 
+     *
      * @param group the group to which the counter belongs. If this is null, the newly created
      *            counter is disabled and {@linkplain #inc() incrementing} is a no-op.
      * @param name the name of the counter
@@ -130,12 +128,20 @@
     }
 
     /**
+     * We do not want to use the {@link LocationIdentity} of the {@link #value} field, so that the
+     * usage in snippets is always possible. If a method accesses the counter via the field and the
+     * snippet, the result might not be correct though.
+     */
+    protected static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
+
+    /**
      * Increments the value of this counter. This method can be safely used in a snippet if it is
      * invoked on a compile-time constant {@link SnippetCounter} object.
      */
     public void inc() {
         if (group != null) {
-            DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, SNIPPET_COUNTER_LOCATION);
+            long loadedValue = ObjectAccess.readLong(this, countOffset(), SNIPPET_COUNTER_LOCATION);
+            ObjectAccess.writeLong(this, countOffset(), loadedValue + 1, SNIPPET_COUNTER_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri May 30 15:09:09 2014 +0200
@@ -24,13 +24,17 @@
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.debug.Debug.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+import static com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates.*;
 import static java.util.FormattableFlags.*;
 
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -40,8 +44,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -49,10 +53,10 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.FloatingReadPhase.MemoryMapImpl;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
@@ -76,8 +80,51 @@
     public static class SnippetInfo {
 
         protected final ResolvedJavaMethod method;
-        protected final boolean[] constantParameters;
-        protected final boolean[] varargsParameters;
+
+        /**
+         * Lazily constructed parts of {@link SnippetInfo}.
+         */
+        static class Lazy {
+            public Lazy(ResolvedJavaMethod method) {
+                int count = method.getSignature().getParameterCount(false);
+                constantParameters = new boolean[count];
+                varargsParameters = new boolean[count];
+                for (int i = 0; i < count; i++) {
+                    constantParameters[i] = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method) != null;
+                    varargsParameters[i] = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method) != null;
+
+                    assert !constantParameters[i] || !varargsParameters[i] : "Parameter cannot be annotated with both @" + ConstantParameter.class.getSimpleName() + " and @" +
+                                    VarargsParameter.class.getSimpleName();
+                }
+
+                // Retrieve the names only when assertions are turned on.
+                assert initNames(method, count);
+            }
+
+            final boolean[] constantParameters;
+            final boolean[] varargsParameters;
+
+            /**
+             * The parameter names, taken from the local variables table. Only used for assertion
+             * checking, so use only within an assert statement.
+             */
+            String[] names;
+
+            private boolean initNames(ResolvedJavaMethod method, int parameterCount) {
+                names = new String[parameterCount];
+                int slotIdx = 0;
+                for (int i = 0; i < names.length; i++) {
+                    names[i] = method.getLocalVariableTable().getLocal(slotIdx, 0).getName();
+
+                    Kind kind = method.getSignature().getParameterKind(i);
+                    slotIdx += kind == Kind.Long || kind == Kind.Double ? 2 : 1;
+                }
+                return true;
+            }
+
+        }
+
+        protected final AtomicReference<Lazy> lazy = new AtomicReference<>(null);
 
         /**
          * Times instantiations of all templates derived form this snippet.
@@ -93,31 +140,18 @@
          */
         private final DebugMetric instantiationCounter;
 
-        /**
-         * The parameter names, taken from the local variables table. Only used for assertion
-         * checking, so use only within an assert statement.
-         */
-        protected final String[] names;
+        private Lazy lazy() {
+            if (lazy.get() == null) {
+                lazy.compareAndSet(null, new Lazy(method));
+            }
+            return lazy.get();
+        }
 
         protected SnippetInfo(ResolvedJavaMethod method) {
             this.method = method;
             instantiationCounter = Debug.metric("SnippetInstantiationCount[%s]", method);
             instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", method);
-            assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + MetaUtil.format("%H.%n", method);
-            int count = method.getSignature().getParameterCount(false);
-            constantParameters = new boolean[count];
-            varargsParameters = new boolean[count];
-            for (int i = 0; i < count; i++) {
-                constantParameters[i] = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method) != null;
-                varargsParameters[i] = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method) != null;
-
-                assert !isConstantParameter(i) || !isVarargsParameter(i) : "Parameter cannot be annotated with both @" + ConstantParameter.class.getSimpleName() + " and @" +
-                                VarargsParameter.class.getSimpleName();
-            }
-
-            names = new String[count];
-            // Retrieve the names only when assertions are turned on.
-            assert initNames();
+            assert method.isStatic() : "snippet method must be static: " + MetaUtil.format("%H.%n", method);
         }
 
         private int templateCount;
@@ -131,35 +165,28 @@
             }
         }
 
-        private boolean initNames() {
-            int slotIdx = 0;
-            for (int i = 0; i < names.length; i++) {
-                names[i] = method.getLocalVariableTable().getLocal(slotIdx, 0).getName();
-
-                Kind kind = method.getSignature().getParameterKind(i);
-                slotIdx += kind == Kind.Long || kind == Kind.Double ? 2 : 1;
-            }
-            return true;
-        }
-
         public ResolvedJavaMethod getMethod() {
             return method;
         }
 
         public int getParameterCount() {
-            return constantParameters.length;
+            return lazy().constantParameters.length;
         }
 
         public boolean isConstantParameter(int paramIdx) {
-            return constantParameters[paramIdx];
+            return lazy().constantParameters[paramIdx];
         }
 
         public boolean isVarargsParameter(int paramIdx) {
-            return varargsParameters[paramIdx];
+            return lazy().varargsParameters[paramIdx];
         }
 
         public String getParameterName(int paramIdx) {
-            return names[paramIdx];
+            String[] names = lazy().names;
+            if (names != null) {
+                return names[paramIdx];
+            }
+            return null;
         }
     }
 
@@ -221,7 +248,7 @@
 
         private boolean check(String name, boolean constParam, boolean varargsParam) {
             assert nextParamIdx < info.getParameterCount() : "too many parameters: " + name + "  " + this;
-            assert info.names[nextParamIdx].equals(name) : "wrong parameter name: " + name + "  " + this;
+            assert info.getParameterName(nextParamIdx) == null || info.getParameterName(nextParamIdx).equals(name) : "wrong parameter name: " + name + "  " + this;
             assert constParam == info.isConstantParameter(nextParamIdx) : "Parameter " + (constParam ? "not " : "") + "annotated with @" + ConstantParameter.class.getSimpleName() + ": " + name +
                             "  " + this;
             assert varargsParam == info.isVarargsParameter(nextParamIdx) : "Parameter " + (varargsParam ? "not " : "") + "annotated with @" + VarargsParameter.class.getSimpleName() + ": " + name +
@@ -241,7 +268,7 @@
                 } else if (info.isVarargsParameter(i)) {
                     result.append("varargs ");
                 }
-                result.append(info.names[i]).append(" = ").append(values[i]);
+                result.append(info.getParameterName(i)).append(" = ").append(values[i]);
                 sep = ", ";
             }
             result.append(">");
@@ -258,8 +285,8 @@
                 for (int i = 0; i < info.getParameterCount(); i++) {
                     if (info.isConstantParameter(i)) {
                         sb.append(sep);
-                        if (info.names[i] != null) {
-                            sb.append(info.names[i]);
+                        if (info.getParameterName(i) != null) {
+                            sb.append(info.getParameterName(i));
                         } else {
                             sb.append(i);
                         }
@@ -392,13 +419,14 @@
     private static final DebugMetric SnippetTemplates = Debug.metric("SnippetTemplateCount");
 
     private static final String MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME = "graal.maxTemplatesPerSnippet";
-    private static final boolean UseSnippetTemplateCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetTemplateCache", "true"));
     private static final int MaxTemplatesPerSnippet = Integer.getInteger(MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME, 50);
 
     /**
      * Base class for snippet classes. It provides a cache for {@link SnippetTemplate}s.
      */
-    public abstract static class AbstractTemplates implements SnippetTemplateCache {
+    public abstract static class AbstractTemplates implements com.oracle.graal.api.replacements.SnippetTemplateCache {
+
+        static final boolean UseSnippetTemplateCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetTemplateCache", "true"));
 
         protected final Providers providers;
         protected final SnippetReflectionProvider snippetReflection;
@@ -416,25 +444,27 @@
             }
         }
 
+        private static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
+            for (Method m : declaringClass.getDeclaredMethods()) {
+                if (m.getName().equals(methodName) && !m.equals(except)) {
+                    return m;
+                }
+            }
+            return null;
+        }
+
         /**
-         * Finds the method in {@code declaringClass} annotated with {@link Snippet} named
-         * {@code methodName}. If {@code methodName} is null, then there must be exactly one snippet
-         * method in {@code declaringClass}.
+         * Finds the unique method in {@code declaringClass} named {@code methodName} annotated by
+         * {@link Snippet} and returns a {@link SnippetInfo} value describing it. There must be
+         * exactly one snippet method in {@code declaringClass}.
          */
         protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName) {
-            Method found = null;
-            Class<?> clazz = declaringClass;
-            while (clazz != Object.class) {
-                for (Method method : clazz.getDeclaredMethods()) {
-                    if (method.getAnnotation(Snippet.class) != null && (methodName == null || method.getName().equals(methodName))) {
-                        assert found == null : "found more than one @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName);
-                        found = method;
-                    }
-                }
-                clazz = clazz.getSuperclass();
-            }
-            assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName);
-            ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(found);
+            assert methodName != null;
+            Method method = findMethod(declaringClass, methodName, null);
+            assert method != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + " named " + methodName;
+            assert method.getAnnotation(Snippet.class) != null : method + " must be annotated with @" + Snippet.class.getSimpleName();
+            assert findMethod(declaringClass, methodName, method) == null : "found more than one method named " + methodName + " in " + declaringClass;
+            ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(method);
             providers.getReplacements().registerSnippet(javaMethod);
             return new SnippetInfo(javaMethod);
         }
@@ -493,7 +523,7 @@
 
         // Copy snippet graph, replacing constant parameters with given arguments
         final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
-        IdentityHashMap<Node, Node> nodeReplacements = new IdentityHashMap<>();
+        Map<Node, Node> nodeReplacements = newNodeIdentityMap();
         nodeReplacements.put(snippetGraph.start(), snippetCopy.start());
 
         MetaAccessProvider metaAccess = providers.getMetaAccess();
@@ -641,11 +671,6 @@
 
         MemoryAnchorNode memoryAnchor = snippetCopy.add(new MemoryAnchorNode());
         snippetCopy.start().replaceAtUsages(InputType.Memory, memoryAnchor);
-        if (memoryAnchor.usages().isEmpty()) {
-            memoryAnchor.safeDelete();
-        } else {
-            snippetCopy.addAfterFixed(snippetCopy.start(), memoryAnchor);
-        }
 
         this.snippet = snippetCopy;
 
@@ -654,9 +679,10 @@
         List<ReturnNode> returnNodes = new ArrayList<>(4);
         List<MemoryMapNode> memMaps = new ArrayList<>(4);
         StartNode entryPointNode = snippet.start();
+        boolean anchorUsed = false;
         for (ReturnNode retNode : snippet.getNodes(ReturnNode.class)) {
             MemoryMapNode memMap = retNode.getMemoryMap();
-            memMap.replaceLastLocationAccess(snippetCopy.start(), memoryAnchor);
+            anchorUsed |= memMap.replaceLastLocationAccess(snippetCopy.start(), memoryAnchor);
             memMaps.add(memMap);
             retNode.setMemoryMap(null);
             returnNodes.add(retNode);
@@ -664,6 +690,11 @@
                 memMap.safeDelete();
             }
         }
+        if (memoryAnchor.usages().isEmpty() && !anchorUsed) {
+            memoryAnchor.safeDelete();
+        } else {
+            snippetCopy.addAfterFixed(snippetCopy.start(), memoryAnchor);
+        }
         assert snippet.getNodes().filter(MemoryMapNode.class).isEmpty();
         if (returnNodes.isEmpty()) {
             this.returnNode = null;
@@ -789,19 +820,19 @@
      *
      * @return the map that will be used to bind arguments to parameters when inlining this template
      */
-    private IdentityHashMap<Node, Node> bind(StructuredGraph replaceeGraph, MetaAccessProvider metaAccess, Arguments args) {
-        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
+    private Map<Node, Node> bind(StructuredGraph replaceeGraph, MetaAccessProvider metaAccess, Arguments args) {
+        Map<Node, Node> replacements = newNodeIdentityMap();
         assert args.info.getParameterCount() == parameters.length : "number of args (" + args.info.getParameterCount() + ") != number of parameters (" + parameters.length + ")";
         for (int i = 0; i < parameters.length; i++) {
             Object parameter = parameters[i];
-            assert parameter != null : this + " has no parameter named " + args.info.names[i];
+            assert parameter != null : this + " has no parameter named " + args.info.getParameterName(i);
             Object argument = args.values[i];
             if (parameter instanceof ParameterNode) {
                 if (argument instanceof ValueNode) {
                     replacements.put((ParameterNode) parameter, (ValueNode) argument);
                 } else {
                     Kind kind = ((ParameterNode) parameter).getKind();
-                    assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + args.info.names[i];
+                    assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + args.info.getParameterName(i);
                     Constant constant = forBoxed(argument, kind);
                     replacements.put((ParameterNode) parameter, ConstantNode.forConstant(constant, metaAccess, replaceeGraph));
                 }
@@ -833,7 +864,7 @@
                     }
                 }
             } else {
-                assert parameter == CONSTANT_PARAMETER || parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + args.info.names[i] + " -> " + parameter;
+                assert parameter == CONSTANT_PARAMETER || parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + args.info.getParameterName(i) + " -> " + parameter;
             }
         }
         return replacements;
@@ -862,7 +893,6 @@
      * lowered and the stamp of the snippet's return value.
      */
     public interface UsageReplacer {
-
         /**
          * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}.
          */
@@ -966,7 +996,15 @@
          * if no FloatingReadNode is reading from this location, the kill to this location is fine.
          */
         for (FloatingReadNode frn : replacee.graph().getNodes(FloatingReadNode.class)) {
-            assert !(kills.contains(frn.location().getLocationIdentity())) : frn + " reads from " + frn.location().getLocationIdentity() + " but " + replacee + " does not kill this location";
+            LocationIdentity locationIdentity = frn.location().getLocationIdentity();
+            if (SnippetCounters.getValue()) {
+                // accesses to snippet counters are artificially introduced and violate the memory
+                // semantics.
+                if (locationIdentity == SnippetCounter.SNIPPET_COUNTER_LOCATION) {
+                    continue;
+                }
+            }
+            assert !kills.contains(locationIdentity) : frn + " reads from location \"" + locationIdentity + "\" but " + replacee + " does not kill this location";
         }
         return true;
     }
@@ -999,7 +1037,7 @@
         }
 
         @Override
-        public void replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
+        public boolean replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
             throw GraalInternalError.shouldNotReachHere();
         }
     }
@@ -1022,7 +1060,7 @@
             StartNode entryPointNode = snippet.start();
             FixedNode firstCFGNode = entryPointNode.next();
             StructuredGraph replaceeGraph = replacee.graph();
-            IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
+            Map<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
             replacements.put(entryPointNode, BeginNode.prevBegin(replacee));
             Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
             Debug.dump(replaceeGraph, "After inlining snippet %s", snippet.method());
@@ -1175,7 +1213,7 @@
             StartNode entryPointNode = snippet.start();
             FixedNode firstCFGNode = entryPointNode.next();
             StructuredGraph replaceeGraph = replacee.graph();
-            IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
+            Map<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
             replacements.put(entryPointNode, tool.getCurrentGuardAnchor().asNode());
             Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
             Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method());
@@ -1242,12 +1280,12 @@
         for (int i = 0; i < args.info.getParameterCount(); i++) {
             if (args.info.isConstantParameter(i)) {
                 Kind kind = signature.getParameterKind(i);
-                assert checkConstantArgument(metaAccess, method, signature, i, args.info.names[i], args.values[i], kind);
+                assert checkConstantArgument(metaAccess, method, signature, i, args.info.getParameterName(i), args.values[i], kind);
 
             } else if (args.info.isVarargsParameter(i)) {
                 assert args.values[i] instanceof Varargs;
                 Varargs varargs = (Varargs) args.values[i];
-                assert checkVarargs(metaAccess, method, signature, i, args.info.names[i], varargs);
+                assert checkVarargs(metaAccess, method, signature, i, args.info.getParameterName(i), varargs);
             }
         }
         return true;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.reflect.*;
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java	Fri May 30 15:09:09 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
@@ -42,17 +42,17 @@
 
     @MethodSubstitution(isStatic = false)
     public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) {
-        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x, Kind.Object, LocationIdentity.ANY_LOCATION);
+        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x, Kind.Object, LocationIdentity.ANY_LOCATION);
     }
 
     @MethodSubstitution(isStatic = false)
     public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) {
-        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x, Kind.Int, LocationIdentity.ANY_LOCATION);
+        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x, Kind.Int, LocationIdentity.ANY_LOCATION);
     }
 
     @MethodSubstitution(isStatic = false)
     public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) {
-        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x, Kind.Long, LocationIdentity.ANY_LOCATION);
+        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x, Kind.Long, LocationIdentity.ANY_LOCATION);
     }
 
     @MethodSubstitution(isStatic = false)
@@ -399,4 +399,47 @@
         }
         return DynamicNewInstanceNode.allocateInstance(clazz, true);
     }
+
+    /**
+     * Guard for {@link Unsafe#getAndSetInt} method family.
+     */
+    public static class GetAndSetGuard implements SubstitutionGuard {
+        public boolean execute() {
+            // FIXME should return whether the current compilation target supports these
+            String arch = System.getProperty("os.arch");
+            switch (arch) {
+                case "amd64":
+                case "x86_64":
+                    return true;
+                default:
+                    return false;
+            }
+        }
+    }
+
+    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
+    public static int getAndAddInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int delta) {
+        return AtomicReadAndAddNode.getAndAddInt(o, offset, delta, LocationIdentity.ANY_LOCATION);
+    }
+
+    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
+    public static long getAndAddLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long delta) {
+        return AtomicReadAndAddNode.getAndAddLong(o, offset, delta, LocationIdentity.ANY_LOCATION);
+    }
+
+    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
+    public static int getAndSetInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int newValue) {
+        return AtomicReadAndWriteNode.getAndSetInt(o, offset, newValue, Kind.Int, LocationIdentity.ANY_LOCATION);
+    }
+
+    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
+    public static long getAndSetLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long newValue) {
+        return AtomicReadAndWriteNode.getAndSetLong(o, offset, newValue, Kind.Long, LocationIdentity.ANY_LOCATION);
+    }
+
+    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
+    public static Object getAndSetObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object newValue) {
+        return AtomicReadAndWriteNode.getAndSetObject(o, offset, newValue, Kind.Object, LocationIdentity.ANY_LOCATION);
+    }
+
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,20 +23,18 @@
 package com.oracle.graal.replacements.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.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, Virtualizable {
+public class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable {
 
     /** {@link Kind} of the arrays to compare. */
     private final Kind kind;
@@ -131,7 +129,7 @@
     public static native boolean equals(double[] array1, double[] array2, int length);
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,16 +23,15 @@
 package com.oracle.graal.replacements.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitCountNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -65,7 +64,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitCount(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,16 +23,15 @@
 package com.oracle.graal.replacements.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanForwardNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -72,7 +71,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitScanForward(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,16 +23,15 @@
 package com.oracle.graal.replacements.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanReverseNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -79,7 +78,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,11 +23,11 @@
 package com.oracle.graal.replacements.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,13 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,13 +22,13 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,9 +24,9 @@
 
 import java.util.*;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.Snippet.VarargsParameter;
 
 /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,7 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static java.lang.reflect.Modifier.*;
-
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
@@ -36,6 +35,7 @@
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
 
@@ -89,7 +89,7 @@
         StructuredGraph methodSubstitution = tool.getReplacements().getMethodSubstitution(getTargetMethod());
         if (methodSubstitution != null) {
             methodSubstitution = methodSubstitution.copy();
-            if (stateAfter() == null || stateAfter().bci == FrameState.AFTER_BCI) {
+            if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) {
                 /*
                  * handles the case of a MacroNode inside a snippet used for another MacroNode
                  * lowering
@@ -136,7 +136,7 @@
         if (replacementGraph != null) {
             // Pull out the receiver null check so that a replaced
             // receiver can be lowered if necessary
-            if (!isStatic(targetMethod.getModifiers())) {
+            if (!targetMethod.isStatic()) {
                 ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
                 if (nonNullReceiver instanceof Lowerable) {
                     ((Lowerable) nonNullReceiver).lower(tool);
@@ -173,7 +173,7 @@
             if (!call.targetMethod().equals(getTargetMethod())) {
                 throw new GraalInternalError("unexpected invoke %s in snippet", getClass().getSimpleName());
             }
-            assert invoke.stateAfter().bci == FrameState.AFTER_BCI;
+            assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI;
             // Here we need to fix the bci of the invoke
             InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci()));
             newInvoke.setStateAfter(invoke.stateAfter());
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,12 +24,13 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 public class MathIntrinsicNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MemoryAnchorNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MemoryAnchorNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.replacements.nodes;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Access the value of a specific register.
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,16 +23,15 @@
 package com.oracle.graal.replacements.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class ReverseBytesNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -66,9 +65,9 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(value.getKind());
-        gen.getLIRGenerator().emitByteSwap(result, gen.operand(value));
+        gen.getLIRGeneratorTool().emitByteSwap(result, gen.operand(value));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Changes the value of a specific register.
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,28 +35,28 @@
  */
 public class SPARC extends Architecture {
 
-    // @formatter:off
-
     public static final RegisterCategory CPU = new RegisterCategory("CPU");
     public static final RegisterCategory FPU = new RegisterCategory("FPU");
 
     // General purpose registers
-    public static final Register r0  = new Register(0, 0, "g0", CPU);
-    public static final Register r1  = new Register(1, 1, "g1", CPU);
-    public static final Register r2  = new Register(2, 2, "g2", CPU);
-    public static final Register r3  = new Register(3, 3, "g3", CPU);
-    public static final Register r4  = new Register(4, 4, "g4", CPU);
-    public static final Register r5  = new Register(5, 5, "g5", CPU);
-    public static final Register r6  = new Register(6, 6, "g6", CPU);
-    public static final Register r7  = new Register(7, 7, "g7", CPU);
-    public static final Register r8  = new Register(8, 8, "o0", CPU);
-    public static final Register r9  = new Register(9, 9, "o1", CPU);
+    public static final Register r0 = new Register(0, 0, "g0", CPU);
+    public static final Register r1 = new Register(1, 1, "g1", CPU);
+    public static final Register r2 = new Register(2, 2, "g2", CPU);
+    public static final Register r3 = new Register(3, 3, "g3", CPU);
+    public static final Register r4 = new Register(4, 4, "g4", CPU);
+    public static final Register r5 = new Register(5, 5, "g5", CPU);
+    public static final Register r6 = new Register(6, 6, "g6", CPU);
+    public static final Register r7 = new Register(7, 7, "g7", CPU);
+
+    public static final Register r8 = new Register(8, 8, "o0", CPU);
+    public static final Register r9 = new Register(9, 9, "o1", CPU);
     public static final Register r10 = new Register(10, 10, "o2", CPU);
     public static final Register r11 = new Register(11, 11, "o3", CPU);
     public static final Register r12 = new Register(12, 12, "o4", CPU);
     public static final Register r13 = new Register(13, 13, "o5", CPU);
     public static final Register r14 = new Register(14, 14, "o6", CPU);
     public static final Register r15 = new Register(15, 15, "o7", CPU);
+
     public static final Register r16 = new Register(16, 16, "l0", CPU);
     public static final Register r17 = new Register(17, 17, "l1", CPU);
     public static final Register r18 = new Register(18, 18, "l2", CPU);
@@ -65,6 +65,7 @@
     public static final Register r21 = new Register(21, 21, "l5", CPU);
     public static final Register r22 = new Register(22, 22, "l6", CPU);
     public static final Register r23 = new Register(23, 23, "l7", CPU);
+
     public static final Register r24 = new Register(24, 24, "i0", CPU);
     public static final Register r25 = new Register(25, 25, "i1", CPU);
     public static final Register r26 = new Register(26, 26, "i2", CPU);
@@ -113,12 +114,14 @@
     public static final Register sp = o6;
     public static final Register fp = i6;
 
+    // @formatter:off
     public static final Register[] cpuRegisters = {
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
         r8,  r9,  r10, r11, r12, r13, r14, r15,
         r16, r17, r18, r19, r20, r21, r22, r23,
         r24, r25, r26, r27, r28, r29, r30, r31
     };
+    // @formatter:on
 
     // Floating point registers
     public static final Register f0 = new Register(32, 0, "f0", FPU);
@@ -130,6 +133,43 @@
     public static final Register f6 = new Register(38, 6, "f6", FPU);
     public static final Register f7 = new Register(39, 7, "f7", FPU);
 
+    public static final Register f8 = new Register(40, 8, "f8", FPU);
+    public static final Register f9 = new Register(41, 9, "f9", FPU);
+    public static final Register f10 = new Register(42, 10, "f10", FPU);
+    public static final Register f11 = new Register(43, 11, "f11", FPU);
+    public static final Register f12 = new Register(44, 12, "f12", FPU);
+    public static final Register f13 = new Register(45, 13, "f13", FPU);
+    public static final Register f14 = new Register(46, 14, "f14", FPU);
+    public static final Register f15 = new Register(47, 15, "f15", FPU);
+
+    public static final Register f16 = new Register(48, 16, "f16", FPU);
+    public static final Register f17 = new Register(49, 17, "f17", FPU);
+    public static final Register f18 = new Register(50, 18, "f18", FPU);
+    public static final Register f19 = new Register(51, 19, "f19", FPU);
+    public static final Register f20 = new Register(52, 20, "f20", FPU);
+    public static final Register f21 = new Register(53, 21, "f21", FPU);
+    public static final Register f22 = new Register(54, 22, "f22", FPU);
+    public static final Register f23 = new Register(55, 23, "f23", FPU);
+
+    public static final Register f24 = new Register(56, 24, "f24", FPU);
+    public static final Register f25 = new Register(57, 25, "f25", FPU);
+    public static final Register f26 = new Register(58, 26, "f26", FPU);
+    public static final Register f27 = new Register(59, 27, "f27", FPU);
+    public static final Register f28 = new Register(60, 28, "f28", FPU);
+    public static final Register f29 = new Register(61, 29, "f29", FPU);
+    public static final Register f30 = new Register(62, 30, "f30", FPU);
+    public static final Register f31 = new Register(63, 31, "f31", FPU);
+
+    // @formatter:off
+    public static final Register[] fpuRegisters = {
+        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+        f8,  f9,  f10, f11, f12, f13, f14, f15,
+        f16, f17, f18, f19, f20, f21, f22, f23,
+        f24, f25, f26, f27, f28, f29, f30, f31
+    };
+    // @formatter:on
+
+    // @formatter:off
     public static final Register[] allRegisters = {
         // CPU
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
@@ -138,9 +178,16 @@
         r24, r25, r26, r27, r28, r29, r30, r31,
         // FPU
         f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+        f8,  f9,  f10, f11, f12, f13, f14, f15,
+        f16, f17, f18, f19, f20, f21, f22, f23,
+        f24, f25, f26, f27, f28, f29, f30, f31
     };
+    // @formatter:on
 
-    // @formatter:on
+    /**
+     * Stack bias for stack and frame pointer loads.
+     */
+    public static final int STACK_BIAS = 0x7ff;
 
     public SPARC() {
         super("SPARC", 8, ByteOrder.BIG_ENDIAN, false, allRegisters, LOAD_STORE | STORE_STORE, 1, r31.encoding + 1, 8);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/AnsiTerminalDecorator.java	Fri May 30 15:09:09 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.test;
+
+import org.junit.runner.*;
+import org.junit.runner.notification.*;
+
+import static com.oracle.graal.debug.AnsiColor.*;
+
+/**
+ * Color support for JUnit test output using ANSI escapes codes.
+ */
+public class AnsiTerminalDecorator extends GraalJUnitRunListenerDecorator {
+
+    public AnsiTerminalDecorator(GraalJUnitRunListener l) {
+        super(l);
+    }
+
+    @Override
+    public void testSucceeded(Description description) {
+        getWriter().print(GREEN);
+        super.testSucceeded(description);
+        getWriter().print(RESET);
+    }
+
+    @Override
+    public void testFailed(Failure failure) {
+        getWriter().print(RED);
+        super.testFailed(failure);
+        getWriter().print(RESET);
+    }
+
+    @Override
+    public void testIgnored(Description description) {
+        getWriter().print(MAGENTA);
+        super.testIgnored(description);
+        getWriter().print(RESET);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/EagerStackTraceDecorator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import org.junit.runner.notification.*;
+
+public class EagerStackTraceDecorator extends GraalJUnitRunListenerDecorator {
+
+    public EagerStackTraceDecorator(GraalJUnitRunListener l) {
+        super(l);
+    }
+
+    @Override
+    public void testFailed(Failure failure) {
+        super.testFailed(failure);
+        failure.getException().printStackTrace(getWriter());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GCAfterTestDecorator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import org.junit.runner.*;
+
+public class GCAfterTestDecorator extends GraalJUnitRunListenerDecorator {
+
+    public GCAfterTestDecorator(GraalJUnitRunListener l) {
+        super(l);
+    }
+
+    @Override
+    public void testFinished(Description description) {
+        System.gc();
+        super.testFinished(description);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import java.util.*;
+
+import junit.runner.*;
+
+import org.junit.internal.*;
+import org.junit.runner.*;
+import org.junit.runner.notification.*;
+
+public class GraalJUnitCore {
+
+    /**
+     * Run the tests contained in the classes named in the <code>args</code>. If all tests run
+     * successfully, exit with a status of 0. Otherwise exit with a status of 1. Write feedback
+     * while tests are running and write stack traces for all failed tests after the tests all
+     * complete.
+     *
+     * @param args names of classes in which to find tests to run
+     */
+    public static void main(String... args) {
+        JUnitSystem system = new RealSystem();
+        JUnitCore junitCore = new JUnitCore();
+        system.out().println("GraalJUnitCore");
+        system.out().println("JUnit version " + Version.id());
+        List<Class<?>> classes = new ArrayList<>();
+        List<Failure> missingClasses = new ArrayList<>();
+        boolean verbose = false;
+        boolean enableTiming = false;
+        boolean color = false;
+        boolean eagerStackTrace = false;
+        boolean gcAfterTest = false;
+        for (String each : args) {
+            if (each.charAt(0) == '-') {
+                // command line arguments
+                if (each.contentEquals("-JUnitVerbose")) {
+                    verbose = true;
+                } else if (each.contentEquals("-JUnitEnableTiming")) {
+                    enableTiming = true;
+                } else if (each.contentEquals("-JUnitColor")) {
+                    color = true;
+                } else if (each.contentEquals("-JUnitEagerStackTrace")) {
+                    eagerStackTrace = true;
+                } else if (each.contentEquals("-JUnitGCAfterTest")) {
+                    gcAfterTest = true;
+                } else {
+                    system.out().println("Unknown command line argument: " + each);
+                }
+
+            } else {
+                try {
+                    classes.add(Class.forName(each));
+                } catch (ClassNotFoundException e) {
+                    system.out().println("Could not find class: " + each);
+                    Description description = Description.createSuiteDescription(each);
+                    Failure failure = new Failure(description, e);
+                    missingClasses.add(failure);
+                }
+            }
+        }
+        GraalJUnitRunListener graalListener;
+        if (!verbose) {
+            graalListener = new GraalTextListener(system);
+        } else {
+            graalListener = new GraalVerboseTextListener(system);
+        }
+        if (enableTiming) {
+            graalListener = new TimingDecorator(graalListener);
+        }
+        if (color) {
+            graalListener = new AnsiTerminalDecorator(graalListener);
+        }
+        if (eagerStackTrace) {
+            graalListener = new EagerStackTraceDecorator(graalListener);
+        }
+        if (gcAfterTest) {
+            graalListener = new GCAfterTestDecorator(graalListener);
+        }
+        junitCore.addListener(GraalTextListener.createRunListener(graalListener));
+        Result result = junitCore.run(classes.toArray(new Class[0]));
+        for (Failure each : missingClasses) {
+            result.getFailures().add(each);
+        }
+        System.exit(result.wasSuccessful() ? 0 : 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitRunListener.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import java.io.*;
+
+import org.junit.internal.*;
+import org.junit.runner.*;
+import org.junit.runner.notification.*;
+
+public interface GraalJUnitRunListener {
+
+    /**
+     * Called before any tests have been run.
+     *
+     * @param description describes the tests to be run
+     */
+    public void testRunStarted(Description description);
+
+    /**
+     * Called when all tests have finished
+     *
+     * @param result the summary of the test run, including all the tests that failed
+     */
+    public void testRunFinished(Result result);
+
+    /**
+     * Called when a test class is about to be started.
+     *
+     * @param clazz the test class
+     */
+    void testClassStarted(Class<?> clazz);
+
+    /**
+     * Called when all tests of a test class have finished.
+     *
+     * @param clazz the test class
+     */
+    void testClassFinished(Class<?> clazz);
+
+    /**
+     * Called when an atomic test is about to be started. This is also called for ignored tests.
+     *
+     * @param description the description of the test that is about to be run (generally a class and
+     *            method name)
+     */
+    void testStarted(Description description);
+
+    /**
+     * Called when an atomic test has finished, whether the test succeeds, fails or is ignored.
+     *
+     * @param description the description of the test that just ran
+     */
+    void testFinished(Description description);
+
+    /**
+     * Called when an atomic test fails.
+     *
+     * @param failure describes the test that failed and the exception that was thrown
+     */
+    void testFailed(Failure failure);
+
+    /**
+     * Called when a test will not be run, generally because a test method is annotated with
+     * {@link org.junit.Ignore}.
+     *
+     * @param description describes the test that will not be run
+     */
+    public void testIgnored(Description description);
+
+    /**
+     * Called when an atomic test succeeds.
+     *
+     * @param description describes the test that will not be run
+     */
+    void testSucceeded(Description description);
+
+    /**
+     * Called when an atomic test flags that it assumes a condition that is false
+     *
+     * @param failure describes the test that failed and the {@link AssumptionViolatedException}
+     *            that was thrown
+     */
+    public void testAssumptionFailure(Failure failure);
+
+    /**
+     * Called after {@link #testClassFinished(Class)}.
+     */
+    public void testClassFinishedDelimiter();
+
+    /**
+     * Called after {@link #testClassStarted(Class)}
+     */
+    public void testClassStartedDelimiter();
+
+    /**
+     * Called after {@link #testStarted(Description)}
+     */
+    public void testStartedDelimiter();
+
+    /**
+     * Called after {@link #testFailed(Failure)}
+     */
+    public void testFinishedDelimiter();
+
+    public PrintStream getWriter();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitRunListenerDecorator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import java.io.*;
+
+import org.junit.runner.*;
+import org.junit.runner.notification.*;
+
+public class GraalJUnitRunListenerDecorator implements GraalJUnitRunListener {
+
+    private final GraalJUnitRunListener l;
+
+    public GraalJUnitRunListenerDecorator(GraalJUnitRunListener l) {
+        this.l = l;
+    }
+
+    @Override
+    public void testRunStarted(Description description) {
+        l.testRunStarted(description);
+    }
+
+    @Override
+    public void testRunFinished(Result result) {
+        l.testRunFinished(result);
+    }
+
+    @Override
+    public void testAssumptionFailure(Failure failure) {
+        l.testAssumptionFailure(failure);
+    }
+
+    @Override
+    public void testIgnored(Description description) {
+        l.testIgnored(description);
+    }
+
+    @Override
+    public void testClassStarted(Class<?> clazz) {
+        l.testClassStarted(clazz);
+    }
+
+    @Override
+    public void testClassFinished(Class<?> clazz) {
+        l.testClassFinished(clazz);
+    }
+
+    @Override
+    public void testStarted(Description description) {
+        l.testStarted(description);
+    }
+
+    @Override
+    public void testFinished(Description description) {
+        l.testFinished(description);
+    }
+
+    @Override
+    public void testFailed(Failure failure) {
+        l.testFailed(failure);
+    }
+
+    @Override
+    public void testSucceeded(Description description) {
+        l.testSucceeded(description);
+    }
+
+    @Override
+    public PrintStream getWriter() {
+        return l.getWriter();
+    }
+
+    public void testClassFinishedDelimiter() {
+        l.testClassFinishedDelimiter();
+    }
+
+    public void testClassStartedDelimiter() {
+        l.testClassStartedDelimiter();
+    }
+
+    public void testStartedDelimiter() {
+        l.testStartedDelimiter();
+    }
+
+    public void testFinishedDelimiter() {
+        l.testFinishedDelimiter();
+    }
+
+}
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.test;
-
-import java.util.*;
-
-import org.junit.*;
-import org.junit.runners.*;
-import org.junit.runners.model.*;
-
-public class GraalLongUnitTest extends BlockJUnit4ClassRunner {
-
-    public GraalLongUnitTest(Class<?> klass) throws InitializationError {
-        super(klass);
-    }
-
-    @Override
-    protected List<FrameworkMethod> computeTestMethods() {
-        List<FrameworkMethod> methods = new ArrayList<>(5);
-        methods.addAll(getTestClass().getAnnotatedMethods(Test.class));
-        methods.addAll(getTestClass().getAnnotatedMethods(LongTest.class));
-        return methods;
-    }
-}
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Fri May 30 15:09:09 2014 +0200
@@ -22,18 +22,18 @@
  */
 package com.oracle.graal.test;
 
+import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 
 import org.junit.*;
-import org.junit.runner.*;
+import org.junit.internal.*;
 
 /**
  * Base class for Graal tests.
  * <p>
- * This contains common utility methods that are used in multiple test projects.
+ * This contains common utility methods and classes that are used in tests.
  */
-@RunWith(GraalLongUnitTest.class)
 public class GraalTest {
 
     protected Method getMethod(String methodName) {
@@ -71,4 +71,120 @@
             throw new RuntimeException("method not found: " + methodName + "" + Arrays.toString(parameterTypes));
         }
     }
+
+    /**
+     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
+     * Does a deep copy equality comparison if {@code expected} is an array.
+     */
+    protected void assertDeepEquals(Object expected, Object actual) {
+        assertDeepEquals(null, expected, actual);
+    }
+
+    /**
+     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
+     * Does a deep copy equality comparison if {@code expected} is an array.
+     *
+     * @param message the identifying message for the {@link AssertionError}
+     */
+    protected void assertDeepEquals(String message, Object expected, Object actual) {
+        assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta());
+    }
+
+    /**
+     * Compares two given values for equality, doing a recursive test if both values are arrays of
+     * the same type.
+     *
+     * @param message the identifying message for the {@link AssertionError}
+     * @param delta the maximum delta between two doubles or floats for which both numbers are still
+     *            considered equal.
+     */
+    protected void assertDeepEquals(String message, Object expected, Object actual, double delta) {
+        if (expected != null && actual != null) {
+            Class<?> expectedClass = expected.getClass();
+            Class<?> actualClass = actual.getClass();
+            if (expectedClass.isArray()) {
+                Assert.assertTrue(message, expected != null);
+                Assert.assertTrue(message, actual != null);
+                Assert.assertEquals(message, expectedClass, actual.getClass());
+                if (expected instanceof int[]) {
+                    Assert.assertArrayEquals(message, (int[]) expected, (int[]) actual);
+                } else if (expected instanceof byte[]) {
+                    Assert.assertArrayEquals(message, (byte[]) expected, (byte[]) actual);
+                } else if (expected instanceof char[]) {
+                    Assert.assertArrayEquals(message, (char[]) expected, (char[]) actual);
+                } else if (expected instanceof short[]) {
+                    Assert.assertArrayEquals(message, (short[]) expected, (short[]) actual);
+                } else if (expected instanceof float[]) {
+                    Assert.assertArrayEquals(message, (float[]) expected, (float[]) actual, (float) delta);
+                } else if (expected instanceof long[]) {
+                    Assert.assertArrayEquals(message, (long[]) expected, (long[]) actual);
+                } else if (expected instanceof double[]) {
+                    Assert.assertArrayEquals(message, (double[]) expected, (double[]) actual, delta);
+                } else if (expected instanceof boolean[]) {
+                    new ExactComparisonCriteria().arrayEquals(message, expected, actual);
+                } else if (expected instanceof Object[]) {
+                    new ComparisonCriteria() {
+                        @Override
+                        protected void assertElementsEqual(Object e, Object a) {
+                            assertDeepEquals(message, e, a, delta);
+                        }
+                    }.arrayEquals(message, expected, actual);
+                } else {
+                    Assert.fail((message == null ? "" : message) + "non-array value encountered: " + expected);
+                }
+            } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) {
+                Assert.assertEquals((double) expected, (double) actual, delta);
+            } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) {
+                Assert.assertEquals((float) expected, (float) actual, delta);
+            } else {
+                Assert.assertEquals(message, expected, actual);
+            }
+        } else {
+            Assert.assertEquals(message, expected, actual);
+        }
+    }
+
+    /**
+     * Gets the value used by {@link #assertDeepEquals(Object, Object)} and
+     * {@link #assertDeepEquals(String, Object, Object)} for the maximum delta between two doubles
+     * or floats for which both numbers are still considered equal.
+     */
+    protected double equalFloatsOrDoublesDelta() {
+        return 0.0D;
+    }
+
+    @SuppressWarnings("serial")
+    public static class MultiCauseAssertionError extends AssertionError {
+
+        private Throwable[] causes;
+
+        public MultiCauseAssertionError(String message, Throwable... causes) {
+            super(message);
+            this.causes = causes;
+        }
+
+        @Override
+        public void printStackTrace(PrintStream out) {
+            super.printStackTrace(out);
+            int num = 0;
+            for (Throwable cause : causes) {
+                if (cause != null) {
+                    out.print("cause " + (num++));
+                    cause.printStackTrace(out);
+                }
+            }
+        }
+
+        @Override
+        public void printStackTrace(PrintWriter out) {
+            super.printStackTrace(out);
+            int num = 0;
+            for (Throwable cause : causes) {
+                if (cause != null) {
+                    out.print("cause " + (num++) + ": ");
+                    cause.printStackTrace(out);
+                }
+            }
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTextListener.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import java.io.*;
+
+import org.junit.internal.*;
+import org.junit.runner.*;
+import org.junit.runner.notification.*;
+
+public class GraalTextListener implements GraalJUnitRunListener {
+
+    private final PrintStream fWriter;
+
+    public GraalTextListener(JUnitSystem system) {
+        this(system.out());
+    }
+
+    public GraalTextListener(PrintStream writer) {
+        fWriter = writer;
+    }
+
+    @Override
+    public PrintStream getWriter() {
+        return fWriter;
+    }
+
+    @Override
+    public void testRunStarted(Description description) {
+    }
+
+    @Override
+    public void testRunFinished(Result result) {
+    }
+
+    @Override
+    public void testAssumptionFailure(Failure failure) {
+    }
+
+    @Override
+    public void testClassStarted(Class<?> clazz) {
+    }
+
+    @Override
+    public void testClassFinished(Class<?> clazz) {
+    }
+
+    @Override
+    public void testStarted(Description description) {
+        getWriter().print('.');
+    }
+
+    @Override
+    public void testFinished(Description description) {
+    }
+
+    @Override
+    public void testFailed(Failure failure) {
+        getWriter().print('E');
+    }
+
+    @Override
+    public void testSucceeded(Description description) {
+    }
+
+    @Override
+    public void testIgnored(Description description) {
+        getWriter().print('I');
+    }
+
+    @Override
+    public void testClassFinishedDelimiter() {
+    }
+
+    @Override
+    public void testClassStartedDelimiter() {
+    }
+
+    @Override
+    public void testStartedDelimiter() {
+    }
+
+    @Override
+    public void testFinishedDelimiter() {
+    }
+
+    public static RunListener createRunListener(GraalJUnitRunListener l) {
+        return new TextListener(l.getWriter()) {
+            private Class<?> lastClass;
+            private boolean failed;
+
+            @Override
+            public final void testStarted(Description description) {
+                Class<?> currentClass = description.getTestClass();
+                if (currentClass != lastClass) {
+                    if (lastClass != null) {
+                        l.testClassFinished(lastClass);
+                        l.testClassFinishedDelimiter();
+                    }
+                    lastClass = currentClass;
+                    l.testClassStarted(currentClass);
+                    l.testClassStartedDelimiter();
+                }
+                failed = false;
+                l.testStarted(description);
+                l.testStartedDelimiter();
+            }
+
+            @Override
+            public final void testFailure(Failure failure) {
+                failed = true;
+                l.testFailed(failure);
+            }
+
+            @Override
+            public final void testFinished(Description description) {
+                // we have to do this because there is no callback for successful tests
+                if (!failed) {
+                    l.testSucceeded(description);
+                }
+                l.testFinished(description);
+                l.testFinishedDelimiter();
+            }
+
+            @Override
+            public void testIgnored(Description description) {
+                l.testStarted(description);
+                l.testStartedDelimiter();
+                l.testIgnored(description);
+                l.testFinished(description);
+                l.testFinishedDelimiter();
+            }
+
+            @Override
+            public void testRunStarted(Description description) {
+                l.testRunStarted(description);
+            }
+
+            @Override
+            public void testRunFinished(Result result) {
+                if (lastClass != null) {
+                    l.testClassFinished(lastClass);
+                }
+                l.testRunFinished(result);
+                super.testRunFinished(result);
+            }
+
+            @Override
+            public void testAssumptionFailure(Failure failure) {
+                l.testAssumptionFailure(failure);
+            }
+
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalVerboseTextListener.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import java.io.*;
+
+import org.junit.internal.*;
+import org.junit.runner.*;
+import org.junit.runner.notification.*;
+
+public class GraalVerboseTextListener extends GraalTextListener {
+
+    public GraalVerboseTextListener(JUnitSystem system) {
+        this(system.out());
+    }
+
+    public GraalVerboseTextListener(PrintStream writer) {
+        super(writer);
+    }
+
+    @Override
+    public void testClassStarted(Class<?> clazz) {
+        getWriter().print(clazz.getName() + " started");
+    }
+
+    @Override
+    public void testClassFinished(Class<?> clazz) {
+        getWriter().print(clazz.getName() + " finished");
+    }
+
+    @Override
+    public void testStarted(Description description) {
+        getWriter().print("  " + description.getMethodName() + ": ");
+    }
+
+    @Override
+    public void testIgnored(Description description) {
+        getWriter().print("Ignored");
+    }
+
+    @Override
+    public void testSucceeded(Description description) {
+        getWriter().print("Passed");
+    }
+
+    @Override
+    public void testFailed(Failure failure) {
+        getWriter().print("FAILED");
+    }
+
+    @Override
+    public void testClassFinishedDelimiter() {
+        getWriter().println();
+    }
+
+    @Override
+    public void testClassStartedDelimiter() {
+        getWriter().println();
+    }
+
+    @Override
+    public void testFinishedDelimiter() {
+        getWriter().println();
+    }
+
+}
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.test;
-
-import java.lang.annotation.*;
-
-/* copy of org.junit.Test */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface LongTest {
-
-    static final class None extends Throwable {
-
-        private static final long serialVersionUID = 1L;
-
-        private None() {
-        }
-    }
-
-    Class<? extends Throwable> expected() default None.class;
-
-    long timeout() default 0L;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/TimingDecorator.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.test;
+
+import org.junit.runner.*;
+
+/**
+ * Timing support for JUnit test runs.
+ */
+public class TimingDecorator extends GraalJUnitRunListenerDecorator {
+
+    private long startTime;
+    private long classStartTime;
+
+    public TimingDecorator(GraalJUnitRunListener l) {
+        super(l);
+    }
+
+    @Override
+    public void testClassStarted(Class<?> clazz) {
+        classStartTime = System.nanoTime();
+        super.testClassStarted(clazz);
+    }
+
+    @Override
+    public void testClassFinished(Class<?> clazz) {
+        long totalTime = System.nanoTime() - classStartTime;
+        super.testClassFinished(clazz);
+        getWriter().print(' ' + valueToString(totalTime));
+    }
+
+    @Override
+    public void testStarted(Description description) {
+        startTime = System.nanoTime();
+        super.testStarted(description);
+    }
+
+    @Override
+    public void testFinished(Description description) {
+        long totalTime = System.nanoTime() - startTime;
+        super.testFinished(description);
+        getWriter().print(" " + valueToString(totalTime));
+    }
+
+    private static String valueToString(long value) {
+        return String.format("%d.%d ms", value / 1000000, (value / 100000) % 10);
+    }
+
+}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Fri May 30 15:09:09 2014 +0200
@@ -42,8 +42,6 @@
 
     protected abstract int getNotifyIndex();
 
-    protected abstract int getCallTargetIndex();
-
     protected abstract int getFrameIndex();
 
     @SlowPath
@@ -86,16 +84,7 @@
 
     public abstract CallTarget getCallTarget();
 
-    public abstract CallTarget getTargetCallTarget();
-
-    public DirectCallNode getCallNode() {
-        Object receiver = stackFrame.getLocal(getNotifyIndex());
-        if (receiver instanceof DirectCallNode) {
-            return (DirectCallNode) receiver;
-        } else {
-            return null;
-        }
-    }
+    public abstract Node getCallNode();
 
     /**
      * This class represents a frame that is taken from the
@@ -112,7 +101,6 @@
             }
         }
         private static final int NOTIFY_INDEX = 0;
-        private static final int CALL_TARGET_INDEX = 1;
         private static final int FRAME_INDEX = 2;
 
         public CallNodeFrame(InspectedFrame stackFrame) {
@@ -125,11 +113,6 @@
         }
 
         @Override
-        protected int getCallTargetIndex() {
-            return CALL_TARGET_INDEX;
-        }
-
-        @Override
         protected int getFrameIndex() {
             return FRAME_INDEX;
         }
@@ -140,16 +123,19 @@
         }
 
         @Override
-        public CallTarget getTargetCallTarget() {
-            return (CallTarget) stackFrame.getLocal(getCallTargetIndex());
+        public Node getCallNode() {
+            Object receiver = stackFrame.getLocal(getNotifyIndex());
+            if (receiver instanceof DirectCallNode || receiver instanceof IndirectCallNode) {
+                return (Node) receiver;
+            }
+            return null;
         }
     }
 
     /**
-     * This class represents a frame that is taken from the
-     * {@link RootCallTarget#callProxy(VirtualFrame)} method.
+     * This class represents a frame that is taken from the {@link OptimizedCallTarget#callProxy}
+     * method.
      */
-    @SuppressWarnings("javadoc")
     public static final class CallTargetFrame extends HotSpotFrameInstance {
         public static final Method METHOD;
         static {
@@ -183,22 +169,17 @@
         }
 
         @Override
-        protected int getCallTargetIndex() {
-            return CALL_TARGET_INDEX;
-        }
-
-        @Override
         protected int getFrameIndex() {
             return FRAME_INDEX;
         }
 
         @Override
         public CallTarget getCallTarget() {
-            return (CallTarget) stackFrame.getLocal(getCallTargetIndex());
+            return (CallTarget) stackFrame.getLocal(CALL_TARGET_INDEX);
         }
 
         @Override
-        public CallTarget getTargetCallTarget() {
+        public Node getCallNode() {
             return null;
         }
     }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
 import java.util.*;
@@ -45,16 +46,15 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.printer.*;
 import com.oracle.graal.runtime.*;
 import com.oracle.graal.truffle.*;
 import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.nodes.*;
 
 /**
@@ -71,7 +71,7 @@
     private StackIntrospection stackIntrospection;
     private ArrayList<String> includes;
     private ArrayList<String> excludes;
-    private Map<OptimizedCallTarget, Future<?>> compilations = new IdentityHashMap<>();
+    private Map<OptimizedCallTarget, Future<?>> compilations = newIdentityMap();
     private final ThreadPoolExecutor compileQueue;
 
     private final ResolvedJavaMethod[] callNodeMethod;
@@ -118,7 +118,7 @@
         if (target instanceof OptimizedCallTarget) {
             return OptimizedDirectCallNode.create((OptimizedCallTarget) target);
         } else {
-            return new DefaultDirectCallNode(target);
+            throw new IllegalStateException(String.format("Unexpected call target class %s!", target.getClass()));
         }
     }
 
@@ -213,7 +213,7 @@
     }
 
     private static CompilationResultBuilderFactory getOptimizedCallTargetInstrumentationFactory(String arch, ResolvedJavaMethod method) {
-        for (OptimizedCallTargetInstrumentationFactory factory : ServiceLoader.loadInstalled(OptimizedCallTargetInstrumentationFactory.class)) {
+        for (OptimizedCallTargetInstrumentationFactory factory : Services.load(OptimizedCallTargetInstrumentationFactory.class)) {
             if (factory.getArchitecture().equals(arch)) {
                 factory.setInstrumentedMethod(method);
                 return factory;
@@ -284,7 +284,6 @@
         if (frames.hasNext()) {
             return new HotSpotFrameInstance.CallTargetFrame(frames.next(), true);
         } else {
-            System.out.println("no current frame found");
             return null;
         }
     }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java	Fri May 30 15:09:09 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.code.CompilationResult.Mark;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/AssumptionPartialEvaluationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/AssumptionPartialEvaluationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -46,7 +46,7 @@
         InstalledCode installedCode = assertPartialEvalEquals("constant42", rootNode);
         Assert.assertTrue(installedCode.isValid());
         try {
-            assertEquals(42, installedCode.executeVarargs(null, null, null));
+            assertDeepEquals(42, installedCode.executeVarargs(null, null, null));
         } catch (InvalidInstalledCodeException e) {
             Assert.fail("Code must not have been invalidated.");
         }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Fri May 30 15:09:09 2014 +0200
@@ -38,7 +38,7 @@
     public ExactMathTest() {
         if (!substitutionsInstalled) {
             Replacements replacements = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getReplacements();
-            replacements.registerSubstitutions(ExactMathSubstitutions.class);
+            replacements.registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
             substitutionsInstalled = true;
         }
     }
@@ -62,6 +62,20 @@
     }
 
     @Test
+    public void testMulHigh() {
+        test("mulHigh", 7, 15);
+        test("mulHigh", Integer.MAX_VALUE, 15);
+        test("mulHigh", Integer.MIN_VALUE, 15);
+    }
+
+    @Test
+    public void testMulHighUnsigned() {
+        test("mulHighUnsigned", 7, 15);
+        test("mulHighUnsigned", Integer.MAX_VALUE, 15);
+        test("mulHighUnsigned", Integer.MIN_VALUE, 15);
+    }
+
+    @Test
     public void testLongAdd() {
         test("longAdd", (long) Integer.MAX_VALUE, 2L);
         test("longAdd", Long.MAX_VALUE, 2L);
@@ -80,6 +94,20 @@
         test("longSub", Long.MIN_VALUE, 2L);
     }
 
+    @Test
+    public void testLongMulHigh() {
+        test("longMulHigh", 7L, 15L);
+        test("longMulHigh", Long.MAX_VALUE, 15L);
+        test("longMulHigh", Long.MIN_VALUE, 15L);
+    }
+
+    @Test
+    public void testLongMulHighUnsigned() {
+        test("longMulHighUnsigned", 7L, 15L);
+        test("longMulHighUnsigned", Long.MAX_VALUE, 15L);
+        test("longMulHighUnsigned", Long.MIN_VALUE, 15L);
+    }
+
     public static int add(int a, int b) {
         return ExactMath.addExact(a, b);
     }
@@ -92,6 +120,14 @@
         return ExactMath.subtractExact(a, b);
     }
 
+    public static int mulHigh(int a, int b) {
+        return ExactMath.multiplyHigh(a, b);
+    }
+
+    public static int mulHighUnsigned(int a, int b) {
+        return ExactMath.multiplyHighUnsigned(a, b);
+    }
+
     public static long longAdd(long a, long b) {
         return ExactMath.addExact(a, b);
     }
@@ -103,4 +139,12 @@
     public static long longSub(long a, long b) {
         return ExactMath.subtractExact(a, b);
     }
+
+    public static long longMulHigh(long a, long b) {
+        return ExactMath.multiplyHigh(a, b);
+    }
+
+    public static long longMulHighUnsigned(long a, long b) {
+        return ExactMath.multiplyHighUnsigned(a, b);
+    }
 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri May 30 15:09:09 2014 +0200
@@ -37,6 +37,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.printer.*;
 import com.oracle.graal.truffle.*;
@@ -137,7 +138,7 @@
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o2.lirLoop().depth - o1.lirLoop().depth;
+                return o2.lirLoop().getDepth() - o1.lirLoop().getDepth();
             }
         });
         return sortedLoops;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Fri May 30 15:09:09 2014 +0200
@@ -247,16 +247,16 @@
         logInliningDecision(result);
     }
 
-    private void performInlining(TruffleInliningResult result) {
-        if (inliningPerformed) {
+    private static void performInlining(TruffleInliningResult result) {
+        if (result.getCallTarget().inliningPerformed) {
             return;
         }
-        inliningPerformed = true;
+        result.getCallTarget().inliningPerformed = true;
         for (TruffleInliningProfile profile : result) {
             profile.getCallNode().inline();
             TruffleInliningResult recursiveResult = profile.getRecursiveResult();
             if (recursiveResult != null) {
-                recursiveResult.getCallTarget().performInlining(recursiveResult);
+                performInlining(recursiveResult);
             }
         }
     }
@@ -275,7 +275,7 @@
         if (profiledReturnTypeAssumption == null) {
             if (TruffleReturnTypeSpeculation.getValue()) {
                 CompilerDirectives.transferToInterpreter();
-                profiledReturnType = result.getClass();
+                profiledReturnType = (result == null ? null : result.getClass());
                 profiledReturnTypeAssumption = Truffle.getRuntime().createAssumption("Profiled Return Type");
             }
         } else if (profiledReturnType != null) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetInstrumentationFactory.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetInstrumentationFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -23,13 +23,14 @@
 package com.oracle.graal.truffle;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
  * A service for creating a specialized {@link CompilationResultBuilder} used to inject code into
  * {@link OptimizedCallTarget#call(Object[])}.
  */
-public interface OptimizedCallTargetInstrumentationFactory extends CompilationResultBuilderFactory {
+public interface OptimizedCallTargetInstrumentationFactory extends CompilationResultBuilderFactory, Service {
 
     /**
      * Gets the architecture supported by this factory.
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Fri May 30 15:09:09 2014 +0200
@@ -171,7 +171,7 @@
                     }
                     if (node instanceof DirectCallNode) {
                         DirectCallNode callNode = (DirectCallNode) node;
-                        if (callNode.isInliningForced()) {
+                        if (callNode.isInlined()) {
                             callNode.getCurrentRootNode().accept(this);
                         }
                     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri May 30 15:09:09 2014 +0200
@@ -22,10 +22,9 @@
  */
 package com.oracle.graal.truffle;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -35,7 +34,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
-import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.spi.*;
@@ -49,6 +47,8 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.common.inlining.info.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.truffle.nodes.asserts.*;
@@ -87,7 +87,7 @@
             constantReceivers = new HashSet<>();
         }
 
-        final StructuredGraph graph = truffleCache.createRootGraph();
+        final StructuredGraph graph = truffleCache.createRootGraph(callTarget.toString());
         assert graph != null : "no graph for root method";
 
         try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph.method())) {
@@ -108,7 +108,7 @@
             canonicalizer.apply(graph, baseContext);
 
             // Intrinsify methods.
-            new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
+            new IncrementalCanonicalizerPhase<>(canonicalizer, new ReplaceIntrinsicsPhase(providers.getReplacements())).apply(graph, baseContext);
 
             Debug.dump(graph, "Before inlining");
 
@@ -124,7 +124,16 @@
             if (TraceTruffleCompilationHistogram.getValue() && constantReceivers != null) {
                 DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes");
                 for (Constant c : constantReceivers) {
-                    histogram.add(providers.getMetaAccess().lookupJavaType(c).getName());
+                    String javaName = MetaUtil.toJavaName(providers.getMetaAccess().lookupJavaType(c), false);
+
+                    // The DSL uses nested classes with redundant names - only show the inner class
+                    int index = javaName.indexOf('$');
+                    if (index != -1) {
+                        javaName = javaName.substring(index + 1);
+                    }
+
+                    histogram.add(javaName);
+
                 }
                 new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram);
             }
@@ -193,7 +202,7 @@
                         }
 
                         StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                        if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().canBeInlined()) {
+                        if (inlineGraph == null && !methodCallTargetNode.targetMethod().isNative() && methodCallTargetNode.targetMethod().canBeInlined()) {
                             inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext, false);
                         }
 
@@ -201,11 +210,10 @@
                             try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) {
 
                                 int nodeCountBefore = graph.getNodeCount();
-                                Mark mark = graph.getMark();
                                 if (TraceTruffleExpansion.getValue()) {
                                     expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
                                 }
-                                List<Node> invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot();
+                                List<Node> canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot();
                                 Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
                                 if (TraceTruffleExpansion.getValue()) {
                                     expansionLogger.postExpand(inlined);
@@ -214,7 +222,8 @@
                                     int nodeCountAfter = graph.getNodeCount();
                                     Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
                                 }
-                                canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark);
+                                AbstractInlineInfo.getInlinedParameterUsages(canonicalizedNodes, inlineGraph, inlined);
+                                canonicalizer.applyIncremental(graph, phaseContext, canonicalizedNodes);
 
                                 changed = true;
                             }
@@ -288,7 +297,7 @@
 
             @Override
             public int compare(LoopEx o1, LoopEx o2) {
-                return o2.lirLoop().depth - o1.lirLoop().depth;
+                return o2.lirLoop().getDepth() - o1.lirLoop().getDepth();
             }
         });
         return sortedLoops;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.truffle;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.*;
@@ -47,7 +45,7 @@
         if (node instanceof LoadFieldNode) {
             LoadFieldNode loadFieldNode = (LoadFieldNode) node;
             if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) {
-                if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.getKind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
+                if (loadFieldNode.field().isFinal() || (loadFieldNode.getKind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
                                 loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
                     Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
                     assert verifyFieldValue(loadFieldNode.field(), constant);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Fri May 30 15:09:09 2014 +0200
@@ -33,7 +33,7 @@
     /**
      * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#callBoundary}.
      */
-    StructuredGraph createRootGraph();
+    StructuredGraph createRootGraph(String name);
 
     /**
      * Returns a cached graph for a method with given arguments.
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,8 @@
  */
 package com.oracle.graal.truffle;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -44,6 +43,7 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.truffle.phases.*;
@@ -81,8 +81,8 @@
         }
     }
 
-    public StructuredGraph createRootGraph() {
-        StructuredGraph graph = new StructuredGraph(callBoundaryMethod);
+    public StructuredGraph createRootGraph(String name) {
+        StructuredGraph graph = new StructuredGraph(name, callBoundaryMethod);
         new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRootGraph, TruffleCompilerImpl.Optimizations).apply(graph);
         return graph;
     }
@@ -251,7 +251,7 @@
         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()));
+            ResolvedJavaType exceptionType = Objects.requireNonNull(StampTool.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();
@@ -265,7 +265,7 @@
 
     private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) {
         boolean result = (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && methodCallTargetNode.targetMethod().canBeInlined() &&
-                        !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
+                        !methodCallTargetNode.targetMethod().isNative() && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
                         methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null &&
                         !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass);
         return result;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -36,6 +36,7 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.DebugMemUseTracker.Closeable;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
@@ -63,7 +64,7 @@
     private final RuntimeProvider runtime;
     private final TruffleCache truffleCache;
 
-    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class};
+    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class};
 
     public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
                     OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
@@ -102,6 +103,10 @@
     public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
     public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
 
+    public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse");
+    public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse");
+    public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse");
+
     public void compileMethodImpl(final OptimizedCallTarget compilable) {
         final StructuredGraph graph;
 
@@ -111,7 +116,7 @@
 
         long timeCompilationStarted = System.nanoTime();
         Assumptions assumptions = new Assumptions(true);
-        try (TimerCloseable a = PartialEvaluationTime.start()) {
+        try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) {
             graph = partialEvaluator.createGraph(compilable, assumptions);
         }
 
@@ -156,7 +161,7 @@
         }
 
         CompilationResult result = null;
-        try (TimerCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache())) {
+        try (TimerCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); Closeable c = CompilationMemUse.start()) {
             CodeCacheProvider codeCache = providers.getCodeCache();
             CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
             CompilationResult compilationResult = new CompilationResult(name);
@@ -183,7 +188,7 @@
         result.setAssumptions(newAssumptions);
 
         InstalledCode installedCode;
-        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); TimerCloseable a = CodeInstallationTime.start()) {
+        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); TimerCloseable a = CodeInstallationTime.start(); Closeable c = CodeInstallationMemUse.start()) {
             installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode);
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri May 30 15:09:09 2014 +0200
@@ -54,7 +54,7 @@
     @Option(help = "Enable automatic inlining of call targets")
     public static final OptionValue<Boolean> TruffleFunctionInlining = new OptionValue<>(true);
     @Option(help = "Maximum number of Graal IR nodes during partial evaluation")
-    public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(45000);
+    public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(200000);
     @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit")
     public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2250);
     @Option(help = "Skip inlining candidate if its tree size exceeds this limit")
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Fri May 30 15:09:09 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle;
 
 import java.io.*;
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -51,7 +50,7 @@
         int sourceMethodBci = callTarget.invoke().bci();
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
         ResolvedJavaType targetReceiverType = null;
-        if (!Modifier.isStatic(sourceMethod.getModifiers()) && callTarget.receiver().isConstant()) {
+        if (!sourceMethod.isStatic() && callTarget.receiver().isConstant()) {
             targetReceiverType = providers.getMetaAccess().lookupJavaType(callTarget.arguments().first().asConstant());
         }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Fri May 30 15:09:09 2014 +0200
@@ -117,7 +117,7 @@
     }
 
     private static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) {
-        return (double) Math.max(1, target.getCompilationProfile().getCallCount()) / Math.max(1, ocn.getCallCount());
+        return (double) Math.max(1, ocn.getCallCount()) / (double) Math.max(1, target.getCompilationProfile().getCallCount());
     }
 
     private final static class ProfileScoreComparator implements Comparator<TruffleInliningProfile> {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Fri May 30 15:09:09 2014 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.truffle.substitutions.*;
+import com.oracle.truffle.api.*;
 
 /**
  * Custom {@link Replacements} for Truffle compilation.
@@ -48,11 +49,11 @@
     }
 
     protected void registerTruffleSubstitutions() {
-        registerSubstitutions(CompilerAssertsSubstitutions.class);
-        registerSubstitutions(CompilerDirectivesSubstitutions.class);
-        registerSubstitutions(ExactMathSubstitutions.class);
-        registerSubstitutions(OptimizedAssumptionSubstitutions.class);
-        registerSubstitutions(OptimizedCallTargetSubstitutions.class);
+        registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class);
+        registerSubstitutions(CompilerDirectives.class, CompilerDirectivesSubstitutions.class);
+        registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
+        registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class);
+        registerSubstitutions(OptimizedCallTarget.class, OptimizedCallTargetSubstitutions.class);
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/LoadIndexedFinalNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/LoadIndexedFinalNode.java	Fri May 30 15:09:09 2014 +0200
@@ -59,7 +59,7 @@
     }
 
     private static Stamp createStamp(ValueNode array, Kind kind) {
-        ResolvedJavaType type = ObjectStamp.typeOrNull(array);
+        ResolvedJavaType type = StampTool.typeOrNull(array);
         if (kind == Kind.Object && type != null) {
             return StampFactory.declared(type.getComponentType());
         } else {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.truffle.nodes.arithmetic;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,12 +23,12 @@
 package com.oracle.graal.truffle.nodes.arithmetic;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.truffle.api.*;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * 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.truffle.nodes.arithmetic;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.truffle.api.*;
+
+@NodeInfo(shortName = "*H")
+public class IntegerMulHighNode extends IntegerArithmeticNode {
+
+    public IntegerMulHighNode(ValueNode x, ValueNode y) {
+        this(x.stamp().unrestricted(), x, y);
+    }
+
+    public IntegerMulHighNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
+    }
+
+    @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2 && inputs[0].getKind() == inputs[1].getKind();
+        switch (inputs[0].getKind()) {
+            case Int:
+                return Constant.forInt(ExactMath.multiplyHigh(inputs[0].asInt(), inputs[1].asInt()));
+            case Long:
+                return Constant.forLong(ExactMath.multiplyHigh(inputs[0].asLong(), inputs[1].asLong()));
+            default:
+                throw GraalInternalError.unimplemented();
+        }
+    }
+
+    @Override
+    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+        Value a = builder.operand(x());
+        Value b = builder.operand(y());
+        builder.setResult(this, gen.emitMulHigh(a, b));
+    }
+
+    @NodeIntrinsic
+    public static int multiplyHigh(int a, int b) {
+        return ExactMath.multiplyHigh(a, b);
+    }
+
+    @NodeIntrinsic
+    public static long multiplyHigh(long a, long b) {
+        return ExactMath.multiplyHigh(a, b);
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Fri May 30 15:09:09 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.truffle.nodes.arithmetic;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ * 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.truffle.nodes.arithmetic;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.truffle.api.*;
+
+@NodeInfo(shortName = "|*H|")
+public class UnsignedMulHighNode extends IntegerArithmeticNode {
+
+    public UnsignedMulHighNode(ValueNode x, ValueNode y) {
+        this(x.stamp().unrestricted(), x, y);
+    }
+
+    public UnsignedMulHighNode(Stamp stamp, ValueNode x, ValueNode y) {
+        super(stamp, x, y);
+    }
+
+    @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2 && inputs[0].getKind() == inputs[1].getKind();
+        switch (inputs[0].getKind()) {
+            case Int:
+                return Constant.forInt(ExactMath.multiplyHighUnsigned(inputs[0].asInt(), inputs[1].asInt()));
+            case Long:
+                return Constant.forLong(ExactMath.multiplyHighUnsigned(inputs[0].asLong(), inputs[1].asLong()));
+            default:
+                throw GraalInternalError.unimplemented();
+        }
+    }
+
+    @Override
+    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+        Value a = builder.operand(x());
+        Value b = builder.operand(y());
+        builder.setResult(this, gen.emitUMulHigh(a, b));
+    }
+
+    @NodeIntrinsic
+    public static int multiplyHighUnsigned(int a, int b) {
+        return ExactMath.multiplyHighUnsigned(a, b);
+    }
+
+    @NodeIntrinsic
+    public static long multiplyHighUnsigned(long a, long b) {
+        return ExactMath.multiplyHighUnsigned(a, b);
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Fri May 30 15:09:09 2014 +0200
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.truffle.nodes.frame;
 
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class ForceMaterializeNode extends FixedWithNextNode implements LIRGenLowerable {
+public class ForceMaterializeNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input private ValueNode object;
 
@@ -36,7 +35,7 @@
         this.object = object;
     }
 
-    public void generate(NodeLIRBuilder generator) {
+    public void generate(NodeLIRBuilderTool generator) {
         // nothing to do
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Fri May 30 15:09:09 2014 +0200
@@ -34,7 +34,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.truffle.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Fri May 30 15:09:09 2014 +0200
@@ -24,13 +24,13 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.truffle.nodes.*;
 import com.oracle.truffle.api.*;
 
@@ -57,7 +57,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (object.isConstant() && !object.isNullConstant() && offset.isConstant()) {
+        if (object.isConstant() && !object.isNullConstant() && offset.isConstant() && condition.isConstant() && condition.asConstant().asInt() == 1) {
             Constant constant = tool.getConstantReflection().readUnsafeConstant(accessKind, object.asConstant(), offset.asConstant().asLong());
             return ConstantNode.forConstant(constant, tool.getMetaAccess(), graph());
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri May 30 15:09:09 2014 +0200
@@ -29,8 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.truffle.nodes.asserts.*;
 import com.oracle.truffle.api.*;
 
@@ -63,7 +61,7 @@
             }
             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, stamp, valueAnchorNode));
+            PiNode piCast = graph().unique(new PiNode(objectArgument, stamp, valueAnchorNode));
             this.replaceAtUsages(piCast);
             return valueAnchorNode;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 
 /**
  * Compiler phase for intrinsifying the access to the Truffle virtual frame.
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -62,4 +62,24 @@
     public static long multiplyExact(long x, long y) {
         return IntegerMulExactNode.multiplyExact(x, y);
     }
+
+    @MethodSubstitution
+    public static int multiplyHigh(int x, int y) {
+        return IntegerMulHighNode.multiplyHigh(x, y);
+    }
+
+    @MethodSubstitution
+    public static int multiplyHighUnsigned(int x, int y) {
+        return UnsignedMulHighNode.multiplyHighUnsigned(x, y);
+    }
+
+    @MethodSubstitution
+    public static long multiplyHigh(long x, long y) {
+        return IntegerMulHighNode.multiplyHigh(x, y);
+    }
+
+    @MethodSubstitution
+    public static long multiplyHighUnsigned(long x, long y) {
+        return UnsignedMulHighNode.multiplyHighUnsigned(x, y);
+    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Fri May 30 15:09:09 2014 +0200
@@ -23,8 +23,8 @@
 package com.oracle.graal.truffle.substitutions;
 
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.truffle.*;
 import com.oracle.graal.truffle.nodes.frame.*;
 import com.oracle.truffle.api.frame.*;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Fri May 30 15:09:09 2014 +0200
@@ -45,7 +45,7 @@
         this.fieldValues = new NodeInputList<>(this, fieldValues);
     }
 
-    private VirtualObjectState(VirtualObjectNode object, List<ValueNode> fieldValues) {
+    public VirtualObjectState(VirtualObjectNode object, List<ValueNode> fieldValues) {
         super(object);
         assert object.entryCount() == fieldValues.size();
         this.fieldValues = new NodeInputList<>(this, fieldValues);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
@@ -32,7 +33,7 @@
 public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
 
     public EarlyReadEliminationPhase(CanonicalizerPhase canonicalizer) {
-        super(1, canonicalizer);
+        super(1, canonicalizer, true);
     }
 
     @Override
@@ -43,7 +44,8 @@
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule) {
-        return new ReadEliminationClosure(schedule);
+    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
+        assert schedule == null;
+        return new ReadEliminationClosure(cfg);
     }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
 
 import java.util.*;
 
@@ -41,20 +42,22 @@
 
 public abstract class EffectsClosure<BlockT extends EffectsBlockState<BlockT>> extends EffectsPhase.Closure<BlockT> {
 
+    private final ControlFlowGraph cfg;
     private final SchedulePhase schedule;
 
     protected final NodeMap<ValueNode> aliases;
     protected final BlockMap<GraphEffectList> blockEffects;
-    private final IdentityHashMap<Loop<Block>, GraphEffectList> loopMergeEffects = new IdentityHashMap<>();
-    private final IdentityHashMap<LoopBeginNode, BlockT> loopEntryStates = new IdentityHashMap<>();
+    private final Map<Loop<Block>, GraphEffectList> loopMergeEffects = newIdentityMap();
+    private final Map<LoopBeginNode, BlockT> loopEntryStates = newNodeIdentityMap();
 
     private boolean changed;
 
-    public EffectsClosure(SchedulePhase schedule) {
+    public EffectsClosure(SchedulePhase schedule, ControlFlowGraph cfg) {
         this.schedule = schedule;
-        this.aliases = schedule.getCFG().graph.createNodeMap();
-        this.blockEffects = new BlockMap<>(schedule.getCFG());
-        for (Block block : schedule.getCFG().getBlocks()) {
+        this.cfg = cfg;
+        this.aliases = cfg.graph.createNodeMap();
+        this.blockEffects = new BlockMap<>(cfg);
+        for (Block block : cfg.getBlocks()) {
             blockEffects.put(block, new GraphEffectList());
         }
     }
@@ -66,7 +69,7 @@
 
     @Override
     public void applyEffects() {
-        final StructuredGraph graph = schedule.getCFG().graph;
+        final StructuredGraph graph = cfg.graph;
         final ArrayList<Node> obsoleteNodes = new ArrayList<>(0);
         BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
 
@@ -113,7 +116,7 @@
                 return info.exitStates;
             }
         };
-        ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+        ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
         assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
     }
 
@@ -123,7 +126,8 @@
 
         GraphEffectList effects = blockEffects.get(block);
         FixedWithNextNode lastFixedNode = null;
-        for (Node node : schedule.getBlockToNodesMap().get(block)) {
+        Iterable<? extends Node> nodes = schedule != null ? schedule.getBlockToNodesMap().get(block) : block.getNodes();
+        for (Node node : nodes) {
             aliases.set(node, null);
             if (node instanceof LoopExitNode) {
                 LoopExitNode loopExit = (LoopExitNode) node;
@@ -155,7 +159,7 @@
     protected final List<BlockT> processLoop(Loop<Block> loop, BlockT initialState) {
         BlockT loopEntryState = initialState;
         BlockT lastMergedState = cloneState(initialState);
-        MergeProcessor mergeProcessor = createMergeProcessor(loop.header);
+        MergeProcessor mergeProcessor = createMergeProcessor(loop.getHeader());
         for (int iteration = 0; iteration < 10; iteration++) {
             LoopInfo<BlockT> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState));
 
@@ -164,7 +168,7 @@
             states.addAll(info.endStates);
             mergeProcessor.merge(states);
 
-            Debug.log("================== %s", loop.header);
+            Debug.log("================== %s", loop.getHeader());
             Debug.log("%s", mergeProcessor.newState);
             Debug.log("===== vs.");
             Debug.log("%s", lastMergedState);
@@ -172,19 +176,19 @@
             if (mergeProcessor.newState.equivalentTo(lastMergedState)) {
                 mergeProcessor.commitEnds(states);
 
-                blockEffects.get(loop.header).insertAll(mergeProcessor.mergeEffects, 0);
+                blockEffects.get(loop.getHeader()).insertAll(mergeProcessor.mergeEffects, 0);
                 loopMergeEffects.put(loop, mergeProcessor.afterMergeEffects);
 
-                assert info.exitStates.size() == loop.exits.size();
-                loopEntryStates.put((LoopBeginNode) loop.header.getBeginNode(), loopEntryState);
-                for (int i = 0; i < loop.exits.size(); i++) {
-                    assert info.exitStates.get(i) != null : "no loop exit state at " + loop.exits.get(i) + " / " + loop.header;
+                assert info.exitStates.size() == loop.getExits().size();
+                loopEntryStates.put((LoopBeginNode) loop.getHeader().getBeginNode(), loopEntryState);
+                for (int i = 0; i < loop.getExits().size(); i++) {
+                    assert info.exitStates.get(i) != null : "no loop exit state at " + loop.getExits().get(i) + " / " + loop.getHeader();
                 }
 
                 return info.exitStates;
             } else {
                 lastMergedState = mergeProcessor.newState;
-                for (Block block : loop.blocks) {
+                for (Block block : loop.getBlocks()) {
                     blockEffects.get(block).clear();
                 }
             }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -24,11 +24,14 @@
 
 import static com.oracle.graal.debug.Debug.*;
 
+import java.util.*;
+
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.util.*;
@@ -46,11 +49,17 @@
     }
 
     private final int maxIterations;
-    private final CanonicalizerPhase canonicalizer;
+    protected final CanonicalizerPhase canonicalizer;
+    private final boolean unscheduled;
 
-    public EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
+    protected EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
+        this(maxIterations, canonicalizer, false);
+    }
+
+    protected EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer, boolean unscheduled) {
         this.maxIterations = maxIterations;
         this.canonicalizer = canonicalizer;
+        this.unscheduled = unscheduled;
     }
 
     @Override
@@ -62,10 +71,19 @@
         boolean changed = false;
         for (int iteration = 0; iteration < maxIterations; iteration++) {
             try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) {
-                SchedulePhase schedule = new SchedulePhase();
-                schedule.apply(graph, false);
-                Closure<?> closure = createEffectsClosure(context, schedule);
-                ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+                SchedulePhase schedule;
+                ControlFlowGraph cfg;
+                if (unscheduled) {
+                    schedule = null;
+                    cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+                } else {
+                    schedule = new SchedulePhase();
+                    schedule.apply(graph, false);
+                    cfg = schedule.getCFG();
+                }
+
+                Closure<?> closure = createEffectsClosure(context, schedule, cfg);
+                ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
 
                 if (!closure.hasChanged()) {
                     break;
@@ -85,19 +103,24 @@
 
                 new DeadCodeEliminationPhase().apply(graph);
 
+                Set<Node> changedNodes = listener.getChangedNodes();
                 for (Node node : graph.getNodes()) {
                     if (node instanceof Simplifiable) {
-                        listener.getChangedNodes().add(node);
+                        changedNodes.add(node);
                     }
                 }
-                if (canonicalizer != null) {
-                    canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
-                }
+                postIteration(graph, context, changedNodes);
             }
             changed = true;
         }
         return changed;
     }
 
-    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, SchedulePhase schedule);
+    protected void postIteration(final StructuredGraph graph, final PhaseContextT context, Set<Node> changedNodes) {
+        if (canonicalizer != null) {
+            canonicalizer.applyIncremental(graph, context, changedNodes);
+        }
+    }
+
+    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, SchedulePhase schedule, ControlFlowGraph cfg);
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.debug.Debug.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
 
@@ -31,6 +31,8 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.cfs.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class IterativeInliningPhase extends AbstractInliningPhase {
@@ -70,9 +72,14 @@
 
                 new DeadCodeEliminationPhase().apply(graph);
 
-                if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+                boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+                if (reduceOrEliminate && OptCanonicalizer.getValue()) {
                     canonicalizer.apply(graph, context);
-                    new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+                    if (FlowSensitiveReduction.getValue()) {
+                        new IterativeFlowSensitiveReductionPhase(canonicalizer).apply(graph, context);
+                    } else {
+                        new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+                    }
                 }
                 if (!progress) {
                     break;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Fri May 30 15:09:09 2014 +0200
@@ -34,10 +34,10 @@
 
     static class ReadCacheEntry {
 
-        public final ResolvedJavaField identity;
+        public final LocationIdentity identity;
         public final ValueNode object;
 
-        public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) {
+        public ReadCacheEntry(LocationIdentity identity, ValueNode object) {
             this.identity = identity;
             this.object = object;
         }
@@ -95,7 +95,7 @@
         return super.equivalentTo(other);
     }
 
-    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value, PartialEscapeClosure<?> closure) {
+    public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
@@ -107,7 +107,7 @@
         readCache.put(new ReadCacheEntry(identity, cacheObject), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity, PartialEscapeClosure<?> closure) {
+    public ValueNode getReadCache(ValueNode object, LocationIdentity identity, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Fri May 30 15:09:09 2014 +0200
@@ -83,6 +83,17 @@
                 } else {
                     processIdentity(state, ANY_LOCATION);
                 }
+            } else if (node instanceof ArrayLengthNode) {
+                ArrayLengthNode length = (ArrayLengthNode) node;
+                ValueNode array = GraphUtil.unproxify(length.array());
+                ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, this);
+                if (cachedValue != null) {
+                    effects.replaceAtUsages(length, cachedValue);
+                    addScalarAlias(length, cachedValue);
+                    deleted = true;
+                } else {
+                    state.addReadCache(array, ARRAY_LENGTH_LOCATION, length, this);
+                }
             } else if (node instanceof MemoryCheckpoint.Single) {
                 METRIC_MEMORYCHECKPOINT.increment();
                 LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
@@ -183,7 +194,7 @@
             }
         }
 
-        private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<PEReadEliminationBlockState> states) {
+        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List<PEReadEliminationBlockState> states) {
             ValueNode[] values = new ValueNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, PEReadEliminationClosure.this);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.nodes.*;
@@ -31,7 +33,7 @@
 
 public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<T>> extends EffectsBlockState<T> {
 
-    protected final IdentityHashMap<VirtualObjectNode, ObjectState> objectStates = new IdentityHashMap<>();
+    protected final Map<VirtualObjectNode, ObjectState> objectStates = newIdentityMap();
 
     /**
      * Final subclass of PartialEscapeBlockState, for performance and to make everything behave
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri May 30 15:09:09 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -33,10 +35,8 @@
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.util.*;
@@ -56,7 +56,6 @@
 
     private final NodeBitMap usages;
     private final VirtualizerToolImpl tool;
-    private final Map<Invoke, Double> hints = new IdentityHashMap<>();
 
     /**
      * Final subclass of PartialEscapeClosure, for performance and to make everything behave nicely
@@ -80,15 +79,11 @@
     }
 
     public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Assumptions assumptions) {
-        super(schedule);
+        super(schedule, schedule.getCFG());
         this.usages = schedule.getCFG().graph.createNodeBitMap();
         this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, assumptions, this);
     }
 
-    public Map<Invoke, Double> getHints() {
-        return hints;
-    }
-
     /**
      * @return true if the node was deleted, false otherwise
      */
@@ -117,10 +112,6 @@
             for (ValueNode input : node.inputs().filter(ValueNode.class)) {
                 ObjectState obj = getObjectState(state, input);
                 if (obj != null) {
-                    if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
-                        Invoke invoke = ((MethodCallTargetNode) node).invoke();
-                        hints.put(invoke, 5d);
-                    }
                     VirtualUtil.trace("replacing input %s at %s: %s", input, node, obj);
                     replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED);
                 }
@@ -279,8 +270,8 @@
     protected class MergeProcessor extends EffectsClosure<BlockT>.MergeProcessor {
 
         private final HashMap<Object, ValuePhiNode> materializedPhis = new HashMap<>();
-        private final IdentityHashMap<ValueNode, ValuePhiNode[]> valuePhis = new IdentityHashMap<>();
-        private final IdentityHashMap<ValuePhiNode, VirtualObjectNode> valueObjectVirtuals = new IdentityHashMap<>();
+        private final Map<ValueNode, ValuePhiNode[]> valuePhis = newIdentityMap();
+        private final Map<ValuePhiNode, VirtualObjectNode> valueObjectVirtuals = newNodeIdentityMap();
 
         public MergeProcessor(Block mergeBlock) {
             super(mergeBlock);
@@ -580,15 +571,29 @@
                 } else {
                     // all inputs are virtual: check if they're compatible and without identity
                     boolean compatible = true;
+                    boolean hasIdentity = false;
                     ObjectState firstObj = objStates[0];
                     for (int i = 0; i < objStates.length; i++) {
                         ObjectState obj = objStates[i];
-                        boolean hasIdentity = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
-                        if (hasIdentity || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
+                        hasIdentity |= obj.virtual.hasIdentity();
+                        boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
+                        if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
                             compatible = false;
                             break;
                         }
                     }
+                    if (compatible && hasIdentity) {
+                        // we still need to check whether this value is referenced by any other phi
+                        outer: for (PhiNode otherPhi : merge.phis().filter(otherPhi -> otherPhi != phi)) {
+                            for (int i = 0; i < objStates.length; i++) {
+                                ObjectState otherPhiValueState = getObjectState(states.get(i), otherPhi.valueAt(i));
+                                if (Arrays.asList(objStates).contains(otherPhiValueState)) {
+                                    compatible = false;
+                                    break outer;
+                                }
+                            }
+                        }
+                    }
 
                     if (compatible) {
                         VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,18 +22,20 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.virtual.phases.ea.PartialEscapePhase.Options.*;
 
 import java.util.*;
+import java.util.function.*;
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 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.options.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
@@ -42,7 +44,6 @@
 public class PartialEscapePhase extends EffectsPhase<PhaseContext> {
 
     static class Options {
-
         //@formatter:off
         @Option(help = "")
         public static final OptionValue<Boolean> OptEarlyReadElimination = new OptionValue<>(true);
@@ -50,14 +51,28 @@
     }
 
     private final boolean readElimination;
+    private final BasePhase<PhaseContext> cleanupPhase;
 
     public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer) {
-        this(iterative, OptEarlyReadElimination.getValue(), canonicalizer);
+        this(iterative, OptEarlyReadElimination.getValue(), canonicalizer, null);
+    }
+
+    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer, BasePhase<PhaseContext> cleanupPhase) {
+        this(iterative, OptEarlyReadElimination.getValue(), canonicalizer, cleanupPhase);
     }
 
-    public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer) {
+    public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer, BasePhase<PhaseContext> cleanupPhase) {
         super(iterative ? EscapeAnalysisIterations.getValue() : 1, canonicalizer);
         this.readElimination = readElimination;
+        this.cleanupPhase = cleanupPhase;
+    }
+
+    @Override
+    protected void postIteration(StructuredGraph graph, PhaseContext context, Set<Node> changedNodes) {
+        super.postIteration(graph, context, changedNodes);
+        if (cleanupPhase != null) {
+            cleanupPhase.apply(graph, context);
+        }
     }
 
     @Override
@@ -70,7 +85,8 @@
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule) {
+    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
+        assert schedule != null;
         if (readElimination) {
             return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection(), context.getAssumptions());
         } else {
@@ -79,7 +95,7 @@
     }
 
     public static Map<Invoke, Double> getHints(StructuredGraph graph) {
-        NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
+        ToDoubleFunction<FixedNode> probabilities = new FixedNodeProbabilityCache();
         Map<Invoke, Double> hints = null;
         for (CommitAllocationNode commit : graph.getNodes().filter(CommitAllocationNode.class)) {
             double sum = 0;
@@ -87,14 +103,14 @@
             for (Node commitUsage : commit.usages()) {
                 for (Node usage : commitUsage.usages()) {
                     if (usage instanceof FixedNode) {
-                        sum += probabilities.get((FixedNode) usage);
+                        sum += probabilities.applyAsDouble((FixedNode) usage);
                     } else {
                         if (usage instanceof MethodCallTargetNode) {
-                            invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
+                            invokeSum += probabilities.applyAsDouble(((MethodCallTargetNode) usage).invoke().asNode());
                         }
                         for (Node secondLevelUage : usage.usages()) {
                             if (secondLevelUage instanceof FixedNode) {
-                                sum += probabilities.get(((FixedNode) secondLevelUage));
+                                sum += probabilities.applyAsDouble(((FixedNode) secondLevelUage));
                             }
                         }
                     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Fri May 30 15:09:09 2014 +0200
@@ -132,13 +132,7 @@
     }
 
     public void killReadCache(LocationIdentity identity) {
-        Iterator<Map.Entry<CacheEntry<?>, ValueNode>> iter = readCache.entrySet().iterator();
-        while (iter.hasNext()) {
-            Map.Entry<CacheEntry<?>, ValueNode> entry = iter.next();
-            if (entry.getKey().conflicts(identity)) {
-                iter.remove();
-            }
-        }
+        readCache.entrySet().removeIf(entry -> entry.getKey().conflicts(identity));
     }
 
     public Map<CacheEntry<?>, ValueNode> getReadCache() {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Fri May 30 15:09:09 2014 +0200
@@ -34,15 +34,14 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.ReadCacheEntry;
 
 public class ReadEliminationClosure extends EffectsClosure<ReadEliminationBlockState> {
 
-    public ReadEliminationClosure(SchedulePhase schedule) {
-        super(schedule);
+    public ReadEliminationClosure(ControlFlowGraph cfg) {
+        super(null, cfg);
     }
 
     @Override
@@ -53,104 +52,104 @@
     @Override
     protected boolean processNode(Node node, ReadEliminationBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
         boolean deleted = false;
-        if (node instanceof LoadFieldNode) {
-            LoadFieldNode load = (LoadFieldNode) node;
-            if (!load.isVolatile()) {
-                ValueNode object = GraphUtil.unproxify(load.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, load.field());
+        if (node instanceof AccessFieldNode) {
+            AccessFieldNode access = (AccessFieldNode) node;
+            if (access.isVolatile()) {
+                processIdentity(state, ANY_LOCATION);
+            } else {
+                ValueNode object = GraphUtil.unproxify(access.object());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, access.field());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
-                if (cachedValue != null) {
-                    effects.replaceAtUsages(load, cachedValue);
-                    addScalarAlias(load, cachedValue);
-                    deleted = true;
+                if (node instanceof LoadFieldNode) {
+                    if (cachedValue != null) {
+                        effects.replaceAtUsages(access, cachedValue);
+                        addScalarAlias(access, cachedValue);
+                        deleted = true;
+                    } else {
+                        state.addCacheEntry(identifier, access);
+                    }
                 } else {
-                    state.addCacheEntry(identifier, load);
+                    assert node instanceof StoreFieldNode;
+                    StoreFieldNode store = (StoreFieldNode) node;
+                    ValueNode value = getScalarAlias(store.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteFixedNode(store);
+                        deleted = true;
+                    }
+                    state.killReadCache(store.field());
+                    state.addCacheEntry(identifier, value);
+                }
+            }
+        } else if (node instanceof FixedAccessNode) {
+            if (node instanceof ReadNode) {
+                ReadNode read = (ReadNode) node;
+                if (read.location() instanceof ConstantLocationNode) {
+                    ValueNode object = GraphUtil.unproxify(read.object());
+                    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;
+                    } else {
+                        state.addCacheEntry(identifier, read);
+                    }
+                }
+            } else if (node instanceof WriteNode) {
+                WriteNode write = (WriteNode) node;
+                if (write.location() instanceof ConstantLocationNode) {
+                    ValueNode object = GraphUtil.unproxify(write.object());
+                    ReadCacheEntry identifier = new ReadCacheEntry(object, write.location());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
+
+                    ValueNode value = getScalarAlias(write.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteFixedNode(write);
+                        deleted = true;
+                    }
+                    processIdentity(state, write.location().getLocationIdentity());
+                    state.addCacheEntry(identifier, value);
+                } else {
+                    processIdentity(state, write.location().getLocationIdentity());
+                }
+            }
+        } else if (node instanceof UnsafeAccessNode) {
+            if (node instanceof UnsafeLoadNode) {
+                UnsafeLoadNode load = (UnsafeLoadNode) node;
+                if (load.offset().isConstant() && load.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
+                    ValueNode object = GraphUtil.unproxify(load.object());
+                    LoadCacheEntry identifier = new LoadCacheEntry(object, load.getLocationIdentity());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
+                    if (cachedValue != null) {
+                        effects.replaceAtUsages(load, cachedValue);
+                        addScalarAlias(load, cachedValue);
+                        deleted = true;
+                    } else {
+                        state.addCacheEntry(identifier, load);
+                    }
                 }
             } else {
-                processIdentity(state, ANY_LOCATION);
-            }
-        } else if (node instanceof StoreFieldNode) {
-            StoreFieldNode store = (StoreFieldNode) node;
-            if (!store.isVolatile()) {
-                ValueNode object = GraphUtil.unproxify(store.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, store.field());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
+                assert node instanceof UnsafeStoreNode;
+                UnsafeStoreNode write = (UnsafeStoreNode) node;
+                if (write.offset().isConstant() && write.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
+                    ValueNode object = GraphUtil.unproxify(write.object());
+                    LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
 
-                ValueNode value = getScalarAlias(store.value());
-                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                    effects.deleteFixedNode(store);
-                    deleted = true;
-                }
-                state.killReadCache(store.field());
-                state.addCacheEntry(identifier, value);
-            } else {
-                processIdentity(state, ANY_LOCATION);
-            }
-        } else if (node instanceof ReadNode) {
-            ReadNode read = (ReadNode) node;
-            if (read.location() instanceof ConstantLocationNode) {
-                ValueNode object = GraphUtil.unproxify(read.object());
-                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);
+                    ValueNode value = getScalarAlias(write.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteFixedNode(write);
+                        deleted = true;
                     }
-                    effects.replaceAtUsages(read, cachedValue);
-                    addScalarAlias(read, cachedValue);
-                    deleted = true;
+                    processIdentity(state, write.getLocationIdentity());
+                    state.addCacheEntry(identifier, value);
                 } else {
-                    state.addCacheEntry(identifier, read);
+                    processIdentity(state, write.getLocationIdentity());
                 }
             }
-        } else if (node instanceof UnsafeLoadNode) {
-            UnsafeLoadNode load = (UnsafeLoadNode) node;
-            if (load.offset().isConstant() && load.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
-                ValueNode object = GraphUtil.unproxify(load.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, load.getLocationIdentity());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
-                if (cachedValue != null) {
-                    effects.replaceAtUsages(load, cachedValue);
-                    addScalarAlias(load, cachedValue);
-                    deleted = true;
-                } else {
-                    state.addCacheEntry(identifier, load);
-                }
-            }
-        } else if (node instanceof WriteNode) {
-            WriteNode write = (WriteNode) node;
-            if (write.location() instanceof ConstantLocationNode) {
-                ValueNode object = GraphUtil.unproxify(write.object());
-                ReadCacheEntry identifier = new ReadCacheEntry(object, write.location());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
-
-                ValueNode value = getScalarAlias(write.value());
-                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                    effects.deleteFixedNode(write);
-                    deleted = true;
-                }
-                processIdentity(state, write.location().getLocationIdentity());
-                state.addCacheEntry(identifier, value);
-            } else {
-                processIdentity(state, write.location().getLocationIdentity());
-            }
-        } else if (node instanceof UnsafeStoreNode) {
-            UnsafeStoreNode write = (UnsafeStoreNode) node;
-            if (write.offset().isConstant() && write.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
-                ValueNode object = GraphUtil.unproxify(write.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
-
-                ValueNode value = getScalarAlias(write.value());
-                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                    effects.deleteFixedNode(write);
-                    deleted = true;
-                }
-                processIdentity(state, write.getLocationIdentity());
-                state.addCacheEntry(identifier, value);
-            } else {
-                processIdentity(state, write.getLocationIdentity());
-            }
         } else if (node instanceof MemoryCheckpoint.Single) {
             LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
             processIdentity(state, identity);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
 
 import java.util.*;
 
@@ -42,7 +43,7 @@
         // helper code that determines the paths that keep obsolete nodes alive:
 
         NodeFlood flood = graph.createNodeFlood();
-        IdentityHashMap<Node, Node> path = new IdentityHashMap<>();
+        Map<Node, Node> path = newIdentityMap();
         flood.add(graph.start());
         for (Node current : flood) {
             if (current instanceof AbstractEndNode) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import static com.oracle.graal.phases.GraalOptions.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/BarrieredAccess.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,937 @@
+/*
+ * 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.word;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.word.Word.Opcode;
+import com.oracle.graal.word.Word.Operation;
+
+/**
+ * Medium-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for
+ * {@link Pointer} and {@link ObjectAccess}, these methods access the memory without any null
+ * checks. However, these methods use read- or write barriers. When the VM uses compressed pointers,
+ * then readObject and writeObject methods access compressed pointers.
+ */
+public class BarrieredAccess {
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native byte readByte(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native char readChar(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native short readShort(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native int readInt(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native long readLong(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native float readFloat(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native double readDouble(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Word readWord(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ_BARRIERED)
+    public static native Object readObject(Object object, int offset);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, WordBase offset, Object val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeByte(Object object, int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeChar(Object object, int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeShort(Object object, int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeInt(Object object, int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeLong(Object object, int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeFloat(Object object, int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeDouble(Object object, int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeWord(Object object, int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     *
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE_BARRIERED)
+    public static native void writeObject(Object object, int offset, Object val);
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/ObjectAccess.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/ObjectAccess.java	Fri May 30 15:09:09 2014 +0200
@@ -30,7 +30,8 @@
 /**
  * Low-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for
  * {@link Pointer}, these methods access the raw memory without any null checks, read- or write
- * barriers.
+ * barriers. When the VM uses compressed pointers, then readObject and writeObject methods access
+ * compressed pointers.
  */
 public final class ObjectAccess {
 
@@ -40,13 +41,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native byte readByte(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -55,13 +56,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native char readChar(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -70,13 +71,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native short readShort(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -85,13 +86,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native int readInt(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -100,13 +101,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native long readLong(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -115,13 +116,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native float readFloat(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -130,13 +131,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native double readDouble(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -145,13 +146,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
@@ -160,112 +161,112 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Object readObject(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native byte readByte(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native char readChar(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native short readShort(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native int readInt(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native long readLong(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native float readFloat(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native double readDouble(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Object readObject(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
@@ -274,13 +275,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeByte(Object object, WordBase offset, byte val, LocationIdentity locationIdentity);
 
     /**
@@ -289,13 +290,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeChar(Object object, WordBase offset, char val, LocationIdentity locationIdentity);
 
     /**
@@ -304,13 +305,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeShort(Object object, WordBase offset, short val, LocationIdentity locationIdentity);
 
     /**
@@ -319,13 +320,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeInt(Object object, WordBase offset, int val, LocationIdentity locationIdentity);
 
     /**
@@ -334,13 +335,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeLong(Object object, WordBase offset, long val, LocationIdentity locationIdentity);
 
     /**
@@ -349,13 +350,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeFloat(Object object, WordBase offset, float val, LocationIdentity locationIdentity);
 
     /**
@@ -364,13 +365,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeDouble(Object object, WordBase offset, double val, LocationIdentity locationIdentity);
 
     /**
@@ -379,13 +380,13 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeWord(Object object, WordBase offset, WordBase val, LocationIdentity locationIdentity);
 
     /**
@@ -394,112 +395,112 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeObject(Object object, WordBase offset, Object val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeByte(Object object, int offset, byte val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeChar(Object object, int offset, char val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeShort(Object object, int offset, short val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeInt(Object object, int offset, int val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeLong(Object object, int offset, long val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeFloat(Object object, int offset, float val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeDouble(Object object, int offset, double val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeWord(Object object, int offset, WordBase val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeObject(Object object, int offset, Object val, LocationIdentity locationIdentity);
 
     /**
@@ -508,12 +509,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native byte readByte(Object object, WordBase offset);
 
     /**
@@ -522,12 +523,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native char readChar(Object object, WordBase offset);
 
     /**
@@ -536,12 +537,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native short readShort(Object object, WordBase offset);
 
     /**
@@ -550,12 +551,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native int readInt(Object object, WordBase offset);
 
     /**
@@ -564,12 +565,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native long readLong(Object object, WordBase offset);
 
     /**
@@ -578,12 +579,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native float readFloat(Object object, WordBase offset);
 
     /**
@@ -592,12 +593,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native double readDouble(Object object, WordBase offset);
 
     /**
@@ -606,12 +607,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Word readWord(Object object, WordBase offset);
 
     /**
@@ -620,102 +621,102 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Object readObject(Object object, WordBase offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native byte readByte(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native char readChar(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native short readShort(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native int readInt(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native long readLong(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native float readFloat(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native double readDouble(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Word readWord(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_OBJECT)
     public static native Object readObject(Object object, int offset);
 
     /**
@@ -724,12 +725,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeByte(Object object, WordBase offset, byte val);
 
     /**
@@ -738,12 +739,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeChar(Object object, WordBase offset, char val);
 
     /**
@@ -752,12 +753,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeShort(Object object, WordBase offset, short val);
 
     /**
@@ -766,12 +767,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeInt(Object object, WordBase offset, int val);
 
     /**
@@ -780,12 +781,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeLong(Object object, WordBase offset, long val);
 
     /**
@@ -794,12 +795,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeFloat(Object object, WordBase offset, float val);
 
     /**
@@ -808,12 +809,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeDouble(Object object, WordBase offset, double val);
 
     /**
@@ -822,12 +823,12 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeWord(Object object, WordBase offset, WordBase val);
 
     /**
@@ -836,101 +837,101 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeObject(Object object, WordBase offset, Object val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeByte(Object object, int offset, byte val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeChar(Object object, int offset, char val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeShort(Object object, int offset, short val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeInt(Object object, int offset, int val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeLong(Object object, int offset, long val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeFloat(Object object, int offset, float val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeDouble(Object object, int offset, double val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeWord(Object object, int offset, WordBase val);
 
     /**
      * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
-     * 
+     *
      * @param object the base object for the memory access
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_OBJECT)
     public static native void writeObject(Object object, int offset, Object val);
 }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Fri May 30 15:09:09 2014 +0200
@@ -26,13 +26,22 @@
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 
+/**
+ * Lowest-level memory access of native C memory. These methods access the raw memory without any
+ * null checks, read- or write barriers. Even when the VM uses compressed pointers, then readObject
+ * and writeObject methods access uncompressed pointers.
+ * <p>
+ * Do not use these methods to access Java objects, i.e., do not use
+ * {@code Word.fromObject(obj).readXxx()}. Instead, use {@link ObjectAccess} or
+ * {@link BarrieredAccess} to access Java objects.
+ */
 public interface Pointer extends Unsigned, PointerBase {
 
     /**
      * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
      * checks are performed. The caller must ensure that the Pointer contains a valid Java object
      * that can i.e., processed by the garbage collector.
-     * 
+     *
      * @return this Pointer cast to Object.
      */
     Object toObject();
@@ -44,7 +53,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -58,7 +67,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -72,7 +81,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -86,7 +95,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -100,7 +109,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -114,7 +123,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -128,7 +137,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -142,7 +151,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -156,7 +165,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -166,7 +175,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -176,7 +185,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -186,7 +195,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -196,7 +205,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -206,7 +215,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -216,7 +225,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -226,7 +235,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -236,7 +245,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -246,7 +255,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
@@ -260,7 +269,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -274,7 +283,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -288,7 +297,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -302,7 +311,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -316,7 +325,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -330,7 +339,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -344,7 +353,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -358,7 +367,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -372,7 +381,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -386,7 +395,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -396,7 +405,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -406,7 +415,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -416,7 +425,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -426,7 +435,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -436,7 +445,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -446,7 +455,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -456,7 +465,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -466,7 +475,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -476,7 +485,7 @@
     /**
      * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
      * are in bytes. The memory must be uninitialized or zero prior to this operation.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -486,7 +495,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
@@ -500,7 +509,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -513,7 +522,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -526,7 +535,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -539,7 +548,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -552,7 +561,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -565,7 +574,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -578,7 +587,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -591,7 +600,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -604,7 +613,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -618,7 +627,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param barrierType the type of the read barrier to be added
      * @return the result of the memory access
@@ -628,7 +637,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -637,7 +646,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -646,7 +655,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -655,7 +664,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -664,7 +673,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -673,7 +682,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -682,7 +691,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -691,7 +700,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -700,7 +709,7 @@
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
@@ -710,7 +719,7 @@
      * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if
      * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent
      * field).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param barrierType the type of the read barrier to be added
      * @return the result of the memory access
@@ -724,7 +733,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -737,7 +746,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -750,7 +759,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -763,7 +772,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -776,7 +785,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -789,7 +798,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -802,7 +811,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -815,7 +824,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -828,7 +837,7 @@
      * The offset is always treated as a {@link Signed} value. However, the static type is
      * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
      * knows that the highest-order bit of the unsigned value is never used).
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -837,7 +846,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -846,7 +855,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -855,7 +864,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -864,7 +873,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -873,7 +882,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -882,7 +891,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -891,7 +900,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -900,7 +909,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
@@ -909,7 +918,7 @@
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
-     * 
+     *
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.word;
 
-import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.lang.annotation.*;
 
@@ -60,9 +60,13 @@
          NODE_CLASS,
          COMPARISON,
          NOT,
-         READ,
+         READ_POINTER,
+         READ_OBJECT,
+         READ_BARRIERED,
          READ_HEAP,
-         WRITE,
+         WRITE_POINTER,
+         WRITE_OBJECT,
+         WRITE_BARRIERED,
          INITIALIZE,
          ZERO,
          FROM_UNSIGNED,
@@ -91,7 +95,7 @@
     /**
      * The constant 0, i.e., the word with no bits set. There is no difference between a signed and
      * unsigned zero.
-     * 
+     *
      * @return the constant 0.
      */
     @Operation(opcode = Opcode.ZERO)
@@ -102,7 +106,7 @@
     /**
      * Unsafe conversion from a Java long value to a Word. The parameter is treated as an unsigned
      * 64-bit value (in contrast to the semantics of a Java long).
-     * 
+     *
      * @param val a 64 bit unsigned value
      * @return the value cast to Word
      */
@@ -114,7 +118,7 @@
     /**
      * Unsafe conversion from a Java long value to a {@link PointerBase pointer}. The parameter is
      * treated as an unsigned 64-bit value (in contrast to the semantics of a Java long).
-     * 
+     *
      * @param val a 64 bit unsigned value
      * @return the value cast to PointerBase
      */
@@ -127,7 +131,7 @@
     /**
      * Unsafe conversion from a Java int value to a Word. The parameter is treated as an unsigned
      * 32-bit value (in contrast to the semantics of a Java int).
-     * 
+     *
      * @param val a 32 bit unsigned value
      * @return the value cast to Word
      */
@@ -139,7 +143,7 @@
     /**
      * Unsafe conversion from a Java long value to a Word. The parameter is treated as a signed
      * 64-bit value (unchanged semantics of a Java long).
-     * 
+     *
      * @param val a 64 bit signed value
      * @return the value cast to Word
      */
@@ -151,7 +155,7 @@
     /**
      * Unsafe conversion from a Java int value to a Word. The parameter is treated as a signed
      * 32-bit value (unchanged semantics of a Java int).
-     * 
+     *
      * @param val a 32 bit signed value
      * @return the value cast to Word
      */
@@ -634,155 +638,155 @@
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public byte readByte(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getByte(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public char readChar(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getChar(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public short readShort(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getShort(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public int readInt(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getInt(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public long readLong(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getLong(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public float readFloat(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getFloat(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public double readDouble(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getDouble(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public Word readWord(WordBase offset, LocationIdentity locationIdentity) {
         return box(unsafe.getAddress(add((Word) offset).unbox()));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public native Object readObject(WordBase offset, LocationIdentity locationIdentity);
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public byte readByte(int offset, LocationIdentity locationIdentity) {
         return readByte(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public char readChar(int offset, LocationIdentity locationIdentity) {
         return readChar(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public short readShort(int offset, LocationIdentity locationIdentity) {
         return readShort(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public int readInt(int offset, LocationIdentity locationIdentity) {
         return readInt(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public long readLong(int offset, LocationIdentity locationIdentity) {
         return readLong(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public float readFloat(int offset, LocationIdentity locationIdentity) {
         return readFloat(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public double readDouble(int offset, LocationIdentity locationIdentity) {
         return readDouble(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public Word readWord(int offset, LocationIdentity locationIdentity) {
         return readWord(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public Object readObject(int offset, LocationIdentity locationIdentity) {
         return readObject(signed(offset), locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity) {
         unsafe.putByte(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeChar(WordBase offset, char val, LocationIdentity locationIdentity) {
         unsafe.putChar(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeShort(WordBase offset, short val, LocationIdentity locationIdentity) {
         unsafe.putShort(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeInt(WordBase offset, int val, LocationIdentity locationIdentity) {
         unsafe.putInt(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeLong(WordBase offset, long val, LocationIdentity locationIdentity) {
         unsafe.putLong(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity) {
         unsafe.putFloat(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity) {
         unsafe.putDouble(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity) {
         unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox());
     }
@@ -794,53 +798,53 @@
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public native void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeByte(int offset, byte val, LocationIdentity locationIdentity) {
         writeByte(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeChar(int offset, char val, LocationIdentity locationIdentity) {
         writeChar(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeShort(int offset, short val, LocationIdentity locationIdentity) {
         writeShort(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeInt(int offset, int val, LocationIdentity locationIdentity) {
         writeInt(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeLong(int offset, long val, LocationIdentity locationIdentity) {
         writeLong(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeFloat(int offset, float val, LocationIdentity locationIdentity) {
         writeFloat(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeDouble(int offset, double val, LocationIdentity locationIdentity) {
         writeDouble(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeWord(int offset, WordBase val, LocationIdentity locationIdentity) {
         writeWord(signed(offset), val, locationIdentity);
     }
@@ -852,116 +856,116 @@
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeObject(int offset, Object val, LocationIdentity locationIdentity) {
         writeObject(signed(offset), val, locationIdentity);
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public byte readByte(WordBase offset) {
         return unsafe.getByte(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public char readChar(WordBase offset) {
         return unsafe.getChar(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public short readShort(WordBase offset) {
         return unsafe.getShort(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public int readInt(WordBase offset) {
         return unsafe.getInt(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public long readLong(WordBase offset) {
         return unsafe.getLong(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public float readFloat(WordBase offset) {
         return unsafe.getFloat(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public double readDouble(WordBase offset) {
         return unsafe.getDouble(add((Word) offset).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public Word readWord(WordBase offset) {
         return box(unsafe.getAddress(add((Word) offset).unbox()));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public native Object readObject(WordBase offset);
 
     @Operation(opcode = Opcode.READ_HEAP)
     public native Object readObject(WordBase offset, BarrierType barrierType);
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public byte readByte(int offset) {
         return readByte(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public char readChar(int offset) {
         return readChar(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public short readShort(int offset) {
         return readShort(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public int readInt(int offset) {
         return readInt(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public long readLong(int offset) {
         return readLong(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public float readFloat(int offset) {
         return readFloat(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public double readDouble(int offset) {
         return readDouble(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public Word readWord(int offset) {
         return readWord(signed(offset));
     }
 
     @Override
-    @Operation(opcode = Opcode.READ)
+    @Operation(opcode = Opcode.READ_POINTER)
     public Object readObject(int offset) {
         return readObject(signed(offset));
     }
@@ -972,107 +976,107 @@
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeByte(WordBase offset, byte val) {
         unsafe.putByte(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeChar(WordBase offset, char val) {
         unsafe.putChar(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeShort(WordBase offset, short val) {
         unsafe.putShort(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeInt(WordBase offset, int val) {
         unsafe.putInt(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeLong(WordBase offset, long val) {
         unsafe.putLong(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeFloat(WordBase offset, float val) {
         unsafe.putFloat(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeDouble(WordBase offset, double val) {
         unsafe.putDouble(add((Word) offset).unbox(), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeWord(WordBase offset, WordBase val) {
         unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox());
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public native void writeObject(WordBase offset, Object val);
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeByte(int offset, byte val) {
         writeByte(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeChar(int offset, char val) {
         writeChar(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeShort(int offset, short val) {
         writeShort(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeInt(int offset, int val) {
         writeInt(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeLong(int offset, long val) {
         writeLong(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeFloat(int offset, float val) {
         writeFloat(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeDouble(int offset, double val) {
         writeDouble(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeWord(int offset, WordBase val) {
         writeWord(signed(offset), val);
     }
 
     @Override
-    @Operation(opcode = Opcode.WRITE)
+    @Operation(opcode = Opcode.WRITE_POINTER)
     public void writeObject(int offset, Object val) {
         writeObject(signed(offset), val);
     }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Fri May 30 15:09:09 2014 +0200
@@ -27,12 +27,13 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that can be used inside a snippet without having the elements (including the
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Fri May 30 15:09:09 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.phases.*;
 
 /**
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -57,6 +57,7 @@
     protected final ResolvedJavaType wordBaseType;
     protected final ResolvedJavaType wordImplType;
     protected final ResolvedJavaType objectAccessType;
+    protected final ResolvedJavaType barrieredAccessType;
     protected final Kind wordKind;
 
     public WordTypeRewriterPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, Kind wordKind) {
@@ -66,6 +67,7 @@
         this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
         this.wordImplType = metaAccess.lookupJavaType(Word.class);
         this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class);
+        this.barrieredAccessType = metaAccess.lookupJavaType(BarrieredAccess.class);
     }
 
     @Override
@@ -144,7 +146,7 @@
      * own and not in the stamp, {@link #changeToWord} does not perform all necessary changes.
      */
     protected void rewriteAccessIndexed(StructuredGraph graph, AccessIndexedNode node) {
-        ResolvedJavaType arrayType = ObjectStamp.typeOrNull(node.array());
+        ResolvedJavaType arrayType = StampTool.typeOrNull(node.array());
         /*
          * There are cases where the array does not have a known type yet, i.e., the type is null.
          * In that case we assume it is not a word type.
@@ -170,23 +172,26 @@
      */
     protected void rewriteInvoke(StructuredGraph graph, MethodCallTargetNode callTargetNode) {
         ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
-        if (!wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass()) && !objectAccessType.equals(targetMethod.getDeclaringClass())) {
+        final boolean isWordBase = wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass());
+        final boolean isObjectAccess = objectAccessType.equals(targetMethod.getDeclaringClass());
+        final boolean isBarrieredAccess = barrieredAccessType.equals(targetMethod.getDeclaringClass());
+        if (!isWordBase && !isObjectAccess && !isBarrieredAccess) {
             /*
              * Not a method defined on WordBase or a subclass / subinterface, and not on
-             * ObjectAccess, so nothing to rewrite.
+             * ObjectAccess and not on BarrieredAccess, so nothing to rewrite.
              */
             return;
         }
 
+        Invoke invoke = callTargetNode.invoke();
         if (!callTargetNode.isStatic()) {
             assert callTargetNode.receiver().getKind() == wordKind : "changeToWord() missed the receiver";
-            targetMethod = wordImplType.resolveMethod(targetMethod);
+            targetMethod = wordImplType.resolveMethod(targetMethod, invoke.getContextType());
         }
         Operation operation = targetMethod.getAnnotation(Word.Operation.class);
         assert operation != null : targetMethod;
 
         NodeInputList<ValueNode> arguments = callTargetNode.arguments();
-        Invoke invoke = callTargetNode.invoke();
 
         switch (operation.opcode()) {
             case NODE_CLASS:
@@ -211,7 +216,9 @@
                 replace(invoke, graph.unique(new XorNode(StampFactory.forKind(wordKind), arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
                 break;
 
-            case READ: {
+            case READ_POINTER:
+            case READ_OBJECT:
+            case READ_BARRIERED: {
                 assert arguments.size() == 2 || arguments.size() == 3;
                 Kind readKind = asKind(callTargetNode.returnType());
                 LocationNode location;
@@ -220,7 +227,7 @@
                 } else {
                     location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
                 }
-                replace(invoke, readOp(graph, arguments.get(0), invoke, location, BarrierType.NONE, false));
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, operation.opcode()));
                 break;
             }
             case READ_HEAP: {
@@ -231,10 +238,12 @@
                 replace(invoke, readOp(graph, arguments.get(0), invoke, location, barrierType, true));
                 break;
             }
-            case WRITE:
+            case WRITE_POINTER:
+            case WRITE_OBJECT:
+            case WRITE_BARRIERED:
             case INITIALIZE: {
                 assert arguments.size() == 3 || arguments.size() == 4;
-                Kind writeKind = asKind(targetMethod.getSignature().getParameterType(Modifier.isStatic(targetMethod.getModifiers()) ? 2 : 1, targetMethod.getDeclaringClass()));
+                Kind writeKind = asKind(targetMethod.getSignature().getParameterType(targetMethod.isStatic() ? 2 : 1, targetMethod.getDeclaringClass()));
                 LocationNode location;
                 if (arguments.size() == 3) {
                     location = makeLocation(graph, arguments.get(1), writeKind, LocationIdentity.ANY_LOCATION);
@@ -375,6 +384,14 @@
         return IndexedLocationNode.create(locationIdentity, readKind, 0, fromSigned(graph, offset), graph, 1);
     }
 
+    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Opcode op) {
+        assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED;
+        final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED);
+
+        return readOp(graph, base, invoke, location, barrier, compressible);
+    }
+
     protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
         JavaReadNode read = graph.add(new JavaReadNode(base, location, barrierType, compressible));
         graph.addBeforeFixed(invoke.asNode(), read);
@@ -387,8 +404,11 @@
     }
 
     protected ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) {
-        assert op == Opcode.WRITE || op == Opcode.INITIALIZE;
-        JavaWriteNode write = graph.add(new JavaWriteNode(base, value, location, BarrierType.NONE, false, op == Opcode.INITIALIZE));
+        assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE;
+        final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
+        final boolean initialize = (op == Opcode.INITIALIZE);
+        JavaWriteNode write = graph.add(new JavaWriteNode(base, value, location, barrier, compressible, initialize));
         write.setStateAfter(invoke.stateAfter());
         graph.addBeforeFixed(invoke.asNode(), write);
         return write;
@@ -403,7 +423,7 @@
     }
 
     protected boolean isWord(ValueNode node) {
-        return isWord(ObjectStamp.typeOrNull(node));
+        return isWord(StampTool.typeOrNull(node));
     }
 
     protected boolean isWord(ResolvedJavaType type) {
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Fri May 30 15:09:09 2014 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.word.phases;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
@@ -110,12 +108,12 @@
         if (method.getAnnotation(NodeIntrinsic.class) == null) {
             Invoke invoke = (Invoke) callTarget.usages().first();
             NodeInputList<ValueNode> arguments = callTarget.arguments();
-            boolean isStatic = Modifier.isStatic(method.getModifiers());
+            boolean isStatic = method.isStatic();
             int argc = 0;
             if (!isStatic) {
                 ValueNode receiver = arguments.get(argc);
                 if (receiver == node && isWord(node)) {
-                    ResolvedJavaMethod resolvedMethod = wordAccess.wordImplType.resolveMethod(method);
+                    ResolvedJavaMethod resolvedMethod = wordAccess.wordImplType.resolveMethod(method, invoke.getContextType());
                     verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method));
                     Operation operation = resolvedMethod.getAnnotation(Word.Operation.class);
                     verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LazyClassLoadingTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.dsl.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.LazyClassLoadingTestFactory.TestNodeFactory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
+
+public class LazyClassLoadingTest {
+    @Test
+    public void test() {
+        String testClassName = getClass().getName();
+        String factoryClassName = testClassName + "Factory";
+        String nodeFactoryClassName = factoryClassName + "$TestNodeFactory";
+
+        Assert.assertFalse(isLoaded(factoryClassName + "$TestNode"));
+        Assert.assertFalse(isLoaded(nodeFactoryClassName));
+
+        NodeFactory<TestNode> factory = TestNodeFactory.getInstance();
+
+        Assert.assertTrue(isLoaded(nodeFactoryClassName));
+        Assert.assertFalse(isLoaded(nodeFactoryClassName + "$TestBaseNode"));
+
+        TestHelper.createRoot(factory);
+
+        Assert.assertTrue(isLoaded(nodeFactoryClassName + "$TestBaseNode"));
+        Assert.assertTrue(isLoaded(nodeFactoryClassName + "$TestUninitializedNode"));
+        Assert.assertFalse(isLoaded(nodeFactoryClassName + "$TestGenericNode"));
+    }
+
+    private boolean isLoaded(String className) {
+        ClassLoader classLoader = getClass().getClassLoader();
+        Method m;
+        try {
+            m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
+            m.setAccessible(true);
+            return m.invoke(classLoader, className) != null;
+        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @NodeChildren({@NodeChild("left"), @NodeChild("right")})
+    abstract static class TestNode extends ValueNode {
+        @Specialization(order = 1)
+        int add(int left, int right) {
+            return 42;
+        }
+
+        @Specialization(order = 2)
+        int add(boolean left, boolean right) {
+            return 21;
+        }
+
+        @Specialization(order = 4)
+        String add(boolean left, int right) {
+            return "(boolean,int)";
+        }
+    }
+}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java	Fri May 30 15:09:09 2014 +0200
@@ -36,10 +36,8 @@
  *
  * <p>
  * Child nodes are stored in the class of the parent node in fields that are marked with the
- * {@link Child} annotation. Before such a field is assigned, {@link Node#adoptChild} must be
- * called. This method automatically establishes a link from the child to the parent. The
- * {@link Node#getParent()} method allows access to this field. Every node also provides the ability
- * to iterate over its children using {@link Node#getChildren()}.
+ * {@link Child} annotation. The {@link Node#getParent()} method allows access to this field. Every
+ * node also provides the ability to iterate over its children using {@link Node#getChildren()}.
  * </p>
  *
  * <p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Inserting Extra Nodes into the AST Transparently</h3>
+ * 
+ * <p>
+ * The {@link Node} class provides a callback that is invoked whenever a node is adopted in an AST
+ * by insertion or replacement. Node classes can override the {@code onAdopt()} method to run extra
+ * functionality upon adoption.
+ * </p>
+ * 
+ * <p>
+ * This test demonstrates how node instances of a specific class can be automatically wrapped in
+ * extra nodes when they are inserted into the AST.
+ * </p>
+ */
+public class OnAdoptTest {
+
+    static class Root extends RootNode {
+
+        @Child private Base child1;
+        @Child private Base child2;
+
+        public Root(Base child1, Base child2) {
+            super(null);
+            this.child1 = child1;
+            this.child2 = child2;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return child1.executeInt(frame) + child2.executeInt(frame);
+        }
+
+    }
+
+    abstract static class Base extends Node {
+        public abstract int executeInt(VirtualFrame frame);
+    }
+
+    static class Wrapper extends Base {
+
+        @Child private Base wrappee;
+
+        public Wrapper(Base wrappee) {
+            this.wrappee = wrappee;
+        }
+
+        @Override
+        public int executeInt(VirtualFrame frame) {
+            return 1 + wrappee.executeInt(frame);
+        }
+
+    }
+
+    abstract static class GenBase extends Base {
+
+        private final int k;
+
+        public GenBase(int k) {
+            this.k = k;
+        }
+
+        @Override
+        public int executeInt(VirtualFrame frame) {
+            return k;
+        }
+
+    }
+
+    static class Gen extends GenBase {
+        public Gen(int k) {
+            super(k);
+        }
+    }
+
+    static class GenWrapped extends GenBase {
+
+        public GenWrapped(int k) {
+            super(k);
+        }
+
+        @Override
+        protected void onAdopt() {
+            Wrapper w = new Wrapper(this);
+            this.replace(w);
+        }
+
+    }
+
+    @Test
+    public void testOnInsert() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        Base b1 = new Gen(11);
+        Base b2 = new GenWrapped(11);
+        Root r = new Root(b1, b2);
+        CallTarget ct = runtime.createCallTarget(r);
+        Object result = ct.call();
+        Assert.assertEquals(23, result);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java	Fri May 30 15:09:09 2014 +0200
@@ -91,4 +91,54 @@
         }
         return r;
     }
+
+    public static int multiplyHigh(int x, int y) {
+        long r = (long) x * (long) y;
+        return (int) (r >> 32);
+    }
+
+    public static int multiplyHighUnsigned(int x, int y) {
+        long xl = x & 0xFFFFFFFFL;
+        long yl = y & 0xFFFFFFFFL;
+        long r = xl * yl;
+        return (int) (r >> 32);
+    }
+
+    public static long multiplyHigh(long x, long y) {
+        long x0, y0, z0;
+        long x1, y1, z1, z2, t;
+
+        x0 = x & 0xFFFFFFFFL;
+        x1 = x >> 32;
+
+        y0 = y & 0xFFFFFFFFL;
+        y1 = y >> 32;
+
+        z0 = x0 * y0;
+        t = x1 * y0 + (z0 >>> 32);
+        z1 = t & 0xFFFFFFFFL;
+        z2 = t >> 32;
+        z1 += x0 * y1;
+
+        return x1 * y1 + z2 + (z1 >> 32);
+    }
+
+    public static long multiplyHighUnsigned(long x, long y) {
+        long x0, y0, z0;
+        long x1, y1, z1, z2, t;
+
+        x0 = x & 0xFFFFFFFFL;
+        x1 = x >>> 32;
+
+        y0 = y & 0xFFFFFFFFL;
+        y1 = y >>> 32;
+
+        z0 = x0 * y0;
+        t = x1 * y0 + (z0 >>> 32);
+        z1 = t & 0xFFFFFFFFL;
+        z2 = t >>> 32;
+        z1 += x0 * y1;
+
+        return x1 * y1 + z2 + (z1 >>> 32);
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Fri May 30 15:09:09 2014 +0200
@@ -24,30 +24,150 @@
  */
 package com.oracle.truffle.api;
 
-import com.oracle.truffle.api.debug.*;
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.*;
 import com.oracle.truffle.api.source.*;
 
 /**
- * Information about the runtime context of a Truffle program.
+ * Access to information and basic services in the runtime context for a Truffle-implemented guest
+ * language.
  * <p>
- * <strong>Disclaimer:</strong> this interface is under development and will change.
+ * <strong>Disclaimer:</strong> this class is under development and will change.
  */
-public interface ExecutionContext {
+public abstract class ExecutionContext {
+
+    private final ProbeManager probeManager = new ProbeManager();
+    private final List<SourceListener> sourceListeners = new ArrayList<>();
+    private Visualizer visualizer = new DefaultVisualizer();
+
+    protected ExecutionContext() {
+    }
+
+    public void initialize() {
+        setSourceCallback(new SourceCallback() {
+
+            public void startLoading(Source source) {
+                for (SourceListener listener : sourceListeners) {
+                    listener.loadStarting(source);
+                }
+            }
+
+            public void endLoading(Source source) {
+                for (SourceListener listener : sourceListeners) {
+                    listener.loadEnding(source);
+                }
+            }
+        });
+    }
+
+    /**
+     * Registers a tool interested in being notified about the loading of {@link Source}s.
+     */
+    public final void addSourceListener(SourceListener listener) {
+        assert listener != null;
+        sourceListeners.add(listener);
+    }
+
+    /**
+     * Unregisters a tool interested in being notified about the loading of {@link Source}s.
+     */
+    public final void removeSourceListener(SourceListener removeListener) {
+        final List<SourceListener> listeners = new ArrayList<>(sourceListeners);
+        for (SourceListener listener : listeners) {
+            if (listener == removeListener) {
+                sourceListeners.remove(listener);
+            }
+        }
+    }
+
+    /**
+     * Registers a tool interested in being notified about the insertion of a newly created
+     * {@link Probe} into a Truffle AST.
+     */
+    public final void addProbeListener(ProbeListener listener) {
+        probeManager.addProbeListener(listener);
+    }
+
+    /**
+     * Unregisters a tool interested in being notified about the insertion of a newly created
+     * {@link Probe} into a Truffle AST.
+     */
+    public final void removeProbeListener(ProbeListener listener) {
+        probeManager.removeProbeListener(listener);
+    }
+
+    /**
+     * Return the (possibly newly created) {@link Probe} uniquely associated with a particular
+     * source code location. A newly created probe carries no tags.
+     *
+     * @return a probe uniquely associated with an extent of guest language source code.
+     */
+    public final Probe getProbe(SourceSection sourceSection) {
+        return probeManager.getProbe(sourceSection);
+    }
+
+    /**
+     * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty
+     * collection if no probes found.
+     */
+    public final Collection<Probe> findProbesTaggedAs(PhylumTag tag) {
+        return probeManager.findProbesTaggedAs(tag);
+    }
+
+    /**
+     * Returns all existing probes with first character on a specified line; empty collection if no
+     * probes found.
+     */
+    public final Collection<Probe> findProbesByLine(SourceLineLocation lineLocation) {
+        return probeManager.findProbesByLine(lineLocation);
+    }
+
+    /**
+     * Sets a trap that will make a callback at any AST location where a existing probe holds a
+     * specified tag; only one trap may be set at a time.
+     *
+     * @throws IllegalStateException if a trap is already set
+     */
+    public final void setPhylumTrap(PhylumTrap trap) throws IllegalStateException {
+        // TODO (mlvdv) consider allowing multiple traps (without inhibiting Truffle inlining)
+        probeManager.setPhylumTrap(trap);
+    }
+
+    /**
+     * Clears a trap that will halt execution; only one trap may be set at a time.
+     *
+     * @throws IllegalStateException if no trap is set.
+     */
+    public final void clearPhylumTrap() {
+        probeManager.clearPhylumTrap();
+    }
+
+    /**
+     * Access to information visualization services for the specific language.
+     */
+    public final Visualizer getVisualizer() {
+        return visualizer;
+    }
+
+    /**
+     * Assign guest language-specific visualization support for tools. This must be assigned outside
+     * the implementation context to avoid build circularities.
+     */
+    public final void setVisualizer(Visualizer visualizer) {
+        this.visualizer = visualizer;
+    }
 
     /**
      * Gets the name of the language, possibly with version number. in short enough form that it
      * might be used for an interactive prompt.
      */
-    String getLanguageShortName();
+    public abstract String getLanguageShortName();
 
     /**
-     * Gets access to source management services.
+     * Establishes source event reporting
      */
-    SourceManager getSourceManager();
-
-    /**
-     * Gets access to debugging services. Returns an inert instance if no services installed.
-     */
-    DebugContext getDebugContext();
+    protected abstract void setSourceCallback(SourceCallback sourceCallback);
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
 
 import java.io.*;
 
+import com.oracle.truffle.api.source.*;
+
 /**
  * Represents a unit (typically a file) of guest language source code.
  */
@@ -34,12 +36,21 @@
     /**
      * Returns the name of this resource holding a guest language program. An example would be the
      * name of a guest language source code file.
-     * 
+     *
      * @return the name of the guest language program
      */
     String getName();
 
     /**
+     * Returns a short version of the name of the resource holding a guest language program (as
+     * described in @getName). For example, this could be just the name of the file, rather than a
+     * full path.
+     *
+     * @return the short name of the guest language program
+     */
+    String getShortName();
+
+    /**
      * The normalized, canonical name of the file.
      */
     String getPath();
@@ -88,4 +99,61 @@
      */
     int getLineLength(int lineNumber);
 
+    /**
+     * Creates a representation of a contiguous region of text in the source. Computes the
+     * {@code (startLine, startColumn)} values by building a {@linkplain TextMap map} of lines in
+     * the source.
+     * <p>
+     * Checks the position arguments for consistency with the source.
+     * <p>
+     * The resulting representation defines hash/equality around equivalent location, presuming that
+     * {@link Source} representations are cannonical.
+     *
+     *
+     * @param identifier terse description of the region
+     * @param charIndex 0-based position of the first character in the section
+     * @param length the number of characters in the section
+     * @return newly created object representing the specified region
+     * @throws IllegalArgumentException if either of the arguments are outside the text of the
+     *             source
+     * @throws IllegalStateException if the source is one of the "null" instances
+     */
+    SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException, IllegalStateException;
+
+    /**
+     * Creates a representation of a contiguous region of text in the source. Computes the
+     * {@code charIndex} value by building a {@linkplain TextMap map} of lines in the source.
+     * <p>
+     * Checks the position arguments for consistency with the source.
+     * <p>
+     * The resulting representation defines hash/equality around equivalent location, presuming that
+     * {@link Source} representations are cannonical.
+     *
+     * @param identifier terse description of the region
+     * @param startLine 1-based line number of the first character in the section
+     * @param startColumn 1-based column number of the first character in the section
+     * @param length the number of characters in the section
+     * @return newly created object representing the specified region
+     * @throws IllegalArgumentException if arguments are outside the text of the source
+     * @throws IllegalStateException if the source is one of the "null" instances
+     */
+    SourceSection createSection(String identifier, int startLine, int startColumn, int length);
+
+    /**
+     * Creates a representation of a contiguous region of text in the source.
+     * <p>
+     * This method performs no checks on the validity of the arguments.
+     * <p>
+     * The resulting representation defines hash/equality around equivalent location, presuming that
+     * {@link Source} representations are cannonical.
+     *
+     * @param identifier terse description of the region
+     * @param startLine 1-based line number of the first character in the section
+     * @param startColumn 1-based column number of the first character in the section
+     * @param charIndex the 0-based index of the first character of the section
+     * @param length the number of characters in the section
+     * @return newly created object representing the specified region
+     */
+    SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length);
+
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Fri May 30 15:09:09 2014 +0200
@@ -25,47 +25,63 @@
 package com.oracle.truffle.api;
 
 /**
- * Description of contiguous text section within the source code of a guest language program.
+ * Description of contiguous section of text within a {@link Source} of program code.
+ *
+ * The starting location of the section can be described using two different coordinates:
+ * <ul>
+ * <li>{@code (startLine, startColumn)}: rows and columns are 1-based, so the first character in a
+ * source file is at position {@code (1,1)}. {@code Tab} characters are counted as occupying one
+ * column.</li>
+ * <li><b>character index</b>: 0-based offset of the character from the beginning of the source, so
+ * the first character in a file is at index {@code 0}.</li>
+ * </ul>
+ * The {@code Newline} that terminates each line counts as a single character for the purpose of a
+ * character index and when counting the length of text. The {@code (line,column)} coordinates of a
+ * {@code Newline} should never appear in a text section.
+ * <p>
+ * If the final character of source is not a {@code Newline}, the final characters of the text are
+ * still considered to be a line ("unterminated").
+ * <p>
+ *
+ * @see Source#createSection(String, int, int, int, int)
+ * @see Source#createSection(String, int, int, int)
+ * @see Source#createSection(String, int, int)
  */
 public interface SourceSection {
 
+    // TODO support alternate text representations/encodings
+
     /**
-     * Returns the object representing the source program that contains this section.
-     * 
+     * Representation of the source program that contains this section.
+     *
      * @return the source object
      */
     Source getSource();
 
     /**
-     * Returns 1-based line number of the first character in this source section (inclusive).
-     * 
+     * Returns 1-based line number of the first character in this section (inclusive).
+     *
      * @return the starting line number
      */
     int getStartLine();
 
     /**
-     * Returns the 1-based column number of the first character in this source section (inclusive).
-     * 
+     * Returns the 1-based column number of the first character in this section (inclusive).
+     *
      * @return the starting column number
      */
     int getStartColumn();
 
     /**
-     * Returns the 0-based index of the first character in this source section.
-     * <p>
-     * The complete text of the source that contains this section can be retrieved via
-     * {@link Source#getCode()}.
-     * 
+     * Returns the 0-based index of the first character in this section.
+     *
      * @return the starting character index
      */
     int getCharIndex();
 
     /**
-     * Returns the length of this source section in characters.
-     * <p>
-     * The complete text of the source that contains this section can be retrieved via
-     * {@link Source#getCode()}.
-     * 
+     * Returns the length of this section in characters.
+     *
      * @return the number of characters in the section
      */
     int getCharLength();
@@ -73,42 +89,54 @@
     /**
      * Returns the index of the text position immediately following the last character in the
      * section.
-     * 
+     *
      * @return the end position of the section
      */
     int getCharEndIndex();
 
     /**
-     * Returns the identifier of this source section that is used for printing the section.
-     * 
+     * Returns terse text describing this source section, typically used for printing the section.
+     *
      * @return the identifier of the section
      */
     String getIdentifier();
 
     /**
-     * Returns text of the code represented by this source section.
-     * 
+     * Returns text described by this section.
+     *
      * @return the code as a String object
      */
     String getCode();
 
     /**
+     * Returns a short description of the source section, using just the file name, rather than its
+     * full path.
+     *
+     * @return a short description of the source section
+     */
+    String getShortDescription();
+
+    /**
      * Singleton instance with no content.
      */
     SourceSection NULL = new NullSourceSection() {
 
+        @Override
         public Source getSource() {
             return null;
         }
 
+        @Override
         public int getStartLine() {
             return 0;
         }
 
+        @Override
         public int getStartColumn() {
             return 0;
         }
 
+        @Override
         public int getCharIndex() {
             return 0;
         }
@@ -118,18 +146,26 @@
             return 0;
         }
 
+        @Override
         public int getCharEndIndex() {
             return 0;
         }
 
+        @Override
         public String getIdentifier() {
             return null;
         }
 
+        @Override
         public String getCode() {
             return null;
         }
 
+        @Override
+        public String getShortDescription() {
+            return "short";
+        }
+
     };
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java	Fri May 30 15:09:09 2014 +0200
@@ -33,7 +33,14 @@
 
     private static final TruffleRuntime RUNTIME;
 
-    private static native TruffleRuntime initializeRuntime();
+    /**
+     * Creates a new {@link TruffleRuntime} instance if the runtime has a specialized
+     * implementation.
+     *
+     * @throws UnsatisfiedLinkError if the runtime does not have a specialized implementation of
+     *             {@link TruffleRuntime}
+     */
+    private static native TruffleRuntime createRuntime();
 
     public static TruffleRuntime getRuntime() {
         return RUNTIME;
@@ -42,7 +49,7 @@
     static {
         TruffleRuntime runtime;
         try {
-            runtime = initializeRuntime();
+            runtime = createRuntime();
         } catch (UnsatisfiedLinkError e) {
             runtime = new DefaultTruffleRuntime();
         }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Fri May 30 15:09:09 2014 +0200
@@ -106,7 +106,8 @@
 
     /**
      * Accesses the current stack, i.e., the contents of the {@link Frame}s and the associated
-     * {@link CallTarget}s.
+     * {@link CallTarget}s. Iteration starts at the caller frame, i.e., it does not include the
+     * current frame.
      *
      * @return a lazy collection of {@link FrameInstance}.
      */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ASTPrinter.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.debug;
-
-import java.io.*;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Language-agnostic access to AST-based debugging support.
- * <p>
- * <strong>WARNING:</strong> this interface is under development and will change substantially.
- */
-public interface ASTPrinter {
-
-    /**
-     * Prints a textual AST display, one line per node, with nesting.
-     * 
-     * @param p
-     * @param node the root node of the display.
-     * @param maxDepth the maximum number of levels to print below the root
-     * @param markNode a node to mark with a textual arrow prefix, if present.
-     */
-    void printTree(PrintWriter p, Node node, int maxDepth, Node markNode);
-
-    /**
-     * Creates a textual AST display, one line per node, with nesting.
-     * 
-     * @param node the root node of the display.
-     * @param maxDepth the maximum number of levels to print below the root
-     * @param markNode a node to mark with a textual arrow prefix, if present.
-     */
-    String printTreeToString(Node node, int maxDepth, Node markNode);
-
-    /**
-     * Creates a textual AST display, one line per node, with nesting.
-     * 
-     * @param node the root node of the display.
-     * @param maxDepth the maximum number of levels to print below the root
-     */
-    String printTreeToString(Node node, int maxDepth);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugContext.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.debug;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.instrument.*;
-
-/**
- * Access to the suite of facilities available when debugging is enabled.
- */
-public interface DebugContext {
-
-    /**
-     * Access to the Truffle execution context being debugged.
-     */
-    ExecutionContext getContext();
-
-    /**
-     * Access to the appropriate implementation of AST node instrumentation.
-     */
-    NodeInstrumenter getNodeInstrumenter();
-
-    /**
-     * Access to the management of breakpoints, notifications, etc.
-     */
-    DebugManager getDebugManager();
-
-    /**
-     * Gets a printer for Truffle ASTs helpful for debugging guest language implementations.
-     */
-    ASTPrinter getASTPrinter();
-
-    /**
-     * Converts a value in the guest language to a display string.
-     */
-    String displayValue(Object value);
-
-    /**
-     * Converts a slot identifier in the guest language to a display string.
-     */
-    String displayIdentifier(FrameSlot slot);
-
-    /**
-     * Invokes appropriate debugging action when Truffle execution halts.
-     */
-    void executionHalted(Node node, MaterializedFrame frame);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugManager.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.debug;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.instrument.*;
-import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
-
-/**
- * Language-agnostic access to AST-based debugging support.
- * <p>
- * <strong>Disclaimer:</strong> this interface is under development and will change.
- */
-public interface DebugManager {
-
-    /**
-     * Informs the {@link DebugManager} that the Guest Language runtime is starting to load a
-     * source. Care should be taken to ensure that under any circumstance there is always a
-     * following call to {@link #notifyFinishedLoading(Source)} with the same argument.
-     */
-    void notifyStartLoading(Source source);
-
-    /**
-     * Informs the {@link DebugManager} that the Guest Language runtime has finished loading a
-     * source. Care should be taken to ensure that under any circumstance there is always a prior
-     * call to {@link #notifyStartLoading(Source)} with the same argument.
-     */
-    void notifyFinishedLoading(Source source);
-
-    /**
-     * Return a reference to the (canonical) instrumentation site associated with a particular
-     * source code location; this site will have effect on any Truffle/AST implementation
-     * corresponding to the source location, even if the AST is copied multiple times.
-     */
-    ProbeChain getProbeChain(SourceSection sourceSection);
-
-    /**
-     * Informs the {@link DebugManager} that Truffle execution has halted; execution will resume
-     * when this method returns.
-     * 
-     * @param astNode a guest language AST node that represents the current execution site, assumed
-     *            not to be any kind of {@link InstrumentationNode},
-     * @param frame execution frame at the site where execution suspended
-     */
-    void haltedAt(Node astNode, MaterializedFrame frame);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DefaultDebugManager.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.debug;
-
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
-import com.oracle.truffle.api.source.*;
-
-/**
- * A minimal, language-agnostic implementation that tracks loaded sources, and keeps maps describing
- * what locations in the source have instrumentation available. This implementation will do nothing
- * unless there are calls to it during AST construction, notably {@link #notifyStartLoading(Source)}
- * and {@link #notifyFinishedLoading(Source)} <em>and</em> there are at least some AST nodes being
- * instrumented.
- */
-public class DefaultDebugManager implements DebugManager {
-
-    private final Set<Source> loadedSources = new HashSet<>();
-
-    private Source beingLoaded = null;
-
-    /**
-     * Map: SourceSection ==&gt; probe chain associated with that source section in an AST.
-     */
-    private final Map<SourceSection, ProbeChain> srcToProbeChain = new HashMap<>();
-
-    /**
-     * Map: Source lines ==&gt; probe chains associated with source sections starting on the line.
-     */
-    private final Map<SourceLineLocation, Set<ProbeChain>> lineToProbeChains = new HashMap<>();
-
-    private final ExecutionContext context;
-
-    public DefaultDebugManager(ExecutionContext context) {
-        this.context = context;
-    }
-
-    /**
-     * Gets the {@linkplain ProbeChain probe} associated with a particular {@link SourceSection
-     * source location}, creating a new one if needed. There should only be one probe associated
-     * with each {@linkplain SourceSection source location}.
-     */
-    public ProbeChain getProbeChain(SourceSection sourceSection) {
-        assert sourceSection != null;
-        assert sourceSection.getSource().equals(beingLoaded);
-
-        ProbeChain probeChain = srcToProbeChain.get(sourceSection);
-
-        if (probeChain != null) {
-            return probeChain;
-        }
-        probeChain = new ProbeChain(context, sourceSection, null);
-
-        // Register new ProbeChain by unique SourceSection
-        srcToProbeChain.put(sourceSection, probeChain);
-
-        // Register new ProbeChain by source line, there may be more than one
-        // Create line location for map key
-        final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
-
-        Set<ProbeChain> probeChains = lineToProbeChains.get(lineLocation);
-        if (probeChains == null) {
-            probeChains = new HashSet<>();
-            lineToProbeChains.put(lineLocation, probeChains);
-        }
-        probeChains.add(probeChain);
-
-        return probeChain;
-    }
-
-    public void notifyStartLoading(Source source) {
-        assert beingLoaded == null;
-        beingLoaded = source;
-    }
-
-    public void notifyFinishedLoading(Source source) {
-        assert source == beingLoaded;
-        loadedSources.add(source);
-        beingLoaded = null;
-    }
-
-    public void haltedAt(Node astNode, MaterializedFrame frame) {
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/KillException.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.debug;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Controls breaking out of an execution context, such as a shell or eval.
- */
-public final class KillException extends ControlFlowException {
-
-    private static final long serialVersionUID = 3163641880088766957L;
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/QuitException.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.debug;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Controls breaking out of all executions and ending Truffle execution.
- */
-public final class QuitException extends ControlFlowException {
-
-    private static final long serialVersionUID = -4301115629772778413L;
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Fri May 30 15:09:09 2014 +0200
@@ -40,9 +40,7 @@
 
     boolean isVirtualFrame();
 
-    DirectCallNode getCallNode();
+    Node getCallNode();
 
     CallTarget getCallTarget();
-
-    CallTarget getTargetCallTarget();
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Fri May 30 15:09:09 2014 +0200
@@ -35,11 +35,13 @@
 public class DefaultCallTarget implements RootCallTarget {
 
     private final RootNode rootNode;
+    private final DefaultTruffleRuntime defaultTruffleRuntime;
 
-    public DefaultCallTarget(RootNode function) {
+    public DefaultCallTarget(RootNode function, DefaultTruffleRuntime defaultTruffleRuntime) {
         this.rootNode = function;
         this.rootNode.adoptChildren();
         this.rootNode.setCallTarget(this);
+        this.defaultTruffleRuntime = defaultTruffleRuntime;
     }
 
     @Override
@@ -53,7 +55,29 @@
 
     @Override
     public Object call(Object... args) {
-        VirtualFrame frame = new DefaultVirtualFrame(getRootNode().getFrameDescriptor(), args);
-        return getRootNode().execute(frame);
+        final VirtualFrame frame = new DefaultVirtualFrame(getRootNode().getFrameDescriptor(), args);
+        FrameInstance oldCurrentFrame = defaultTruffleRuntime.setCurrentFrame(new FrameInstance() {
+
+            public Frame getFrame(FrameAccess access, boolean slowPath) {
+                return frame;
+            }
+
+            public boolean isVirtualFrame() {
+                return false;
+            }
+
+            public Node getCallNode() {
+                return null;
+            }
+
+            public CallTarget getCallTarget() {
+                return DefaultCallTarget.this;
+            }
+        });
+        try {
+            return getRootNode().execute(frame);
+        } finally {
+            defaultTruffleRuntime.setCurrentFrame(oldCurrentFrame);
+        }
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java	Fri May 30 15:09:09 2014 +0200
@@ -34,14 +34,40 @@
 public final class DefaultDirectCallNode extends DirectCallNode {
 
     private boolean inliningForced;
+    private final DefaultTruffleRuntime defaultTruffleRuntime;
 
-    public DefaultDirectCallNode(CallTarget target) {
+    public DefaultDirectCallNode(CallTarget target, DefaultTruffleRuntime defaultTruffleRuntime) {
         super(target);
+        this.defaultTruffleRuntime = defaultTruffleRuntime;
     }
 
     @Override
-    public Object call(VirtualFrame frame, Object[] arguments) {
-        return getCurrentCallTarget().call(arguments);
+    public Object call(final VirtualFrame frame, Object[] arguments) {
+        final CallTarget currentCallTarget = defaultTruffleRuntime.getCurrentFrame().getCallTarget();
+        FrameInstance frameInstance = new FrameInstance() {
+
+            public Frame getFrame(FrameAccess access, boolean slowPath) {
+                return frame;
+            }
+
+            public boolean isVirtualFrame() {
+                return false;
+            }
+
+            public Node getCallNode() {
+                return DefaultDirectCallNode.this;
+            }
+
+            public CallTarget getCallTarget() {
+                return currentCallTarget;
+            }
+        };
+        defaultTruffleRuntime.pushFrame(frameInstance);
+        try {
+            return getCurrentCallTarget().call(arguments);
+        } finally {
+            defaultTruffleRuntime.popFrame();
+        }
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.impl;
-
-import com.oracle.truffle.api.*;
-
-/**
- * Represents a contiguous text section within the source code of a guest language program.
- */
-public class DefaultSourceSection implements SourceSection {
-
-    private final Source source;
-    private final String identifier;
-    private final int startLine;
-    private final int startColumn;
-    private final int charIndex;
-    private final int charLength;
-
-    /**
-     * Creates a new object representing a contiguous text section within the source code of a guest
-     * language program's text.
-     * <p>
-     * The starting location of the section is specified using two different coordinate:
-     * <ul>
-     * <li><b>(row, column)</b>: rows and columns are 1-based, so the first character in a source
-     * file is at position {@code (1,1)}.</li>
-     * <li><b>character index</b>: 0-based offset of the character from the beginning of the source,
-     * so the first character in a file is at index {@code 0}.</li>
-     * </ul>
-     * The <b>newline</b> that terminates each line counts as a single character for the purpose of
-     * a character index. The (row,column) coordinates of a newline character should never appear in
-     * a text section.
-     * <p>
-     * 
-     * @param source object representing the complete source program that contains this section
-     * @param identifier an identifier used when printing the section
-     * @param startLine the 1-based number of the start line of the section
-     * @param startColumn the 1-based number of the start column of the section
-     * @param charIndex the 0-based index of the first character of the section
-     * @param charLength the length of the section in number of characters
-     */
-    public DefaultSourceSection(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) {
-        this.source = source;
-        this.identifier = identifier;
-        this.startLine = startLine;
-        this.startColumn = startColumn;
-        this.charIndex = charIndex;
-        this.charLength = charLength;
-    }
-
-    public final Source getSource() {
-        return source;
-    }
-
-    public final int getStartLine() {
-        return startLine;
-    }
-
-    public final int getStartColumn() {
-        return startColumn;
-    }
-
-    public final int getCharIndex() {
-        return charIndex;
-    }
-
-    public final int getCharLength() {
-        return charLength;
-    }
-
-    public final int getCharEndIndex() {
-        return charIndex + charLength;
-    }
-
-    public final String getIdentifier() {
-        return identifier;
-    }
-
-    public final String getCode() {
-        return getSource().getCode().substring(charIndex, charIndex + charLength);
-    }
-
-    @Override
-    public String toString() {
-        return String.format("%s:%d", source.getName(), startLine);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + charIndex;
-        result = prime * result + charLength;
-        result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
-        result = prime * result + ((source == null) ? 0 : source.hashCode());
-        result = prime * result + startColumn;
-        result = prime * result + startLine;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof DefaultSourceSection)) {
-            return false;
-        }
-        DefaultSourceSection other = (DefaultSourceSection) obj;
-        if (charIndex != other.charIndex) {
-            return false;
-        }
-        if (charLength != other.charLength) {
-            return false;
-        }
-        if (identifier == null) {
-            if (other.identifier != null) {
-                return false;
-            }
-        } else if (!identifier.equals(other.identifier)) {
-            return false;
-        }
-        if (source == null) {
-            if (other.source != null) {
-                return false;
-            }
-        } else if (!source.equals(other.source)) {
-            return false;
-        }
-        if (startColumn != other.startColumn) {
-            return false;
-        }
-        if (startLine != other.startLine) {
-            return false;
-        }
-        return true;
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Fri May 30 15:09:09 2014 +0200
@@ -24,6 +24,8 @@
  */
 package com.oracle.truffle.api.impl;
 
+import java.util.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
@@ -37,6 +39,9 @@
  */
 public final class DefaultTruffleRuntime implements TruffleRuntime {
 
+    private ThreadLocal<LinkedList<FrameInstance>> stackTraces = new ThreadLocal<>();
+    private ThreadLocal<FrameInstance> currentFrames = new ThreadLocal<>();
+
     public DefaultTruffleRuntime() {
         if (Truffle.getRuntime() != null) {
             throw new IllegalArgumentException("Cannot instantiate DefaultTruffleRuntime. Use Truffle.getRuntime() instead.");
@@ -50,11 +55,11 @@
 
     @Override
     public RootCallTarget createCallTarget(RootNode rootNode) {
-        return new DefaultCallTarget(rootNode);
+        return new DefaultCallTarget(rootNode, this);
     }
 
     public DirectCallNode createDirectCallNode(CallTarget target) {
-        return new DefaultDirectCallNode(target);
+        return new DefaultDirectCallNode(target, this);
     }
 
     public IndirectCallNode createIndirectCallNode() {
@@ -86,13 +91,34 @@
         return new DefaultAssumption(name);
     }
 
+    private LinkedList<FrameInstance> getThreadLocalStackTrace() {
+        LinkedList<FrameInstance> result = stackTraces.get();
+        if (result == null) {
+            result = new LinkedList<>();
+            stackTraces.set(result);
+        }
+        return result;
+    }
+
+    public FrameInstance setCurrentFrame(FrameInstance newValue) {
+        FrameInstance oldValue = currentFrames.get();
+        currentFrames.set(newValue);
+        return oldValue;
+    }
+
+    public void pushFrame(FrameInstance frame) {
+        getThreadLocalStackTrace().addFirst(frame);
+    }
+
+    public void popFrame() {
+        getThreadLocalStackTrace().removeFirst();
+    }
+
     public Iterable<FrameInstance> getStackTrace() {
-        // TODO(lstadler) implement this using ThreadLocal
-        return null;
+        return getThreadLocalStackTrace();
     }
 
     public FrameInstance getCurrentFrame() {
-        // TODO(lstadler) implement this using ThreadLocal
-        return null;
+        return currentFrames.get();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTNodeProber.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Implementation of a policy for <em>instrumenting</em> inserting a {@link Probe} at a Truffle AST
+ * node.
+ * <p>
+ * Note that this interface is guest language agnostic, but current extensions are
+ * language-specific. This will be revisited.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development. Really!
+ */
+public interface ASTNodeProber {
+
+    /**
+     * Optionally applies <em>instrumentation</em> at a Truffle AST node, depending on guest
+     * language characteristics and use-case policy.
+     * <ul>
+     * <li>if no instrumentation is to be applied, returns the AST node unmodified;</li>
+     * <li>if an AST node is to be instrumented, then returns a newly created {@link Wrapper} that
+     * <em>decorates</em> the AST node and notifies an associated {@link Probe} of all
+     * {@link ExecutionEvents} at the wrapped AST node.</li>
+     * <li>if the argument is itself a {@link Wrapper}, i.e. if the AST node at this site has
+     * already been wrapped, then the wrapper is returned (with the possible addition of a
+     * {@linkplain PhylumTag tag}).</li>
+     * </ul>
+     *
+     * @param astNode an AST node to which instrumentation might be applied
+     * @param tag an optional category directing how the node, if instrumented, should be perceived
+     *            by tool users
+     * @param args additional arguments for instrumentation specific to a particular guest language
+     * @return if no instrumentation should be applied or if the node is a {@link Wrapper} then the
+     *         unmodified node; otherwise a newly created {@link Wrapper} (whose child
+     *         {@code astNode}) with an associated {@link Probe} .
+     */
+
+    Node probeAs(Node astNode, PhylumTag tag, Object... args);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import java.io.*;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Language-agnostic access to AST-based debugging support.
+ * <p>
+ * <strong>WARNING:</strong> this interface is under development and will change substantially.
+ */
+public interface ASTPrinter {
+
+    /**
+     * Prints a textual AST display, one line per node, with nesting.
+     * 
+     * @param p
+     * @param node the root node of the display.
+     * @param maxDepth the maximum number of levels to print below the root
+     * @param markNode a node to mark with a textual arrow prefix, if present.
+     */
+    void printTree(PrintWriter p, Node node, int maxDepth, Node markNode);
+
+    /**
+     * Creates a textual AST display, one line per node, with nesting.
+     * 
+     * @param node the root node of the display.
+     * @param maxDepth the maximum number of levels to print below the root
+     * @param markNode a node to mark with a textual arrow prefix, if present.
+     */
+    String printTreeToString(Node node, int maxDepth, Node markNode);
+
+    /**
+     * Creates a textual AST display, one line per node, with nesting.
+     * 
+     * @param node the root node of the display.
+     * @param maxDepth the maximum number of levels to print below the root
+     */
+    String printTreeToString(Node node, int maxDepth);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTProber.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,66 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Implementation of a policy for <em>instrumenting</em> Truffle ASTs with {@link Probe}s at
+ * particular nodes by inserting node {@link Wrapper}s.
+ * <p>
+ * Multiple "node probers" can be added, typically by different tools; the "combined prober" will
+ * apply all of them.
+ * <p>
+ * The current implementation is provisional and does not completely encapsulate everything that
+ * needs to be implemented for a particular use-case or set of use-cases. In particular, the AST
+ * building code for each language implementation must have hand-coded applications of node probing
+ * methods at the desired locations. For the duration of this approach, this must be done for any
+ * node that any client tool wishes to probe.
+ * <p>
+ * A better approach will be to implement such policies as a Truffle {@link NodeVisitor}, but that
+ * is not possible at this time.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ */
+public interface ASTProber {
+
+    // TODO (mlvdv) This is a provisional interface, more of a marker really
+    // TODO (mlvdv) AST probing should eventually be done with visitors.
+
+    /**
+     * Adds a specification for adding probes at particular kinds of nodes.
+     *
+     * @param nodeProber
+     * @throws IllegalArgumentException if the prober is not applicable to the guest language
+     *             implementation.
+     */
+    void addNodeProber(ASTNodeProber nodeProber) throws IllegalArgumentException;
+
+    /**
+     * Gets a (possibly guest language-specific) {@link ASTNodeProber} that will apply all that have
+     * been added; {@code null} if no instrumentation in AST.
+     */
+    ASTNodeProber getCombinedNodeProber();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ExecutionEvents.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,179 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Normal events during program execution at Truffle AST nodes that are reported via a {@link Probe}
+ * associated with the node, and made available to the probe's attached {@link Instrument}s.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ */
+public interface ExecutionEvents {
+
+    /**
+     * Notifies that an AST node's execute method has just been entered. Callers should assure that
+     * a matching call to {@link #leave(Node, VirtualFrame, Object)} always follows.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame being passed to the execute method
+     */
+    void enter(Node astNode, VirtualFrame frame);
+
+    /**
+     * Notifies that an AST Node's void-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     */
+    void leave(Node astNode, VirtualFrame frame);
+
+    /**
+     * Notifies that an AST Node's boolean-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, boolean result);
+
+    /**
+     * Notifies that an AST Node's byte-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, byte result);
+
+    /**
+     * Notifies that an AST Node's short-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, short result);
+
+    /**
+     * Notifies that an AST Node's integer-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, int result);
+
+    /**
+     * Notifies that an AST Node's long-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, long result);
+
+    /**
+     * Notifies that an AST Node's float-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, float result);
+
+    /**
+     * Notifies that an AST Node's double-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, double result);
+
+    /**
+     * Notifies that an AST Node's char-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, char result);
+
+    /**
+     * Notifies that an AST Node's object-valued execute method is about to exit.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param result The result of the call to the execute method.
+     */
+    void leave(Node astNode, VirtualFrame frame, Object result);
+
+    /**
+     * Notifies that an AST Node's execute method is about to leave under exceptional conditions,
+     * returning no value.
+     * <p>
+     * Callers should assure (via {@code try/finally}) that a matching call to this method always
+     * follows a call to {@link #enter(Node, VirtualFrame)}.
+     *
+     * @param astNode The AST node on which the execute method is being called
+     * @param frame The frame that was passed to the execute method
+     * @param e the exception associated with the unusual return
+     */
+    void leaveExceptional(Node astNode, VirtualFrame frame, Exception e);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,136 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A receiver of Truffle AST runtime {@link ExecutionEvents}, propagated from the {@link Probe} to
+ * which the instrument is attached, for the benefit of associated <em>tools</em>.
+ * <p>
+ * Guidelines for implementing {@link Instrument}s, with particular attention to minimize runtime
+ * performance overhead:
+ * <ol>
+ * <li>Extend this abstract class and override only the {@linkplain ExecutionEvents event handling
+ * methods} for which intervention is needed.</li>
+ * <li>Instruments are Truffle {@link Node}s and should be coded as much as possible in the desired
+ * <em>Truffle style</em>, documented more thoroughly elsewhere.</li>
+ * <li>Maintain as little state as possible.</li>
+ * <li>If state is necessary, make object fields {@code final} if at all possible.</li>
+ * <li>If non-final object-valued state is necessary, annotate it as {@link CompilationFinal} and
+ * call {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.</li>
+ * <li>Never store a {@link Frame} value in a field.</li>
+ * <li>Minimize computation in standard execution paths.</li>
+ * <li>If runtime calls must be made back to a tool, construct the instrument with a callback stored
+ * in a {@code final} field.</li>
+ * <li>Tool methods called by the instrument should be annotated as {@link SlowPath} to prevent them
+ * from being inlined into fast execution paths.</li>
+ * <li>If computation in the execution path is needed, and if performance is important, then the
+ * computation is best expressed as a guest language AST and evaluated using standard Truffle
+ * mechanisms so that standard Truffle optimizations can be applied.</li>
+ * </ol>
+ * <p>
+ * Guidelines for attachment to a {@link Probe}:
+ * <ol>
+ * <li>An Instrument instance must only attached to a single {@link Probe}, each of which is
+ * associated uniquely with a specific syntactic unit of a guest language program, and thus
+ * (initially) to a specific {@linkplain Node Truffle AST node}.</li>
+ * <li>When the AST containing such a node is copied at runtime, the {@link Probe} will be shared by
+ * every copy, and so the Instrument will receive events corresponding to the intended syntactic
+ * unit of code, independent of which AST copy is being executed.</li>
+ * </ol>
+ * <p>
+ * Guidelines for handling {@link ExecutionEvents}:
+ * <ol>
+ * <li>Separate event methods are defined for each kind of possible return: object-valued,
+ * primitive-valued, void-valued, and exceptional.</li>
+ * <li>Override "leave*" primitive methods if the language implementation returns primitives and the
+ * instrument should avoid boxing them.</li>
+ * <li>On the other hand, if boxing all primitives for instrumentation is desired, it is only
+ * necessary to override the object-valued return methods, since the default implementation of each
+ * primitive-valued return method is to box the value and forward it to the object-valued return
+ * method.</li>
+ * </ol>
+ *
+ * <p>
+ * <strong>Disclaimer:</strong> experimental; under development.
+ *
+ * @see Probe
+ * @see ASTNodeProber
+ */
+public abstract class Instrument extends InstrumentationNode {
+
+    protected Instrument() {
+    }
+
+    public void enter(Node astNode, VirtualFrame frame) {
+    }
+
+    public void leave(Node astNode, VirtualFrame frame) {
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, boolean result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, byte result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, short result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, int result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, long result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, char result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, float result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, double result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, Object result) {
+    }
+
+    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/KillException.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Controls breaking out of an execution context, such as a shell or eval.
+ */
+public final class KillException extends ControlFlowException {
+
+    private static final long serialVersionUID = 3163641880088766957L;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/PhylumTag.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+/**
+ * Program element "tags", presumed to be singletons (best implemented as enums) that define
+ * user-visible behavior for debugging and other simple tools. These categories (<em>phyla</em>)
+ * should correspond to program structures that are meaningful to a guest language programmer.
+ * <p>
+ * An untagged Truffle node should be understood as an artifact of the guest language implementation
+ * and should not be visible to the user of a guest language programming tool. Nodes may also have
+ * more than one tag, for example a variable assignment that is also a statement. Finally, the
+ * assignment of tags to nodes could depending on the use-case of whatever tool is using them.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ *
+ * @see Probe
+ * @see Wrapper
+ * @see StandardTag
+ */
+public interface PhylumTag {
+
+    /**
+     * Human-friendly name of guest language program elements belonging to the category, e.g.
+     * "statement".
+     */
+    String name();
+
+    /**
+     * Criteria and example uses for the tag.
+     */
+    String getDescription();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/PhylumTagged.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+/**
+ * Information about a guest language program element in a Truffle that can be marked as belonging
+ * to 0 or more {@linkplain PhylumTag tags}.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ *
+ * @see Probe
+ * @see Wrapper
+ */
+public interface PhylumTagged {
+
+    /**
+     * Is this node tagged as belonging to a particular category of language constructs?
+     */
+    boolean isTaggedAs(PhylumTag tag);
+
+    /**
+     * In which categories has this node been tagged (<em>empty set</em> if none).
+     */
+    Iterable<PhylumTag> getPhylumTags();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/PhylumTrap.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A trap that can be set to interrupt execution at probed nodes carrying a specific tag.
+ */
+public abstract class PhylumTrap {
+
+    private final PhylumTag tag;
+
+    protected PhylumTrap(PhylumTag tag) {
+        this.tag = tag;
+    }
+
+    public final PhylumTag getTag() {
+        return tag;
+    }
+
+    /**
+     * Callback that will be received whenever execution enters a node with the specified tag.
+     */
+    public abstract void phylumTrappedAt(Node node, MaterializedFrame frame);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * A collector of {@link ExecutionEvents} at a specific site (node) in a Truffle AST (generated by a
+ * {@link Wrapper} inserted into the AST) for the purpose of <em>instrumentation</em>. For probes
+ * associated with programmer-facing tools, there should be no more than one probe associated with a
+ * particular piece of source code syntax (i.e. a {@link SourceSection}).
+ * <p>
+ * Any {@linkplain PhylumTag tags} associated with a particular piece of source code syntax are
+ * managed by the probe.
+ * <p>
+ * When ASTs are copied, it is presumed that the probe for a site is shared by all AST nodes
+ * representing that site.
+ * <p>
+ * A probe holds zero or more {@link Instrument}s, which can be added and removed dynamically.
+ * Events reported to a probe are propagated to every attached instrument; the order is undefined.
+ * <p>
+ * Probe methods must be amenable to Truffle/Graal inlining on the assumption that the collection of
+ * attached instruments seldom changes. The assumption is invalidated when instruments are added or
+ * removed, but some instruments may change their internal state in such a way that the assumption
+ * should also be invalidated.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development. In particular, the
+ * <em>notify</em> methods must be migrated to another interface.
+ *
+ * @see Instrument
+ * @see Wrapper
+ */
+public interface Probe extends ExecutionEvents, PhylumTagged {
+
+    /**
+     * The source location with which this probe is (presumably uniquely) associated.
+     */
+    SourceSection getSourceLocation();
+
+    /**
+     * Mark this probe as being associated with an AST node in some category useful for debugging
+     * and other tools.
+     */
+    void tagAs(PhylumTag tag);
+
+    /**
+     * Adds an instrument to this probe.
+     */
+    void addInstrument(Instrument newInstrument);
+
+    /**
+     * Removes an instrument from this probe.
+     */
+    void removeInstrument(Instrument oldInstrument);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Client for receiving events relate to {@link Probe} management. Does not report AST copying.
+ */
+public interface ProbeListener {
+
+    /**
+     * Notifies that a newly created (untagged) {@link Probe} has been inserted into a Truffle AST.
+     * There will be no notification when an existing {@link Probe} is shared by an AST copy.
+     */
+    void newProbeInserted(SourceSection location, Probe probe);
+
+    /**
+     * Notifies that a (fully constructed) {@link Probe} has been tagged. A subsequent marking with
+     * the same tag is idempotent and generates no notification.
+     */
+    void probeTaggedAs(Probe probe, PhylumTag tag);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/QuitException.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Controls breaking out of all executions and ending Truffle execution.
+ */
+public final class QuitException extends ControlFlowException {
+
+    private static final long serialVersionUID = -4301115629772778413L;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceCallback.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Instrumentation callback for guest language source-related events.
+ */
+public interface SourceCallback {
+
+    public void startLoading(Source source);
+
+    public void endLoading(Source source);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SourceListener.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * A client of the instrumentation framework that requests event notifications from the language
+ * engine when sources are loaded.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ */
+public interface SourceListener {
+
+    /**
+     * The guest language runtime is starting to load a source. Care should be taken to ensure that
+     * under any circumstance there is always a following call to {@link #loadEnding(Source)} with
+     * the same argument.
+     */
+    void loadStarting(Source source);
+
+    /**
+     * The guest language runtime has finished loading a source. Care should be taken to ensure that
+     * under any circumstance there is always a prior call to {@link #loadStarting(Source)} with the
+     * same argument.
+     */
+    void loadEnding(Source source);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardTag.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+/**
+ * A somewhat language-agnostic set of phylum categories, suitable for conventional imperative
+ * languages, and is being developed incrementally.
+ * <p>
+ * The need for alternative sets of tags is likely to arise, perhaps for other families of languages
+ * (for example for mostly expression-oriented languages) or even for specific languages.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ *
+ * @see Probe
+ * @see Wrapper
+ */
+public enum StandardTag implements PhylumTag {
+
+    /**
+     * Marker for a variable assignment.
+     */
+    ASSIGNMENT("assignment", "a variable assignment"),
+
+    /**
+     * Marker for a call site.
+     */
+    CALL("call", "a method/procedure call site"),
+
+    /**
+     * Marker for a location where a guest language exception is about to be thrown.
+     */
+    THROW("throw", "creator of an exception"),
+
+    /**
+     * Marker for a location where ordinary "stepping" should halt.
+     */
+    STATEMENT("statement", "basic unit of the language, suitable for \"stepping\" in a debugger");
+
+    private final String name;
+    private final String description;
+
+    private StandardTag(String name, String description) {
+        this.name = name;
+        this.description = description;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java	Fri May 30 15:09:09 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Visualization services for the benefit of instrumentation-based tools, possibly specialized for
+ * each guest language and possibly specialized for relevant information from the underlying Truffle
+ * implementation.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ */
+public interface Visualizer {
+
+    /**
+     * Gets a printer for Truffle ASTs, possibly specialized to be helpful for a specific guest
+     * language implementation.
+     */
+    ASTPrinter getASTPrinter();
+
+    /**
+     * A short description of a source location in terms of source + line number.
+     */
+    String displaySourceLocation(Node node);
+
+    /**
+     * Describes the name of the method containing a node.
+     */
+    String displayMethodName(Node node);
+
+    /**
+     * The name of the method.
+     */
+    String displayCallTargetName(CallTarget callTarget);
+
+    /**
+     * Converts a value in the guest language to a display string.
+     */
+    String displayValue(ExecutionContext context, Object value);
+
+    /**
+     * Converts a slot identifier in the guest language to a display string.
+     */
+    String displayIdentifier(FrameSlot slot);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Wrapper.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,77 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A node that can be inserted into a Truffle AST in order to attach <em>instrumentation</em> at a
+ * particular node.
+ * <p>
+ * A wrapper <em>decorates</em> an AST node (its <em>child</em>) by acting as a transparent
+ * <em>proxy</em> for the child with respect to Truffle execution semantics.
+ * <p>
+ * A wrapper is also expected to notify its associated {@link Probe} when {@link ExecutionEvents}
+ * occur at the wrapper during program execution.
+ * <p>
+ * The wrapper's {@link Probe} is shared by every copy of the wrapper made when the AST is copied.
+ * <p>
+ * Wrapper implementation guidelines:
+ * <ol>
+ * <li>Every guest language implementation should include a Wrapper implementation; usually only one
+ * is needed.</li>
+ * <li>The Wrapper type should descend from the <em>language-specific node class</em> of the guest
+ * language.</li>
+ * <li>The Wrapper must have a single {@code @Child private <guestLanguage>Node child} field.</li>
+ * <li>The Wrapper must act as a <em>proxy</em> for its child, which means implementing every
+ * possible <em>execute-</em> method that gets called on guest language AST node types by their
+ * parents, and passing along each call to its child.</li>
+ * <li>The Wrapper must have a single {@code private final Probe probe} to which an optional probe
+ * can be attached during node construction.</li>
+ * <li>Wrapper methods must also notify its attached {@link Probe}, if any, in terms of standard
+ * {@link ExecutionEvents}.</li>
+ * <li>Most importantly, Wrappers must be implemented so that Truffle optimization will reduce their
+ * runtime overhead to zero when there is no probe attached or when a probe has no attached
+ * {@link Instrument}s.</li>
+ * </ol>
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ *
+ * @see Probe
+ * @see ExecutionEvents
+ */
+public interface Wrapper extends PhylumTagged {
+
+    /**
+     * Gets the AST node being instrumented, which should never be an instance of {@link Wrapper}.
+     */
+    Node getChild();
+
+    /**
+     * Gets the {@link Probe} to which events occurring at this wrapper's child are propagated.
+     */
+    Probe getProbe();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+
+/**
+ * A language-agnostic for printing out various pieces of a Truffle AST.
+ */
+public class DefaultASTPrinter implements ASTPrinter {
+
+    public DefaultASTPrinter() {
+    }
+
+    public void printTree(PrintWriter p, Node node, int maxDepth, Node markNode) {
+        printTree(p, node, maxDepth, markNode, 1);
+        p.println();
+        p.flush();
+    }
+
+    public String printTreeToString(Node node, int maxDepth, Node markNode) {
+        StringWriter out = new StringWriter();
+        printTree(new PrintWriter(out), node, maxDepth, markNode);
+        return out.toString();
+    }
+
+    public String printTreeToString(Node node, int maxDepth) {
+        return printTreeToString(node, maxDepth, null);
+    }
+
+    private static void printTree(PrintWriter p, Node node, int maxDepth, Node markNode, int level) {
+        if (node == null) {
+            p.print("null");
+            return;
+        }
+
+        p.print(nodeName(node));
+
+        String sep = "";
+        p.print("(");
+
+        final SourceSection src = node.getSourceSection();
+        if (src != null) {
+            if (!(src instanceof NullSourceSection)) {
+                p.print(src.getSource().getName() + ":" + src.getStartLine());
+            }
+        }
+        if (node instanceof PhylumTagged) {
+            final PhylumTagged taggedNode = (PhylumTagged) node;
+            p.print("[");
+            String prefix = "";
+            for (PhylumTag tag : taggedNode.getPhylumTags()) {
+                p.print(prefix);
+                prefix = ",";
+                p.print(tag.toString());
+            }
+            p.print("]");
+        }
+
+        ArrayList<NodeField> childFields = new ArrayList<>();
+
+        for (NodeField field : NodeClass.get(node.getClass()).getFields()) {
+            if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
+                childFields.add(field);
+            } else if (field.getKind() == NodeFieldKind.DATA) {
+                // p.print(sep);
+                // sep = ", ";
+                //
+                // final String fieldName = field.getName();
+                // switch (fieldName) {
+                //
+                // }
+                // p.print(fieldName);
+                // p.print(" = ");
+                // p.print(field.loadValue(node));
+            }
+        }
+        p.print(")");
+
+        if (level <= maxDepth) {
+
+            if (childFields.size() != 0) {
+                p.print(" {");
+                for (NodeField field : childFields) {
+
+                    Object value = field.loadValue(node);
+                    if (value == null) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        p.print(" = null ");
+                    } else if (field.getKind() == NodeFieldKind.CHILD) {
+                        final Node valueNode = (Node) value;
+                        printNewLine(p, level, valueNode == markNode);
+                        p.print(field.getName());
+                        p.print(" = ");
+                        printTree(p, valueNode, maxDepth, markNode, level + 1);
+                    } else if (field.getKind() == NodeFieldKind.CHILDREN) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        Node[] children = (Node[]) value;
+                        p.print(" = [");
+                        sep = "";
+                        for (Node child : children) {
+                            p.print(sep);
+                            sep = ", ";
+                            printTree(p, child, maxDepth, markNode, level + 1);
+                        }
+                        p.print("]");
+                    } else {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                    }
+                }
+                printNewLine(p, level - 1);
+                p.print("}");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level, boolean mark) {
+        p.println();
+        for (int i = 0; i < level; i++) {
+            if (mark && i == 0) {
+                p.print(" -->");
+            } else {
+                p.print("    ");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level) {
+        printNewLine(p, level, false);
+    }
+
+    private static String nodeName(Node node) {
+        return node.getClass().getSimpleName();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+public class DefaultVisualizer implements Visualizer {
+
+    private final ASTPrinter astPrinter;
+
+    public DefaultVisualizer() {
+        this.astPrinter = new DefaultASTPrinter();
+    }
+
+    public ASTPrinter getASTPrinter() {
+        return astPrinter;
+    }
+
+    public String displaySourceLocation(Node node) {
+        if (node == null) {
+            return "<unknown>";
+        }
+        SourceSection section = node.getSourceSection();
+        boolean estimated = false;
+        if (section == null) {
+            section = node.getEncapsulatingSourceSection();
+            estimated = true;
+        }
+        return section.getShortDescription() + (estimated ? "~" : "");
+    }
+
+    public String displayMethodName(Node node) {
+        if (node == null) {
+            return null;
+        }
+        RootNode root = node.getRootNode();
+        if (root == null) {
+            return "unknown";
+        }
+        return root.getCallTarget().toString();
+    }
+
+    public String displayCallTargetName(CallTarget callTarget) {
+        return callTarget.toString();
+    }
+
+    public String displayValue(ExecutionContext context, Object value) {
+        return value.toString();
+    }
+
+    public String displayIdentifier(FrameSlot slot) {
+        return slot.getIdentifier().toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,399 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
+ * <p>
+ * Coordinates propagation of Truffle AST {@link ExecutionEvents}.
+ */
+public abstract class InstrumentationNode extends Node implements ExecutionEvents {
+
+    interface ProbeCallback {
+        void newTagAdded(ProbeImpl probe, PhylumTag tag);
+    }
+
+    /**
+     * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection}
+     * extent of guest language source code.
+     *
+     * @return a new probe
+     */
+    static ProbeImpl createProbe(SourceSection sourceSection, ProbeCallback probeCallback) {
+        return new ProbeImpl(sourceSection, probeCallback);
+    }
+
+    /**
+     * Next in chain.
+     */
+    @Child protected InstrumentationNode next;
+
+    protected InstrumentationNode() {
+    }
+
+    /**
+     * Gets the {@link Probe} to which this instrument is attached; {@code null} if not attached.
+     */
+    protected Probe getProbe() {
+        final InstrumentationNode parent = (InstrumentationNode) getParent();
+        return parent == null ? null : parent.getProbe();
+    }
+
+    /**
+     * Add a probe to the end of this probe chain.
+     */
+    private void internalAddInstrument(Instrument newInstrument) {
+        if (next == null) {
+            this.next = insert(newInstrument);
+        } else {
+            next.internalAddInstrument(newInstrument);
+        }
+    }
+
+    private void internalRemoveInstrument(Instrument oldInstrument) {
+        if (next == null) {
+            throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument);
+        } else if (next == oldInstrument) {
+            if (oldInstrument.next == null) {
+                this.next = null;
+            } else {
+                this.next = insert(oldInstrument.next);
+                oldInstrument.next = null;
+            }
+        } else {
+            next.internalRemoveInstrument(oldInstrument);
+        }
+    }
+
+    /**
+     * Reports to the instance of {@link Probe} holding this instrument, if any, that some essential
+     * state has changed that requires deoptimization.
+     */
+    @CompilerDirectives.SlowPath
+    protected void notifyProbeChanged(Instrument instrument) {
+        Probe probe = getProbe();
+        if (probe != null) {
+            final ProbeImpl probeImpl = (ProbeImpl) probe;
+            probeImpl.notifyProbeChanged(instrument);
+        }
+    }
+
+    protected void internalEnter(Node astNode, VirtualFrame frame) {
+        enter(astNode, frame);
+        if (next != null) {
+            next.internalEnter(astNode, frame);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame) {
+        leave(astNode, frame);
+        if (next != null) {
+            next.internalLeave(astNode, frame);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, boolean result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, byte result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, short result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, int result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, long result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, char result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, float result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, double result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeave(Node astNode, VirtualFrame frame, Object result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    protected void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+        leaveExceptional(astNode, frame, null);
+        if (next != null) {
+            next.internalLeaveExceptional(astNode, frame, e);
+        }
+    }
+
+    /**
+     * Holder of a chain of {@linkplain InstrumentationNode instruments}: manages the
+     * {@link Assumption} that none of the instruments have changed since last checked.
+     * <p>
+     * An instance is intended to be shared by every clone of the AST node with which it is
+     * originally attached, so it holds no parent pointer.
+     * <p>
+     * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful
+     * for instrumentation about its AST location(s).
+     */
+    static final class ProbeImpl extends InstrumentationNode implements Probe {
+
+        private final ProbeCallback probeCallback;
+
+        /**
+         * Source information about the AST node (and its clones) to which this probe is attached.
+         */
+        private final SourceSection probedSourceSection;
+
+        // TODO (mlvdv) assumption model broken
+        @CompilerDirectives.CompilationFinal private Assumption probeUnchanged;
+
+        @CompilerDirectives.CompilationFinal private PhylumTrap trap = null;
+
+        private final ArrayList<PhylumTag> tags = new ArrayList<>();
+
+        private ProbeImpl(SourceSection sourceSection, ProbeCallback probeCallback) {
+            this.probeCallback = probeCallback;
+            this.probedSourceSection = sourceSection;
+            this.probeUnchanged = Truffle.getRuntime().createAssumption();
+            this.next = null;
+        }
+
+        public SourceSection getSourceLocation() {
+            return probedSourceSection;
+        }
+
+        @SlowPath
+        public void tagAs(PhylumTag tag) {
+            assert tag != null;
+            if (!tags.contains(tag)) {
+                tags.add(tag);
+                probeCallback.newTagAdded(this, tag);
+            }
+        }
+
+        public boolean isTaggedAs(PhylumTag tag) {
+            assert tag != null;
+            return tags.contains(tag);
+        }
+
+        public Iterable<PhylumTag> getPhylumTags() {
+            return tags;
+        }
+
+        @SlowPath
+        public void addInstrument(Instrument instrument) {
+            probeUnchanged.invalidate();
+            super.internalAddInstrument(instrument);
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        @SlowPath
+        public void removeInstrument(Instrument instrument) {
+            probeUnchanged.invalidate();
+            super.internalRemoveInstrument(instrument);
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        @Override
+        protected Probe getProbe() {
+            return this;
+        }
+
+        @Override
+        @SlowPath
+        protected void notifyProbeChanged(Instrument instrument) {
+            probeUnchanged.invalidate();
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        @SlowPath
+        void setTrap(PhylumTrap trap) {
+            assert trap == null || isTaggedAs(trap.getTag());
+            probeUnchanged.invalidate();
+            this.trap = trap;
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        public void enter(Node astNode, VirtualFrame frame) {
+            if (trap != null || next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                if (trap != null) {
+                    trap.phylumTrappedAt(astNode, frame.materialize());
+                }
+                if (next != null) {
+                    next.internalEnter(astNode, frame);
+                }
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, boolean result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, byte result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, short result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, int result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, long result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, char result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, float result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, double result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, Object result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeaveExceptional(astNode, frame, e);
+            }
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,168 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeCallback;
+import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeImpl;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * Factory and services for AST {@link Probe}s
+ */
+public final class ProbeManager {
+
+    // TODO (mlvdv) use weak references.
+    /**
+     * Map: SourceSection ==> probe associated with that source section in an AST.
+     */
+    private final Map<SourceSection, ProbeImpl> srcToProbe = new HashMap<>();
+
+    // TODO (mlvdv) use weak references.
+    /**
+     * Map: Source line ==> probes associated with source sections starting on the line.
+     */
+    private final Map<SourceLineLocation, Collection<Probe>> lineToProbes = new HashMap<>();
+
+    private final List<ProbeListener> probeListeners = new ArrayList<>();
+
+    private final ProbeCallback probeCallback;
+
+    /**
+     * When non-null, "enter" events with matching tags will trigger a callback.
+     */
+    private PhylumTrap phylumTrap = null;
+
+    public ProbeManager() {
+        this.probeCallback = new ProbeCallback() {
+            /**
+             * Receives (from the {@link Probe} implementation) and distributes notification that a
+             * {@link Probe} has acquired a new {@linkplain PhylumTag tag}.
+             */
+            public void newTagAdded(ProbeImpl probe, PhylumTag tag) {
+                for (ProbeListener listener : probeListeners) {
+                    listener.probeTaggedAs(probe, tag);
+                }
+                if (phylumTrap != null && tag == phylumTrap.getTag()) {
+                    probe.setTrap(phylumTrap);
+                }
+            }
+        };
+    }
+
+    public void addProbeListener(ProbeListener listener) {
+        assert listener != null;
+        probeListeners.add(listener);
+    }
+
+    public void removeProbeListener(ProbeListener removeListener) {
+        final List<ProbeListener> listeners = new ArrayList<>(probeListeners);
+        for (ProbeListener listener : listeners) {
+            if (listener == removeListener) {
+                probeListeners.remove(listener);
+            }
+        }
+    }
+
+    public Probe getProbe(SourceSection sourceSection) {
+        assert sourceSection != null;
+
+        ProbeImpl probe = srcToProbe.get(sourceSection);
+
+        if (probe != null) {
+            return probe;
+        }
+        probe = InstrumentationNode.createProbe(sourceSection, probeCallback);
+
+        // Register new probe by unique SourceSection
+        srcToProbe.put(sourceSection, probe);
+
+        // Register new probe by source line, there may be more than one
+        // Create line location for map key
+        final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
+
+        Collection<Probe> probes = lineToProbes.get(lineLocation);
+        if (probes == null) {
+            probes = new ArrayList<>(2);
+            lineToProbes.put(lineLocation, probes);
+        }
+        probes.add(probe);
+
+        for (ProbeListener listener : probeListeners) {
+            listener.newProbeInserted(sourceSection, probe);
+        }
+
+        return probe;
+    }
+
+    public Collection<Probe> findProbesTaggedAs(PhylumTag tag) {
+        final List<Probe> probes = new ArrayList<>();
+        for (Probe probe : srcToProbe.values()) {
+            if (tag == null || probe.isTaggedAs(tag)) {
+                probes.add(probe);
+            }
+        }
+        return probes;
+    }
+
+    public Collection<Probe> findProbesByLine(SourceLineLocation lineLocation) {
+        final Collection<Probe> probes = lineToProbes.get(lineLocation);
+        if (probes == null) {
+            return Collections.emptyList();
+        }
+        return new ArrayList<>(probes);
+    }
+
+    public void setPhylumTrap(PhylumTrap trap) {
+        assert trap != null;
+        if (this.phylumTrap != null) {
+            throw new IllegalStateException("trap already set");
+        }
+        this.phylumTrap = trap;
+
+        PhylumTag tag = trap.getTag();
+        for (ProbeImpl probe : srcToProbe.values()) {
+            if (probe.isTaggedAs(tag)) {
+                probe.setTrap(trap);
+            }
+        }
+    }
+
+    public void clearPhylumTrap() {
+        if (this.phylumTrap == null) {
+            throw new IllegalStateException("no trap set");
+        }
+        for (ProbeImpl probe : srcToProbe.values()) {
+            if (probe.isTaggedAs(phylumTrap.getTag())) {
+                probe.setTrap(null);
+            }
+        }
+        phylumTrap = null;
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Fri May 30 15:09:09 2014 +0200
@@ -134,31 +134,6 @@
      * @param newChildren the array of new children whose parent should be updated
      * @return the array of new children
      */
-    @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;
@@ -191,8 +166,12 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
+        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         newChild.adoptHelper();
+        if (isInserted) {
+            newChild.onAdopt();
+        }
     }
 
     private void adoptHelper() {
@@ -209,8 +188,12 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
+        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         newChild.adoptUnadoptedHelper();
+        if (isInserted) {
+            newChild.onAdopt();
+        }
     }
 
     private void adoptUnadoptedHelper() {
@@ -332,7 +315,6 @@
     }
 
     private void traceRewrite(Node newNode, CharSequence reason) {
-
         if (TruffleOptions.TraceRewritesFilterFromCost != null) {
             if (filterByKind(this, TruffleOptions.TraceRewritesFilterFromCost)) {
                 return;
@@ -352,8 +334,21 @@
             return;
         }
 
+        final SourceSection reportedSourceSection = getEncapsulatingSourceSection();
+
         PrintStream out = System.out;
-        out.printf("[truffle]   rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason);
+        out.printf("[truffle]   rewrite %-50s |From %-40s |To %-40s |Reason %s%s%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason != null && reason.length() > 0 ? reason
+                        : "unknown", reportedSourceSection != null ? " at " + reportedSourceSection.getShortDescription() : "");
+    }
+
+    /**
+     * Subclasses of {@link Node} can implement this method to execute extra functionality when a
+     * node is effectively inserted into the AST. The {@code onAdopt} callback is called after the
+     * node has been effectively inserted, and it is guaranteed to be called only once for any given
+     * node.
+     */
+    protected void onAdopt() {
+        // empty default
     }
 
     private static String formatNodeInfo(Node node) {
@@ -511,4 +506,31 @@
             throw new RuntimeException(e);
         }
     }
+
+    /**
+     * Returns a user-readable description of the purpose of the Node, or "" if no description is
+     * available.
+     */
+    public String getDescription() {
+        NodeInfo info = getClass().getAnnotation(NodeInfo.class);
+        if (info != null) {
+            return info.description();
+        }
+        return "";
+    }
+
+    /**
+     * Returns a string representing the language this node has been implemented for. If the
+     * language is unknown, returns "".
+     */
+    public String getLanguage() {
+        NodeInfo info = getClass().getAnnotation(NodeInfo.class);
+        if (info != null && info.language() != null && info.language().length() > 0) {
+            return info.language();
+        }
+        if (parent != null) {
+            return parent.getLanguage();
+        }
+        return "";
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java	Fri May 30 15:09:09 2014 +0200
@@ -35,7 +35,7 @@
 
     /**
      * Short name representing the node that can be used for debugging.
-     * 
+     *
      * @return the short name
      */
     String shortName() default "";
@@ -43,10 +43,26 @@
     /**
      * Provides a rough estimate for the cost of the annotated {@link Node}. This estimate can be
      * used by runtime systems or guest languages to implement heuristics based on Truffle ASTs.
-     * 
+     *
      * @see Node#getCost()
      * @see NodeCost
      */
     NodeCost cost() default NodeCost.MONOMORPHIC;
 
+    /**
+     * A human readable explanation of the purpose of the annotated {@link Node}. Can be used e.g.
+     * for debugging or visualization purposes.
+     *
+     * @return the description
+     */
+    String description() default "";
+
+    /**
+     * A description, providing a user-readable explanation of the source language of the annotated
+     * {@link Node}. Can be used e.g. for debugging or visualization purposes. Typically this
+     * information is set only in an abstract base node for the language implementation.
+     *
+     * @return the description
+     */
+    String language() default "";
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Fri May 30 15:09:09 2014 +0200
@@ -47,6 +47,8 @@
     public interface FieldOffsetProvider {
 
         long objectFieldOffset(Field field);
+
+        int getTypeSize(Class<?> clazz);
     }
 
     private static final FieldOffsetProvider unsafeFieldOffsetProvider = new FieldOffsetProvider() {
@@ -55,6 +57,17 @@
         public long objectFieldOffset(Field field) {
             return unsafe.objectFieldOffset(field);
         }
+
+        @Override
+        public int getTypeSize(Class<?> clazz) {
+            if (!clazz.isPrimitive()) {
+                return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
+            } else if (clazz == int.class) {
+                return Unsafe.ARRAY_INT_INDEX_SCALE;
+            } else {
+                throw new UnsupportedOperationException("unsupported field type: " + clazz);
+            }
+        }
     };
 
     public static enum NodeFieldKind {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/DefaultNodeInstrumenter.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A no-op node instrumenter; always returns the node unproxied and unmodified.
- */
-public class DefaultNodeInstrumenter implements NodeInstrumenter {
-
-    public Node instrumentAs(Node node, NodePhylum phylum, Object... args) {
-        return node;
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-/**
- * Marker interface for all Truffle <strong>instrumentation nodes</strong>: nodes that are do not
- * appear in Truffle ASTs as part of a language's execution semantics.
- * <p>
- * In documentation related to instrumentation nodes, these are distinguished by referring to all
- * other nodes (i.e. ones that <em>do</em> implement language semantics) as <em>AST nodes</em>.
- */
-public interface InstrumentationNode {
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeEvents.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Marker interface for all Truffle <strong>instrumentation nodes</strong>: nodes that are do not
- * appear in Truffle ASTs as part of a language's execution semantics.
- * <p>
- * In documentation related to instrumentation nodes, these are distinguished by referring to all
- * other nodes (i.e. ones that <em>do</em> implement language semantics) as <em>AST nodes</em>.
- */
-public interface InstrumentationProbeEvents {
-
-    /**
-     * Notifies a probe that receiver that an AST node's execute method has just been entered.
-     * Callers should assure that a matching call to {@link #leave(Node, VirtualFrame, Object)}
-     * always follows.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame being passed to the execute method
-     */
-    void enter(Node astNode, VirtualFrame frame);
-
-    /**
-     * Notifies a probe that an AST Node's void-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     */
-    void leave(Node astNode, VirtualFrame frame);
-
-    /**
-     * Notifies a probe that an AST Node's boolean-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, boolean result);
-
-    /**
-     * Notifies a probe that an AST Node's byte-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, byte result);
-
-    /**
-     * Notifies a probe that an AST Node's short-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, short result);
-
-    /**
-     * Notifies a probe that an AST Node's integer-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, int result);
-
-    /**
-     * Notifies a probe that an AST Node's long-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, long result);
-
-    /**
-     * Notifies a probe that an AST Node's float-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, float result);
-
-    /**
-     * Notifies a probe that an AST Node's double-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, double result);
-
-    /**
-     * Notifies a probe that an AST Node's char-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, char result);
-
-    /**
-     * Notifies a probe that an AST Node's object-valued execute method is about to exit.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param result The result of the call to the execute method.
-     */
-    void leave(Node astNode, VirtualFrame frame, Object result);
-
-    /**
-     * Notifies a probe that an AST Node's execute method is about to leave under exceptional
-     * conditions, returning no value.
-     * <p>
-     * Callers should assure (via {@code try/finally}) that a matching call to this method always
-     * follows a call to {@link #enter(Node, VirtualFrame)}.
-     * 
-     * @param astNode The AST node on which the execute method is being called
-     * @param frame The frame that was passed to the execute method
-     * @param e the exception associated with the unusual return
-     */
-    void leaveExceptional(Node astNode, VirtualFrame frame, Exception e);
-
-    /**
-     * Notifies a probe that an AST node is about to be replaced with another.
-     * 
-     * @param oldAstNode the AST node currently in the tree
-     * @param newAstNode the AST replacement node
-     * @param reason explanation for the replacement
-     */
-    void replace(Node oldAstNode, Node newAstNode, String reason);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,500 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A <strong>probe</strong>: a Truffle instrumentation node that holds code to perform some action
- * when notified (via a {@linkplain InstrumentationProxyNode proxy node} in the AST) of a
- * {@linkplain InstrumentationProbeEvents probe event} taking place at the AST node.
- * <p>
- * Probes are only active when attached to a {@linkplain ProbeChain "probe chain"} that is referred
- * to by one or more {@linkplain InstrumentationProxyNode proxy nodes} in an AST.
- */
-public abstract class InstrumentationProbeNode extends Node implements InstrumentationNode, InstrumentationProbeEvents {
-
-    /**
-     * Next in chain.
-     */
-    @Child protected InstrumentationProbeNode next;
-
-    protected InstrumentationProbeNode() {
-    }
-
-    protected int countProbes() {
-        return next == null ? 0 : next.countProbes() + 1;
-    }
-
-    protected boolean isStepping() {
-        final InstrumentationProbeNode parent = (InstrumentationProbeNode) getParent();
-        return parent.isStepping();
-    }
-
-    /**
-     * Add a probe to the end of this probe chain.
-     */
-    protected void internalAppendProbe(InstrumentationProbeNode newProbeNode) {
-        if (next == null) {
-            this.next = insert(newProbeNode);
-        } else {
-            next.internalAppendProbe(newProbeNode);
-        }
-    }
-
-    protected void internalRemoveProbe(InstrumentationProbeNode oldProbeNode) {
-        if (next == null) {
-            throw new RuntimeException("Couldn't find probe to remove: " + oldProbeNode);
-        } else if (next == oldProbeNode) {
-            if (oldProbeNode.next == null) {
-                this.next = null;
-            } else {
-                this.next = insert(oldProbeNode.next);
-                oldProbeNode.next = null;
-            }
-        } else {
-            next.internalRemoveProbe(oldProbeNode);
-        }
-    }
-
-    /**
-     * Passes up the chain notification that a probe has changed its execution state in a way that
-     * invalidates fast path code. Assumes that there is an instance of {@link ProbeChain} at the
-     * head of the chain.
-     */
-    @CompilerDirectives.SlowPath
-    protected void notifyProbeChanged(InstrumentationProbeNode probeNode) {
-        final InstrumentationProbeNode parent = (InstrumentationProbeNode) getParent();
-        parent.notifyProbeChanged(probeNode);
-    }
-
-    // TODO (mlvdv) making the internal*() methods public is a workaround for a bug/limitation in
-    // the Truffle compiler; they are intended to be private.
-
-    public void internalEnter(Node astNode, VirtualFrame frame) {
-        enter(astNode, frame);
-        if (next != null) {
-            next.internalEnter(astNode, frame);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame) {
-        leave(astNode, frame);
-        if (next != null) {
-            next.internalLeave(astNode, frame);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, boolean result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, byte result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, short result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, int result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, long result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, char result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, float result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, double result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeave(Node astNode, VirtualFrame frame, Object result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    public void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-        leaveExceptional(astNode, frame, null);
-        if (next != null) {
-            next.internalLeaveExceptional(astNode, frame, e);
-        }
-    }
-
-    public void internalReplace(Node oldAstNode, Node newAstNode, String reason) {
-        replace(oldAstNode, newAstNode, reason);
-        if (next != null) {
-            next.internalReplace(oldAstNode, newAstNode, reason);
-        }
-    }
-
-    /**
-     * A probe implementation that implements all of {@link InstrumentationProbeEvents} with empty
-     * methods; concrete subclasses can override only the methods for which something is to be done.
-     */
-    public static class DefaultProbeNode extends InstrumentationProbeNode {
-
-        private final ExecutionContext executionContext;
-
-        protected DefaultProbeNode(ExecutionContext context) {
-            this.executionContext = context;
-        }
-
-        public ExecutionContext getContext() {
-            return executionContext;
-        }
-
-        public void enter(Node astNode, VirtualFrame frame) {
-        }
-
-        public void leave(Node astNode, VirtualFrame frame) {
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, boolean result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, byte result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, short result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, int result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, long result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, char result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, float result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, double result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, Object result) {
-        }
-
-        public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-        }
-
-        public void replace(Node oldAstNode, Node newAstNode, String reason) {
-        }
-
-    }
-
-    /**
-     * Holder of a chain of {@linkplain InstrumentationProbeNode probes}: manages the
-     * {@link Assumption} that the chain has not changed since checked checked.
-     * <p>
-     * May be categorized by one or more {@linkplain NodePhylum node phyla}, signifying information
-     * useful for instrumentation about its AST location(s).
-     */
-    public static final class ProbeChain extends DefaultProbeNode implements PhylumMarked {
-
-        @CompilerDirectives.CompilationFinal private Assumption probeUnchanged;
-
-        /**
-         * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line
-         * will cause a halt.
-         */
-        @CompilerDirectives.CompilationFinal private boolean stepping;
-
-        /**
-         * Source information about the node to which this probe chain is attached; it isn't
-         * otherwise available. A probe chain is shared by every copy made during runtime, so there
-         * is no parent pointer.
-         */
-        private final SourceSection probedSourceSection;
-
-        private final Set<NodePhylum> phyla = EnumSet.noneOf(NodePhylum.class);
-
-        private final String description; // for debugging
-
-        /**
-         * Creates a new, empty chain of {@linkplain InstrumentationProbeNode probes}, to which
-         * probes can be added/removed, and all of which will be notified of
-         * {@linkplain InstrumentationProbeEvents events} when the chain is notified.
-         */
-        public ProbeChain(ExecutionContext context, SourceSection sourceSection, String description) {
-            super(context);
-            this.probeUnchanged = Truffle.getRuntime().createAssumption();
-            this.probedSourceSection = sourceSection;
-            this.description = description;
-            this.next = null;
-        }
-
-        public int probeCount() {
-            return countProbes();
-        }
-
-        public String getDescription() {
-            return description;
-        }
-
-        public SourceSection getProbedSourceSection() {
-            return probedSourceSection;
-        }
-
-        /**
-         * Mark this probe chain as being associated with an AST node in some category useful for
-         * debugging and other tools.
-         */
-        public void markAs(NodePhylum phylum) {
-            assert phylum != null;
-            phyla.add(phylum);
-        }
-
-        /**
-         * Is this probe chain as being associated with an AST node in some category useful for
-         * debugging and other tools.
-         */
-        public boolean isMarkedAs(NodePhylum phylum) {
-            assert phylum != null;
-            return phyla.contains(phylum);
-        }
-
-        /**
-         * In which categories is the AST (with which this probe is associated) marked?
-         */
-        public Set<NodePhylum> getPhylumMarks() {
-            return phyla;
-        }
-
-        /**
-         * Change <em>stepping mode</em> for statements.
-         */
-        public void setStepping(boolean stepping) {
-            if (this.stepping != stepping) {
-                this.stepping = stepping;
-                probeUnchanged.invalidate();
-                probeUnchanged = Truffle.getRuntime().createAssumption();
-            }
-        }
-
-        @Override
-        protected boolean isStepping() {
-            return stepping;
-        }
-
-        @Override
-        protected int countProbes() {
-            // The head of the chain does not itself hold a probe
-            return next == null ? 0 : next.countProbes();
-        }
-
-        @Override
-        protected void notifyProbeChanged(InstrumentationProbeNode probeNode) {
-            probeUnchanged.invalidate();
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        @CompilerDirectives.SlowPath
-        public void appendProbe(InstrumentationProbeNode newProbeNode) {
-            probeUnchanged.invalidate();
-            super.internalAppendProbe(newProbeNode);
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        @CompilerDirectives.SlowPath
-        public void removeProbe(InstrumentationProbeNode oldProbeNode) {
-            probeUnchanged.invalidate();
-            super.internalRemoveProbe(oldProbeNode);
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        public void notifyEnter(Node astNode, VirtualFrame frame) {
-            if (stepping || next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                if (stepping) {
-                    getContext().getDebugContext().getDebugManager().haltedAt(astNode, frame.materialize());
-                }
-                if (next != null) {
-                    next.internalEnter(astNode, frame);
-                }
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, byte result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, short result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, int result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, long result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, char result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, float result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, double result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, Object result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeaveExceptional(astNode, frame, e);
-            }
-        }
-
-        public void notifyReplace(Node oldAstNode, Node newAstNode, String reason) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalReplace(oldAstNode, newAstNode, reason);
-            }
-        }
-
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProxyNode.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
-
-/**
- * Interface implemented by language-specific Truffle <strong>proxy nodes</strong>: nodes that do
- * not participate in the language's execution semantics, but which are inserted into an AST so that
- * tools (e.g. tracers, analyzers, debuggers) can be notified of AST interpretation events and
- * possibly intervene.
- * <p>
- * Language-specific proxy nodes call notification methods on an attached {@linkplain ProbeChain
- * probe chain} which passes along {@linkplain InstrumentationProbeEvents events} to any
- * {@linkplain InstrumentationProbeNode probes} that might have been attached.
- */
-public interface InstrumentationProxyNode extends InstrumentationNode, PhylumMarked {
-
-    /**
-     * Gets the non-instrumentation node being proxied.
-     */
-    Node getChild();
-
-    /**
-     * Gets the chain of probes to which events at this node are delegated. Note that a chain of
-     * probes may be used by more than one proxy.
-     */
-    ProbeChain getProbeChain();
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/NodeInstrumenter.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Implements the instrumentation of a Truffle AST node and returning either:
- * <ul>
- * <li>the node itself, or</li>
- * <li>a newly created {@linkplain InstrumentationProxyNode proxy node} that holds the instrumented
- * node as its {@linkplain com.oracle.truffle.api.nodes.Node.Child child}.</li>
- * </ul>
- */
-public interface NodeInstrumenter {
-
-    /**
-     * Wraps a {@linkplain InstrumentationProxyNode proxy node} around a node (if not already
-     * wrapped), marks the location with a {@linkplain NodePhylum phylum (category)} for user
-     * interaction, and passes along any characteristics of the particular node that are important
-     * for instrumentation (e.g. the function/method name at a call).
-     */
-    Node instrumentAs(Node node, NodePhylum phylum, Object... args);
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/NodePhylum.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-/**
- * Categories of {@link InstrumentationProxyNode}s to be used for defining user-visible debugging
- * and other simple tool behavior. These categories (<em>phyla</em>) should correspond to program
- * structures that are meaningful to a programmer using the guest language. A Truffle node without a
- * proxy carrying some phylum should be treated as an artifact of the guest language implementation
- * and should never be visible to the user of a guest language programming tool.
- * <p>
- * Note that phyla are not intended to represent a partition of user-visible node categories, as the
- * relative categorization of nodes can change with the particular programming tasks at hand.
- * <p>
- * This is a somewhat language-agnostic set of phyla, suitable for conventional imperative
- * languages, and is being developed incrementally.
- * <p>
- * The need for alternative sets of phyla is likely to arise, perhaps for other families of
- * languages (for example for mostly expression-oriented languages) or even for specific languages.
- * <p>
- * These are listed alphabetically so that listing from some collection classes will come out in
- * that order.
- * <p>
- * <strong>Disclaimer:</strong> this interface is under development and will change.
- */
-public enum NodePhylum {
-
-    /**
-     * Marker for a proxy at a variable assignment.
-     */
-    ASSIGNMENT,
-
-    /**
-     * Marker for a proxy at a call site.
-     */
-    CALL,
-
-    /**
-     * Marker for a proxy at which ordinary "stepping" should halt.
-     */
-    STATEMENT;
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/PhylumMarked.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.nodes.instrument;
-
-import java.util.*;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A kind of {@link Node} that can be marked as belong to 0 or more {@linkplain NodePhylum phyla}.
- */
-public interface PhylumMarked {
-
-    /**
-     * Is this proxy tagged as belonging to a particular category of language constructs?
-     */
-    boolean isMarkedAs(NodePhylum phylum);
-
-    /**
-     * In which categories is this node tagged (<em>empty set</em> if none).
-     */
-    Set<NodePhylum> getPhylumMarks();
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,546 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.source;
+
+import java.io.*;
+import java.lang.ref.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Provider for canonical representations of source code. Three kinds of sources are supported.
+ * <ul>
+ * <li><strong>File:</strong> Each file is represented as a canonical object, indexed by the
+ * absolute, canonical path name of the file. File contents are <em>read lazily</em> and contents
+ * optionally <em>cached</em>.</li>
+ * <li><strong>Literal Source:</strong> A named text string, whose contents are supplied concretely
+ * (possibly via an {@link Reader}), can also be used as a source. These are not indexed and should
+ * be considered value objects; equality is defined based on contents.</li>
+ * <li><strong>Fake Files:</strong> A named text string used for testing; its contents can be
+ * retrieved by name, unlike literal sources.</li>
+ * </ul>
+ * <p>
+ * <strong>File cache:</strong>
+ * <ol>
+ * <li>File content caching is optional, <em>off</em> by default.</li>
+ * <li>The first access to source file contents will result in the contents being read, and (if
+ * enabled) cached.</li>
+ * <li>If file contents have been cached, access to contents via {@link Source#getInputStream()} or
+ * {@link Source#getReader()} will be provided from the cache.</li>
+ * <li>Any access to file contents via the cache will result in a timestamp check and possible cache
+ * reload.</li>
+ * </ol>
+ */
+public final class SourceFactory {
+
+    // Only files and fake files are indexed.
+    private static final Map<String, WeakReference<SourceImpl>> pathToSource = new HashMap<>();
+
+    private static boolean fileCacheEnabled = true;
+
+    private SourceFactory() {
+    }
+
+    /**
+     * Gets the canonical representation of a source file, whose contents will be read lazily and
+     * then cached.
+     *
+     * @param fileName name
+     * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
+     * @return canonical representation of the file's contents.
+     * @throws RuntimeException if the file can not be read
+     */
+    public static Source fromFile(String fileName, boolean reset) throws RuntimeException {
+
+        // TODO (mlvdv) throw IOException
+
+        SourceImpl source = lookup(fileName);
+        if (source == null) {
+            final File file = new File(fileName);
+            String path = null;
+            if (file.exists()) {
+                try {
+                    path = file.getCanonicalPath();
+                } catch (IOException e) {
+                    throw new RuntimeException("Can't find file " + fileName);
+                }
+            }
+            source = lookup(path);
+            if (source == null) {
+                source = new FileSourceImpl(file, fileName, path);
+                store(path, source);
+            }
+        }
+        if (reset) {
+            source.reset();
+        }
+        return source;
+    }
+
+    /**
+     * Gets the canonical representation of a source file, whose contents will be read lazily and
+     * then cached.
+     *
+     * @param fileName name
+     * @return canonical representation of the file's contents.
+     * @throws RuntimeException if the file can not be read
+     */
+    public static Source fromFile(String fileName) throws RuntimeException {
+        return fromFile(fileName, false);
+    }
+
+    /**
+     * Creates a non-canonical source from literal text.
+     *
+     * @param code textual source code
+     * @param description a note about the origin, for error messages and debugging
+     * @return a newly created, non-indexed source representation
+     */
+    public static Source fromText(String code, String description) {
+        assert code != null;
+        return new LiteralSourceImpl(description, code);
+    }
+
+    /**
+     * Creates a source whose contents will be read immediately and cached.
+     *
+     * @param reader
+     * @param description a note about the origin, possibly useful for debugging
+     * @return a newly created, non-indexed source representation
+     * @throws IOException if reading fails
+     */
+    public static Source fromReader(Reader reader, String description) throws IOException {
+        return new LiteralSourceImpl(description, read(reader));
+    }
+
+    /**
+     * Creates a source from literal text, but which acts as a file and can be retrieved by name
+     * (unlike other literal sources); intended for testing.
+     *
+     * @param code textual source code
+     * @param fakeFileName string to use for indexing/lookup
+     * @return a newly created, source representation, canonical with respect to its name
+     */
+    public static Source asFakeFile(String code, String fakeFileName) {
+        final SourceImpl source = new LiteralSourceImpl(fakeFileName, code);
+        store(fakeFileName, source);
+        return source;
+    }
+
+    /**
+     * Enables/disables caching of file contents, <em>disabled</em> by default. Caching of sources
+     * created from literal text or readers is always enabled.
+     */
+    public static void setFileCaching(boolean enabled) {
+        fileCacheEnabled = enabled;
+    }
+
+    private static SourceImpl lookup(String key) {
+        WeakReference<SourceImpl> sourceRef = pathToSource.get(key);
+        return sourceRef == null ? null : sourceRef.get();
+    }
+
+    private static void store(String key, SourceImpl source) {
+        pathToSource.put(key, new WeakReference<>(source));
+    }
+
+    private static String read(Reader reader) throws IOException {
+        final StringBuilder builder = new StringBuilder();
+        final char[] buffer = new char[1024];
+
+        while (true) {
+            final int n = reader.read(buffer);
+            if (n == -1) {
+                break;
+            }
+            builder.append(buffer, 0, n);
+        }
+
+        return builder.toString();
+    }
+
+    private abstract static class SourceImpl implements Source {
+        // TODO (mlvdv) consider canonicalizing and reusing SourceSection instances
+        // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup
+
+        protected TextMap textMap = null;
+
+        protected abstract void reset();
+
+        public final InputStream getInputStream() {
+            return new ByteArrayInputStream(getCode().getBytes());
+        }
+
+        /**
+         * Gets the text (not including a possible terminating newline) in a (1-based) numbered
+         * line.
+         */
+        public final String getCode(int lineNumber) {
+            checkTextMap();
+            final int offset = textMap.lineStartOffset(lineNumber);
+            final int length = textMap.lineLength(lineNumber);
+            return getCode().substring(offset, offset + length);
+        }
+
+        /**
+         * The number of text lines in the source.
+         */
+        public final int getLineCount() {
+            return checkTextMap().lineCount();
+        }
+
+        /**
+         * The 1-based number of the line that includes a 0-based character offset.
+         */
+        public final int getLineNumber(int offset) {
+            return checkTextMap().offsetToLine(offset);
+        }
+
+        /**
+         * The 0-based character offset at the start of a (1-based) numbered line.
+         */
+        public final int getLineStartOffset(int lineNumber) {
+            return checkTextMap().lineStartOffset(lineNumber);
+        }
+
+        /**
+         * The number of characters (not counting a possible terminating newline) in a (1-based)
+         * numbered line.
+         */
+        public final int getLineLength(int lineNumber) {
+            return checkTextMap().lineLength(lineNumber);
+        }
+
+        public final SourceSection createSection(String identifier, int startOffset, int sectionLength) throws IllegalArgumentException {
+            final int codeLength = getCode().length();
+            if (!(startOffset >= 0 && sectionLength >= 0 && startOffset + sectionLength <= codeLength)) {
+                throw new IllegalArgumentException("text positions out of range");
+            }
+            checkTextMap();
+            final int startLine = getLineNumber(startOffset);
+            final int startColumn = startOffset - getLineStartOffset(startLine) + 1;
+
+            return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength);
+        }
+
+        public SourceSection createSection(String identifier, int startLine, int startColumn, int sectionLength) {
+            checkTextMap();
+            final int lineStartOffset = textMap.lineStartOffset(startLine);
+            if (startColumn > textMap.lineLength(startLine)) {
+                throw new IllegalArgumentException("column out of range");
+            }
+            final int startOffset = lineStartOffset + startColumn - 1;
+            return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength);
+        }
+
+        public SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length) {
+            return new SourceSectionImpl(this, identifier, startLine, startColumn, charIndex, length);
+        }
+
+        private TextMap checkTextMap() {
+            if (textMap == null) {
+                final String code = getCode();
+                if (code == null) {
+                    throw new RuntimeException("can't read file " + getName());
+                }
+                textMap = new TextMap(code);
+            }
+            return textMap;
+        }
+    }
+
+    private static class LiteralSourceImpl extends SourceImpl {
+
+        private final String name; // Name used originally to describe the source
+        private final String code;
+
+        public LiteralSourceImpl(String name, String code) {
+            this.name = name;
+            this.code = code;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String getShortName() {
+            return name;
+        }
+
+        @Override
+        public String getCode() {
+            return code;
+        }
+
+        @Override
+        public String getPath() {
+            return name;
+        }
+
+        @Override
+        public Reader getReader() {
+            return new StringReader(code);
+        }
+
+        @Override
+        protected void reset() {
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + name.hashCode();
+            result = prime * result + (code == null ? 0 : code.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (!(obj instanceof LiteralSourceImpl)) {
+                return false;
+            }
+            LiteralSourceImpl other = (LiteralSourceImpl) obj;
+            return name.equals(other.name) && code.equals(other.code);
+        }
+
+    }
+
+    private static class FileSourceImpl extends SourceImpl {
+
+        private final File file;
+        private final String name; // Name used originally to describe the source
+        private final String path;  // Normalized path description of an actual file
+
+        private String code = null;  // A cache of the file's contents
+        private long timeStamp;      // timestamp of the cache in the file system
+
+        public FileSourceImpl(File file, String name, String path) {
+            this.file = file;
+            this.name = name;
+            this.path = path;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String getShortName() {
+            return file.getName();
+        }
+
+        @Override
+        public String getCode() {
+            if (fileCacheEnabled) {
+                if (code == null || timeStamp != file.lastModified()) {
+                    try {
+                        code = read(getReader());
+                        timeStamp = file.lastModified();
+                    } catch (IOException e) {
+                    }
+                }
+                return code;
+            }
+            try {
+                return read(new FileReader(file));
+            } catch (IOException e) {
+            }
+            return null;
+        }
+
+        @Override
+        public String getPath() {
+            return path;
+        }
+
+        @Override
+        public Reader getReader() {
+            if (code != null && timeStamp == file.lastModified()) {
+                return new StringReader(code);
+            }
+            try {
+                return new FileReader(file);
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException("Can't find file " + path);
+            }
+        }
+
+        @Override
+        protected void reset() {
+            this.code = null;
+        }
+
+    }
+
+    private static class SourceSectionImpl implements SourceSection {
+
+        private final Source source;
+        private final String identifier;
+        private final int startLine;
+        private final int startColumn;
+        private final int charIndex;
+        private final int charLength;
+
+        /**
+         * Creates a new object representing a contiguous text section within the source code of a
+         * guest language program's text.
+         * <p>
+         * The starting location of the section is specified using two different coordinate:
+         * <ul>
+         * <li><b>(row, column)</b>: rows and columns are 1-based, so the first character in a
+         * source file is at position {@code (1,1)}.</li>
+         * <li><b>character index</b>: 0-based offset of the character from the beginning of the
+         * source, so the first character in a file is at index {@code 0}.</li>
+         * </ul>
+         * The <b>newline</b> that terminates each line counts as a single character for the purpose
+         * of a character index. The (row,column) coordinates of a newline character should never
+         * appear in a text section.
+         * <p>
+         *
+         * @param source object representing the complete source program that contains this section
+         * @param identifier an identifier used when printing the section
+         * @param startLine the 1-based number of the start line of the section
+         * @param startColumn the 1-based number of the start column of the section
+         * @param charIndex the 0-based index of the first character of the section
+         * @param charLength the length of the section in number of characters
+         */
+        public SourceSectionImpl(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) {
+            this.source = source;
+            this.identifier = identifier;
+            this.startLine = startLine;
+            this.startColumn = startColumn;
+            this.charIndex = charIndex;
+            this.charLength = charLength;
+        }
+
+        public final Source getSource() {
+            return source;
+        }
+
+        public final int getStartLine() {
+            return startLine;
+        }
+
+        public final int getStartColumn() {
+            return startColumn;
+        }
+
+        public final int getCharIndex() {
+            return charIndex;
+        }
+
+        public final int getCharLength() {
+            return charLength;
+        }
+
+        public final int getCharEndIndex() {
+            return charIndex + charLength;
+        }
+
+        public final String getIdentifier() {
+            return identifier;
+        }
+
+        public final String getCode() {
+            return getSource().getCode().substring(charIndex, charIndex + charLength);
+        }
+
+        public final String getShortDescription() {
+            return String.format("%s:%d", source.getShortName(), startLine);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s:%d", source.getName(), startLine);
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + charIndex;
+            result = prime * result + charLength;
+            result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
+            result = prime * result + ((source == null) ? 0 : source.hashCode());
+            result = prime * result + startColumn;
+            result = prime * result + startLine;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (!(obj instanceof SourceSectionImpl)) {
+                return false;
+            }
+            SourceSectionImpl other = (SourceSectionImpl) obj;
+            if (charIndex != other.charIndex) {
+                return false;
+            }
+            if (charLength != other.charLength) {
+                return false;
+            }
+            if (identifier == null) {
+                if (other.identifier != null) {
+                    return false;
+                }
+            } else if (!identifier.equals(other.identifier)) {
+                return false;
+            }
+            if (source == null) {
+                if (other.source != null) {
+                    return false;
+                }
+            } else if (!source.equals(other.source)) {
+                return false;
+            }
+            if (startColumn != other.startColumn) {
+                return false;
+            }
+            if (startLine != other.startLine) {
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,330 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.source;
-
-import java.io.*;
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-
-/**
- * A representation of source code information, suitable for hash table keys with equality defined
- * in terms of content. There are three kinds of sources supported at present.
- * <ul>
- * <li><strong>File:</strong> Each file is represented as a canonical object, indexed by the
- * absolute, canonical path name of the file. The textual contents of the file may be supplied when
- * the object is created, or it may be read lazily. Only one lazy attempt will be made to read a
- * file, and failure will result silently in null content.</li>
- * <li><strong>Literal Source:</strong> A named text string, whose contents are supplied concretely
- * (possibly via an {@link InputStream}), can also be used as a source. These are represented as
- * value objects whose equality depends on both name and contents.</li>
- * <li><strong>Fake Files:</strong> A named text string used for testing; its contents can be
- * retrieved by name, unlike literal sources.</li>
- * </ul>
- * <p>
- * <strong>Cache:</strong>
- * <ol>
- * <li>Access to source file contents via {@link Source#getInputStream()} or
- * {@link Source#getReader()} does <em>not</em> by itself result in the file's contents being cached
- * in the {@link Source} object.</li>
- * <li>Access to source file contents via {@link Source#getCode()} or any other {@link Source}
- * methods related to file's contents <em>will</em> result in the contents being cached in the
- * {@link Source} object.</li>
- * <li>Once source file contents have been cached, access to source file contents via
- * {@link Source#getInputStream()} or {@link Source#getReader()} will be provided from the cache.</li>
- * <li>Any access to source file contents via the cache will result in a timestamp check and
- * possible cache reload.</li>
- * </ol>
- */
-public final class SourceManager {
-
-    // Only files and fake files are indexed.
-    private final Map<String, SourceImpl> pathToSource = new HashMap<>();
-
-    public SourceManager() {
-
-    }
-
-    /**
-     * Gets the canonical representation of a source file, whose contents will be read lazily and
-     * then cached.
-     * 
-     * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
-     */
-    public Source get(String fileName, boolean reset) {
-
-        SourceImpl source = pathToSource.get(fileName);
-        if (source == null) {
-            final File file = new File(fileName);
-            String path = null;
-            if (file.exists()) {
-                try {
-                    path = file.getCanonicalPath();
-                } catch (IOException e) {
-                    throw new RuntimeException("Can't find file " + fileName);
-                }
-            }
-            source = pathToSource.get(path);
-            if (source == null) {
-                source = new FileSourceImpl(file, fileName, path);
-                pathToSource.put(path, source);
-            }
-        }
-        if (reset) {
-            source.reset();
-        }
-        return source;
-    }
-
-    /**
-     * Gets the canonical representation of a source file, whose contents will be read lazily and
-     * then cached.
-     */
-    public Source get(String fileName) {
-        return get(fileName, false);
-    }
-
-    /**
-     * Creates a source from literal text.
-     */
-    @SuppressWarnings("static-method")
-    public Source get(String name, String code) {
-        assert code != null;
-        return new LiteralSourceImpl(name, code);
-    }
-
-    /**
-     * Creates a source whose contents will be read immediately and cached.
-     */
-    @SuppressWarnings("static-method")
-    public Source get(String name, InputStream stream) throws IOException {
-        InputStreamReader reader = new InputStreamReader(stream);
-        return new LiteralSourceImpl(name, readCode(reader));
-    }
-
-    /**
-     * Creates a source from literal text, but which acts as a file and can be retrieved by name
-     * (unlike other literal sources); intended for testing.
-     */
-    public Source getFakeFile(String name, String code) {
-        final SourceImpl source = new LiteralSourceImpl(name, code);
-        pathToSource.put(name, source);
-        return source;
-    }
-
-    private static String readCode(Reader reader) throws IOException {
-        final StringBuilder builder = new StringBuilder();
-        final char[] buffer = new char[1024];
-
-        while (true) {
-            final int n = reader.read(buffer);
-            if (n == -1) {
-                break;
-            }
-            builder.append(buffer, 0, n);
-        }
-
-        return builder.toString();
-    }
-
-    private abstract static class SourceImpl implements Source {
-
-        protected TextMap textMap = null;
-
-        protected abstract void reset();
-
-        public final InputStream getInputStream() {
-            return new ByteArrayInputStream(getCode().getBytes());
-        }
-
-        /**
-         * Gets the text (not including a possible terminating newline) in a (1-based) numbered
-         * line.
-         */
-        public final String getCode(int lineNumber) {
-            checkTextMap();
-            final int offset = textMap.lineStartOffset(lineNumber);
-            final int length = textMap.lineLength(lineNumber);
-            return getCode().substring(offset, offset + length);
-        }
-
-        /**
-         * The number of text lines in the source.
-         */
-        public final int getLineCount() {
-            return checkTextMap().lineCount();
-        }
-
-        /**
-         * The 1-based number of the line that includes a 0-based character offset.
-         */
-        public final int getLineNumber(int offset) {
-            return checkTextMap().offsetToLine(offset);
-        }
-
-        /**
-         * The 0-based character offset at the start of a (1-based) numbered line.
-         */
-        public final int getLineStartOffset(int lineNumber) {
-            return checkTextMap().lineStartOffset(lineNumber);
-        }
-
-        /**
-         * The number of characters (not counting a possible terminating newline) in a (1-based)
-         * numbered line.
-         */
-        public final int getLineLength(int lineNumber) {
-            return checkTextMap().lineLength(lineNumber);
-        }
-
-        private TextMap checkTextMap() {
-            if (textMap == null) {
-                final String code = getCode();
-                if (code == null) {
-                    throw new RuntimeException("can't read file " + getName());
-                }
-                textMap = new TextMap(code);
-            }
-            return textMap;
-        }
-    }
-
-    public static class LiteralSourceImpl extends SourceImpl {
-
-        private final String name; // Name used originally to describe the source
-        private final String code;
-
-        public LiteralSourceImpl(String name, String code) {
-            this.name = name;
-            this.code = code;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public String getCode() {
-            return code;
-        }
-
-        @Override
-        public String getPath() {
-            return name;
-        }
-
-        @Override
-        public Reader getReader() {
-            return new StringReader(code);
-        }
-
-        @Override
-        protected void reset() {
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + name.hashCode();
-            result = prime * result + (code == null ? 0 : code.hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (!(obj instanceof LiteralSourceImpl)) {
-                return false;
-            }
-            LiteralSourceImpl other = (LiteralSourceImpl) obj;
-            return name.equals(other.name) && code.equals(other.code);
-        }
-
-    }
-
-    private static class FileSourceImpl extends SourceImpl {
-
-        private final File file;
-        private final String name; // Name used originally to describe the source
-        private final String path;  // Normalized path description of an actual file
-
-        private String code = null;  // A cache of the file's contents
-        private long timeStamp;      // timestamp of the cache in the file system
-
-        public FileSourceImpl(File file, String name, String path) {
-            this.file = file;
-            this.name = name;
-            this.path = path;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public String getCode() {
-            if (code == null || timeStamp != file.lastModified()) {
-                try {
-                    code = readCode(getReader());
-                    timeStamp = file.lastModified();
-                } catch (IOException e) {
-                }
-            }
-            return code;
-        }
-
-        @Override
-        public String getPath() {
-            return path;
-        }
-
-        @Override
-        public Reader getReader() {
-            if (code != null && timeStamp == file.lastModified()) {
-                return new StringReader(code);
-            }
-            try {
-                return new FileReader(file);
-            } catch (FileNotFoundException e) {
-                throw new RuntimeException("Can't find file " + path);
-            }
-        }
-
-        @Override
-        protected void reset() {
-            this.code = null;
-        }
-
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java	Fri May 30 15:09:09 2014 +0200
@@ -112,7 +112,7 @@
 
     /**
      * Support JDK8 langtools.
-     * 
+     *
      * @param annotationType
      */
     public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
@@ -121,7 +121,7 @@
 
     /**
      * Support for some JDK8 builds. (remove after jdk8 is released)
-     * 
+     *
      * @param annotationType
      */
     public <A extends Annotation> A[] getAnnotations(Class<A> annotationType) {
@@ -130,7 +130,7 @@
 
     /**
      * Support for some JDK8 builds. (remove after jdk8 is released)
-     * 
+     *
      * @param annotationType
      */
     public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri May 30 15:09:09 2014 +0200
@@ -49,6 +49,8 @@
     private static final String EXECUTE_POLYMORPHIC_NAME = "executePolymorphic0";
 
     private static final String UPDATE_TYPES_NAME = "updateTypes";
+    private static final String COPY_WITH_CONSTRUCTOR_NAME = "copyWithConstructor";
+    private static final String CREATE_SPECIALIZATION_NAME = "createSpecialization";
 
     public NodeCodeGenerator(ProcessorContext context) {
         super(context);
@@ -317,16 +319,16 @@
     /**
      * <pre>
      * variant1 $condition != null
-     * 
+     *
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     * 
+     *
      * variant2 $condition != null
      * $type $name = $value;
      * </pre>
-     * 
+     *
      * .
      */
     private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) {
@@ -834,7 +836,7 @@
             if (node.getSpecializations().isEmpty()) {
                 body.nullLiteral();
             } else {
-                body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0)));
+                body.startCall(nodeSpecializationClassName(node.getSpecializations().get(0)), CREATE_SPECIALIZATION_NAME);
                 for (VariableElement var : method.getParameters()) {
                     body.string(var.getSimpleName().toString());
                 }
@@ -865,7 +867,7 @@
             if (found == null) {
                 body.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
             } else {
-                body.startReturn().startNew(nodeSpecializationClassName(found)).startGroup().cast(baseClassName(node)).string(THIS_NODE_LOCAL_VAR_NAME).end().end().end();
+                body.startReturn().startCall(nodeSpecializationClassName(found), CREATE_SPECIALIZATION_NAME).startGroup().string(THIS_NODE_LOCAL_VAR_NAME).end().end().end();
             }
             return method;
         }
@@ -952,7 +954,6 @@
             if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) {
                 clazz.add(createGenericExecute(node, rootGroup));
             }
-
         }
 
         protected boolean needsInvokeCopyConstructorMethod() {
@@ -960,7 +961,7 @@
         }
 
         protected CodeExecutableElement createCopy(TypeMirror baseType, SpecializationData specialization) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), baseType, "copyWithConstructor");
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), baseType, COPY_WITH_CONSTRUCTOR_NAME);
             if (specialization == null) {
                 method.getModifiers().add(ABSTRACT);
             } else {
@@ -968,7 +969,7 @@
                 builder.startReturn();
                 builder.startNew(getElement().asType());
                 builder.string("this");
-                for (ActualParameter param : getImplicitTypeParamters(specialization)) {
+                for (ActualParameter param : getImplicitTypeParameters(specialization)) {
                     builder.string(implicitTypeName(param));
                 }
                 builder.end().end();
@@ -978,9 +979,8 @@
 
         private List<CodeExecutableElement> createImplicitChildrenAccessors() {
             NodeData node = getModel().getNode();
-            // Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>();
-            @SuppressWarnings("unchecked")
-            List<Set<TypeData>> expectTypes = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
+            List<Set<TypeData>> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null);
+            List<Set<TypeData>> expectTypes = new ArrayList<>(prototype);
 
             for (ExecutableTypeData executableType : node.getExecutableTypes()) {
                 for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
@@ -998,8 +998,7 @@
             }
 
             List<CodeExecutableElement> methods = new ArrayList<>();
-            @SuppressWarnings("unchecked")
-            List<Set<TypeData>> visitedList = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
+            List<Set<TypeData>> visitedList = new ArrayList<>(prototype);
             for (SpecializationData spec : node.getSpecializations()) {
                 int signatureIndex = -1;
                 for (ActualParameter param : spec.getParameters()) {
@@ -1740,7 +1739,7 @@
             } else {
                 replaceCall.startCall("replace");
             }
-            replaceCall.startGroup().startNew(className).string(source);
+            replaceCall.startGroup().cast(baseClassName(current.getNode())).startCall(className, CREATE_SPECIALIZATION_NAME).string(source);
             for (ActualParameter param : current.getSignatureParameters()) {
                 NodeChildData child = param.getSpecification().getExecution().getChild();
                 List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
@@ -1764,7 +1763,7 @@
             String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization());
             CodeTreeBuilder builder = parent.create();
 
-            builder.declaration(getElement().asType(), "currentCopy", currentNode + ".copyWithConstructor()");
+            builder.declaration(getElement().asType(), "currentCopy", currentNode + "." + COPY_WITH_CONSTRUCTOR_NAME + "()");
             for (ActualParameter param : getModel().getSignatureParameters()) {
                 NodeExecutionData execution = param.getSpecification().getExecution();
                 builder.startStatement().tree(createAccessChild(execution, "currentCopy")).string(" = ").nullLiteral().end();
@@ -1930,7 +1929,7 @@
             }
         }
 
-        protected final List<ActualParameter> getImplicitTypeParamters(SpecializationData model) {
+        protected final List<ActualParameter> getImplicitTypeParameters(SpecializationData model) {
             List<ActualParameter> parameter = new ArrayList<>();
             for (ActualParameter param : model.getSignatureParameters()) {
                 NodeChildData child = param.getSpecification().getExecution().getChild();
@@ -2548,6 +2547,18 @@
             if (needsInvokeCopyConstructorMethod()) {
                 clazz.add(createCopy(nodeGen.asType(), specialization));
             }
+
+            if (!specialization.isUninitialized() && specialization.getNode().needsRewrites(context)) {
+                clazz.add(createCopyConstructorFactoryMethod(nodeGen.asType(), specialization));
+            } else {
+                for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
+                    if (constructor.getParameters().size() == 1 && ((CodeVariableElement) constructor.getParameters().get(0)).getType().equals(nodeGen.asType())) {
+                        // skip copy constructor - not used
+                        continue;
+                    }
+                    clazz.add(createConstructorFactoryMethod(specialization, constructor));
+                }
+            }
         }
 
         protected void createConstructors(CodeTypeElement clazz) {
@@ -2581,7 +2592,7 @@
                     }
                 }
                 if (superConstructor != null) {
-                    for (ActualParameter param : getImplicitTypeParamters(getModel())) {
+                    for (ActualParameter param : getImplicitTypeParameters(getModel())) {
                         clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param)));
                         superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
 
@@ -2913,6 +2924,40 @@
             return builder.getRoot();
         }
 
+        protected CodeExecutableElement createCopyConstructorFactoryMethod(TypeMirror baseType, SpecializationData specialization) {
+            List<ActualParameter> implicitTypeParams = getImplicitTypeParameters(specialization);
+            CodeVariableElement[] parameters = new CodeVariableElement[implicitTypeParams.size() + 1];
+            int i = 0;
+            String baseName = "current";
+            parameters[i++] = new CodeVariableElement(specialization.getNode().getNodeType(), baseName);
+            for (ActualParameter implicitTypeParam : implicitTypeParams) {
+                parameters[i++] = new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(implicitTypeParam));
+            }
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), CREATE_SPECIALIZATION_NAME, parameters);
+            CodeTreeBuilder builder = method.createBuilder();
+            builder.startReturn();
+            builder.startNew(getElement().asType());
+            builder.startGroup().cast(baseType, CodeTreeBuilder.singleString(baseName)).end();
+            for (ActualParameter param : implicitTypeParams) {
+                builder.string(implicitTypeName(param));
+            }
+            builder.end().end();
+            return method;
+        }
+
+        protected CodeExecutableElement createConstructorFactoryMethod(SpecializationData specialization, ExecutableElement constructor) {
+            List<? extends VariableElement> parameters = constructor.getParameters();
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), CREATE_SPECIALIZATION_NAME,
+                            parameters.toArray(new CodeVariableElement[parameters.size()]));
+            CodeTreeBuilder builder = method.createBuilder();
+            builder.startReturn();
+            builder.startNew(getElement().asType());
+            for (VariableElement param : parameters) {
+                builder.string(((CodeVariableElement) param).getName());
+            }
+            builder.end().end();
+            return method;
+        }
     }
 
     private interface CodeBlock<T> {
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Fri May 30 15:09:09 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -54,20 +54,21 @@
 
     static class TestCase {
         protected final Description name;
-        protected final Source source;
+        protected final Path path;
+        protected final String sourceName;
         protected final String testInput;
         protected final String expectedOutput;
         protected String actualOutput;
 
-        protected TestCase(Class<?> testClass, String name, Source source, String testInput, String expectedOutput) {
-            this.name = Description.createTestDescription(testClass, name);
-            this.source = source;
+        protected TestCase(Class<?> testClass, String baseName, String sourceName, Path path, String testInput, String expectedOutput) {
+            this.name = Description.createTestDescription(testClass, baseName);
+            this.sourceName = sourceName;
+            this.path = path;
             this.testInput = testInput;
             this.expectedOutput = expectedOutput;
         }
     }
 
-    private final SourceManager sourceManager = new SourceManager();
     private final List<TestCase> testCases;
 
     public SLTestRunner(Class<?> runningClass) throws InitializationError {
@@ -89,7 +90,7 @@
         return testCases;
     }
 
-    protected List<TestCase> createTests(final Class<?> c) throws IOException, InitializationError {
+    protected static List<TestCase> createTests(final Class<?> c) throws IOException, InitializationError {
         SLTestSuite suite = c.getAnnotation(SLTestSuite.class);
         if (suite == null) {
             throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLTestSuite.class.getSimpleName(), c.getName(), SLTestRunner.class.getSimpleName()));
@@ -130,7 +131,7 @@
                         expectedOutput = readAllLines(outputFile);
                     }
 
-                    foundCases.add(new TestCase(c, baseName, sourceManager.get(sourceName, readAllLines(sourceFile)), testInput, expectedOutput));
+                    foundCases.add(new TestCase(c, baseName, sourceName, sourceFile, testInput, expectedOutput));
                 }
                 return FileVisitResult.CONTINUE;
             }
@@ -154,8 +155,9 @@
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         PrintStream printer = new PrintStream(out);
         try {
-            SLContext context = new SLContext(sourceManager, new BufferedReader(new StringReader(repeat(testCase.testInput, REPEATS))), printer);
-            SLMain.run(context, testCase.source, null, REPEATS);
+            SLContext context = new SLContext(new BufferedReader(new StringReader(repeat(testCase.testInput, REPEATS))), printer);
+            final Source source = SourceFactory.fromText(readAllLines(testCase.path), testCase.sourceName);
+            SLMain.run(context, source, null, REPEATS);
 
             String actualOutput = new String(out.toByteArray());
             Assert.assertEquals(repeat(testCase.expectedOutput, REPEATS), actualOutput);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Fri May 30 15:09:09 2014 +0200
@@ -27,6 +27,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.builtins.*;
@@ -117,13 +118,14 @@
      * The main entry point. Use the mx command "mx sl" to run it with the correct class path setup.
      */
     public static void main(String[] args) throws IOException {
-        SourceManager sourceManager = new SourceManager();
+
+        SLContext context = new SLContext(new BufferedReader(new InputStreamReader(System.in)), System.out);
 
         Source source;
         if (args.length == 0) {
-            source = sourceManager.get("stdin", System.in);
+            source = SourceFactory.fromReader(new InputStreamReader(System.in), "stdin");
         } else {
-            source = sourceManager.get(args[0]);
+            source = SourceFactory.fromFile(args[0]);
         }
 
         int repeats = 1;
@@ -131,7 +133,6 @@
             repeats = Integer.parseInt(args[1]);
         }
 
-        SLContext context = new SLContext(sourceManager, new BufferedReader(new InputStreamReader(System.in)), System.out);
         run(context, source, System.out, repeats);
     }
 
@@ -144,8 +145,16 @@
             logOutput.println("== running on " + Truffle.getRuntime().getName());
         }
 
+        final SourceCallback sourceCallback = context.getSourceCallback();
+
         /* Parse the SL source file. */
+        if (sourceCallback != null) {
+            sourceCallback.startLoading(source);
+        }
         Parser.parseSL(context, source);
+        if (sourceCallback != null) {
+            sourceCallback.endLoading(source);
+        }
         /* Lookup our main entry point, which is per definition always named "main". */
         SLFunction main = context.getFunctionRegistry().lookup("main");
         if (main.getCallTarget() == null) {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Fri May 30 15:09:09 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.parser.*;
 import com.oracle.truffle.sl.runtime.*;
 
@@ -44,7 +45,7 @@
 
     @SlowPath
     private static void doDefineFunction(SLContext context, String code) {
-        Source source = context.getSourceManager().get("[defineFunction]", code);
+        Source source = SourceFactory.fromText(code, "[defineFunction]");
         /* The same parsing code as for parsing the initial source. */
         Parser.parseSL(context, source);
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Fri May 30 15:09:09 2014 +0200
@@ -55,11 +55,11 @@
         return str.toString();
     }
 
-    private static void dumpFrame(StringBuilder str, CallTarget rootNode, Frame frame, boolean isVirtual) {
+    private static void dumpFrame(StringBuilder str, CallTarget callTarget, Frame frame, boolean isVirtual) {
         if (str.length() > 0) {
             str.append("\n");
         }
-        str.append("Frame: ").append(rootNode).append(isVirtual ? " (virtual)" : "");
+        str.append("Frame: ").append(callTarget).append(isVirtual ? " (virtual)" : "");
         FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
         for (FrameSlot s : frameDescriptor.getSlots()) {
             str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s));
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Fri May 30 15:09:09 2014 +0200
@@ -35,6 +35,7 @@
  * type system for all subclasses.
  */
 @TypeSystemReference(SLTypes.class)
+@NodeInfo(description = "The abstract base node for all expressions")
 public abstract class SLExpressionNode extends SLStatementNode {
 
     /**
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Fri May 30 15:09:09 2014 +0200
@@ -33,6 +33,7 @@
  * builtin functions, the {@link #bodyNode} is a subclass of {@link SLBuiltinNode}. For user-defined
  * functions, the {@link #bodyNode} is a {@link SLFunctionBodyNode}.
  */
+@NodeInfo(language = "Simple Language", description = "The root of all Simple Language execution trees")
 public final class SLRootNode extends RootNode {
 
     /** The function body that is executed, and specialized during execution. */
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Fri May 30 15:09:09 2014 +0200
@@ -30,6 +30,7 @@
  * statements, i.e., without returning a value. The {@link VirtualFrame} provides access to the
  * local variables.
  */
+@NodeInfo(language = "Simple Language", description = "The abstract base node for all statements")
 public abstract class SLStatementNode extends Node {
 
     /**
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Fri May 30 15:09:09 2014 +0200
@@ -44,7 +44,7 @@
  * <li>After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U}
  * <li>After execution of function {@code f3}: {@code I->G}
  * </ol>
- * */
+ */
 public abstract class SLAbstractDispatchNode extends Node {
 
     protected static final int INLINE_CACHE_SIZE = 2;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Fri May 30 15:09:09 2014 +0200
@@ -30,7 +30,7 @@
 /**
  * A statement node that just executes a list of other statements.
  */
-@NodeInfo(shortName = "block")
+@NodeInfo(shortName = "block", description = "The node implementing a source code block")
 public final class SLBlockNode extends SLStatementNode {
 
     /**
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java	Fri May 30 15:09:09 2014 +0200
@@ -32,7 +32,7 @@
  * breaking out. This is done by throwing an {@link SLBreakException exception} that is caught by
  * the {@link SLWhileNode#executeVoid loop node}.
  */
-@NodeInfo(shortName = "break")
+@NodeInfo(shortName = "break", description = "The node implementing a break statement")
 public final class SLBreakNode extends SLStatementNode {
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java	Fri May 30 15:09:09 2014 +0200
@@ -32,7 +32,7 @@
  * are continuing. This is done by throwing an {@link SLContinueException exception} that is caught
  * by the {@link SLWhileNode#executeVoid loop node}.
  */
-@NodeInfo(shortName = "continue")
+@NodeInfo(shortName = "continue", description = "The node implementing a continue statement")
 public final class SLContinueNode extends SLStatementNode {
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Fri May 30 15:09:09 2014 +0200
@@ -28,7 +28,7 @@
 import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.sl.nodes.*;
 
-@NodeInfo(shortName = "if")
+@NodeInfo(shortName = "if", description = "The node implementing a condional statement")
 public final class SLIfNode extends SLStatementNode {
 
     /**
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Fri May 30 15:09:09 2014 +0200
@@ -34,7 +34,7 @@
  * caught by the {@link SLFunctionBodyNode#executeGeneric function body}. The exception transports
  * the return value.
  */
-@NodeInfo(shortName = "return")
+@NodeInfo(shortName = "return", description = "The node implementing a return statement")
 public final class SLReturnNode extends SLStatementNode {
 
     @Child private SLExpressionNode valueNode;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,7 @@
 import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.sl.nodes.*;
 
-@NodeInfo(shortName = "while")
+@NodeInfo(shortName = "while", description = "The node implementing a while loop")
 public final class SLWhileNode extends SLStatementNode {
 
     /**
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java	Fri May 30 15:09:09 2014 +0200
@@ -25,6 +25,7 @@
 import java.math.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
@@ -41,6 +42,7 @@
     }
 
     @Specialization
+    @SlowPath
     protected BigInteger mul(BigInteger left, BigInteger right) {
         return left.multiply(right);
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Fri May 30 15:09:09 2014 +0200
@@ -27,7 +27,6 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.call.*;
@@ -243,7 +242,7 @@
         int startLine = t.line;
         int startColumn = t.col;
         int charLength = t.val.length();
-        SourceSection sourceSection = new DefaultSourceSection(source, functionName, startLine, startColumn, 0, charLength);
+        SourceSection sourceSection = source.createSection(functionName, startLine, startColumn, 0, charLength);
 
         node.assignSourceSection(sourceSection);
         return node;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Fri May 30 15:09:09 2014 +0200
@@ -24,10 +24,11 @@
 
 import java.io.*;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.local.*;
@@ -43,26 +44,27 @@
  * However, if two separate scripts run in one Java VM at the same time, they have a different
  * context. Therefore, the context is not a singleton.
  */
-public final class SLContext {
-    private final SourceManager sourceManager;
+public final class SLContext extends ExecutionContext {
     private final BufferedReader input;
     private final PrintStream output;
     private final SLFunctionRegistry functionRegistry;
+    private SourceCallback sourceCallback = null;
 
-    public SLContext(SourceManager sourceManager, BufferedReader input, PrintStream output) {
-        this.sourceManager = sourceManager;
+    public SLContext(BufferedReader input, PrintStream output) {
         this.input = input;
         this.output = output;
         this.functionRegistry = new SLFunctionRegistry();
-
         installBuiltins();
     }
 
-    /**
-     * Returns the source manger that controls all SL source code that is executed.
-     */
-    public SourceManager getSourceManager() {
-        return sourceManager;
+    @Override
+    public String getLanguageShortName() {
+        return "Simple";
+    }
+
+    @Override
+    public void setSourceCallback(SourceCallback sourceCallback) {
+        this.sourceCallback = sourceCallback;
     }
 
     /**
@@ -88,6 +90,10 @@
         return functionRegistry;
     }
 
+    public SourceCallback getSourceCallback() {
+        return sourceCallback;
+    }
+
     /**
      * Adds all builtin functions to the {@link SLFunctionRegistry}. This method lists all
      * {@link SLBuiltinNode builtin implementation classes}.
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Fri May 30 13:23:53 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Fri May 30 15:09:09 2014 +0200
@@ -29,7 +29,7 @@
  * there is always the danger of a spurious {@link NullPointerException}. Representing the guest
  * language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended
  * practice.
- * */
+ */
 public final class SLNull {
 
     /**
--- a/hotspot/.cproject	Fri May 30 13:23:53 2014 +0200
+++ b/hotspot/.cproject	Fri May 30 15:09:09 2014 +0200
@@ -1,7 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?fileVersion 4.0.0?>
-
-<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
 	<storageModule moduleId="org.eclipse.cdt.core.settings">
 		<cconfiguration id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881">
 			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881" moduleId="org.eclipse.cdt.core.settings" name="Default">
@@ -27,7 +25,9 @@
 							</builder>
 							<tool id="cdt.managedbuild.tool.gnu.archiver.base.1094883386" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
 							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
-								<option id="gnu.cpp.compiler.option.include.paths.801956928" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths"/>
+								<option id="gnu.cpp.compiler.option.include.paths.801956928" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/com.oracle.graal.hotspot/src_gen/hotspot}&quot;"/>
+								</option>
 								<option id="gnu.cpp.compiler.option.preprocessor.def.634868600" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="_LP64=1"/>
 									<listOptionValue builtIn="false" value="COMPILER1=1"/>
@@ -74,11 +74,6 @@
 							</tool>
 						</toolChain>
 					</folderInfo>
-					<fileInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.426128354" name="addnode.cpp" rcbsApplicability="disable" resourcePath="vm/opto/addnode.cpp" toolsToInvoke="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057.211119144">
-						<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057.211119144" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057">
-							<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.202578082" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
-						</tool>
-					</fileInfo>
 					<sourceEntries>
 						<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
 					</sourceEntries>
--- a/hotspot/.project	Fri May 30 13:23:53 2014 +0200
+++ b/hotspot/.project	Fri May 30 15:09:09 2014 +0200
@@ -96,7 +96,17 @@
 			<locationURI>PARENT-1-PROJECT_LOC/src/os_cpu/bsd_x86/vm</locationURI>
 		</link>
 		<link>
-			<name>generated</name>
+			<name>generated_compiler1</name>
+			<type>2</type>
+			<locationURI>PARENT-1-PROJECT_LOC/build/linux/linux_amd64_compiler1/generated</locationURI>
+		</link>
+		<link>
+			<name>generated_compiler2</name>
+			<type>2</type>
+			<locationURI>PARENT-1-PROJECT_LOC/build/linux/linux_amd64_compiler2/generated</locationURI>
+		</link>
+		<link>
+			<name>generated_graal</name>
 			<type>2</type>
 			<locationURI>PARENT-1-PROJECT_LOC/build/linux/linux_amd64_graal/generated</locationURI>
 		</link>
--- a/make/bsd/makefiles/vm.make	Fri May 30 13:23:53 2014 +0200
+++ b/make/bsd/makefiles/vm.make	Fri May 30 15:09:09 2014 +0200
@@ -229,6 +229,7 @@
 else
   GRAAL_SPECIFIC_FILES   :=
   GRAAL_SPECIFIC_GPU_FILES  :=
+  Src_Dirs_I += $(HS_COMMON_SRC)/../graal/com.oracle.graal.hotspot/src_gen/hotspot
 endif
 
 # Always exclude these.
--- a/make/linux/makefiles/vm.make	Fri May 30 13:23:53 2014 +0200
+++ b/make/linux/makefiles/vm.make	Fri May 30 15:09:09 2014 +0200
@@ -211,6 +211,7 @@
 else
   GRAAL_SPECIFIC_FILES   :=
   GRAAL_SPECIFIC_GPU_FILES   :=
+  Src_Dirs_I += $(HS_COMMON_SRC)/../graal/com.oracle.graal.hotspot/src_gen/hotspot
 endif
 
 # Always exclude these.
--- a/make/solaris/makefiles/vm.make	Fri May 30 13:23:53 2014 +0200
+++ b/make/solaris/makefiles/vm.make	Fri May 30 15:09:09 2014 +0200
@@ -229,6 +229,7 @@
 else
   GRAAL_SPECIFIC_FILES   :=
   GRAAL_SPECIFIC_GPU_FILES   :=
+  Src_Dirs_I += $(HS_COMMON_SRC)/../graal/com.oracle.graal.hotspot/src_gen/hotspot
 endif
 
 # Always exclude these.
--- a/make/windows/makefiles/projectcreator.make	Fri May 30 13:23:53 2014 +0200
+++ b/make/windows/makefiles/projectcreator.make	Fri May 30 15:09:09 2014 +0200
@@ -57,6 +57,7 @@
         -relativeInclude src\os_cpu\windows_$(Platform_arch)\vm \
         -relativeInclude src\cpu\$(Platform_arch)\vm \
         -relativeInclude src\gpu \
+        -relativeInclude graal\com.oracle.graal.hotspot\src_gen\hotspot \
         -absoluteInclude $(HOTSPOTBUILDSPACE)/%f/generated \
         -relativeSrcInclude src \
         -absoluteSrcInclude $(HOTSPOTBUILDSPACE) \
@@ -151,7 +152,7 @@
 
 ProjectCreatorIDEOptionsIgnoreGraal=\
  -ignorePath_TARGET src/share/vm/graal \
- -ignorePath_TARGET graal/generated \
+ -ignorePath_TARGET graal\com.oracle.graal.hotspot\src_gen\hotspot \
  -ignorePath_TARGET vm/graal
 
 ProjectCreatorIDEOptionsIgnoreCompiler2=\
@@ -175,7 +176,6 @@
 ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \
  -define_compiler1 COMPILER1 \
  -define_compiler1 GRAAL \
- -ignorePath_compiler1 graal/generated \
  $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1)
 
 ##################################################
@@ -195,7 +195,6 @@
  -define_compiler2 COMPILER1 \
  -define_compiler2 COMPILER2 \
  -define_compiler2 GRAAL \
- -ignorePath_compiler2 graal/generated \
  -additionalFile_compiler2 $(Platform_arch_model).ad \
  -additionalFile_compiler2 ad_$(Platform_arch_model).cpp \
  -additionalFile_compiler2 ad_$(Platform_arch_model).hpp \
--- a/mx.cmd	Fri May 30 13:23:53 2014 +0200
+++ b/mx.cmd	Fri May 30 15:09:09 2014 +0200
@@ -1,1 +1,1 @@
-python mxtool/mx.py %*
+python %~dp0/mxtool/mx.py %*
--- a/mx/JUnitWrapper.java	Fri May 30 13:23:53 2014 +0200
+++ b/mx/JUnitWrapper.java	Fri May 30 15:09:09 2014 +0200
@@ -21,20 +21,19 @@
  * questions.
  */
 
+
 /* Execute testcases by reading names from a given file, due to limits of
  * the operating system regarding command line size (windows: 32k,
  * linux [depending on the settings]: ~2097k)
  * see http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx
  */
-
 import org.apache.tools.ant.*;
 import org.apache.tools.ant.taskdefs.optional.junit.*;
 import org.apache.tools.ant.taskdefs.optional.junit.FormatterElement.TypeAttribute;
 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.*;
 import org.apache.tools.ant.types.*;
 import org.apache.tools.ant.types.selectors.*;
-import org.junit.runner.*;
-
+import com.oracle.graal.test.*;
 import java.io.*;
 import java.util.*;
 
--- a/mx/mx_graal.py	Fri May 30 13:23:53 2014 +0200
+++ b/mx/mx_graal.py	Fri May 30 15:09:09 2014 +0200
@@ -26,16 +26,16 @@
 #
 # ----------------------------------------------------------------------------------------------------
 
-import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO
+import os, stat, errno, sys, shutil, zipfile, tarfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO, socket
 from os.path import join, exists, dirname, basename, getmtime
 from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER
 from outputparser import OutputParser, ValuesMatcher
-from fnmatch import fnmatch
 import mx
 import xml.dom.minidom
 import sanitycheck
 import itertools
 import json, textwrap
+import fnmatch
 
 # This works because when mx loads this file, it makes sure __file__ gets an absolute path
 _graal_home = dirname(dirname(__file__))
@@ -46,8 +46,8 @@
 """ The VMs that can be built and run along with an optional description. Only VMs with a
     description are listed in the dialogue for setting the default VM (see _get_vm()). """
 _vmChoices = {
-    'graal' : 'All compilation is performed with Graal. This includes bootstrapping Graal itself unless -XX:-BootstrapGraal is used.',
-    'server' : 'Normal compilation is performed with the tiered system (i.e., client + server), Truffle compilation is performed with Graal. Use this for optimal Truffle performance.',
+    'graal' : 'Normal compilation is performed with a tiered system (C1 + Graal), Truffle compilation is performed with Graal.',
+    'server' : 'Normal compilation is performed with a tiered system (C1 + C2), Truffle compilation is performed with Graal. Use this for optimal Truffle performance.',
     'client' : None,  # normal compilation with client compiler, explicit compilation (e.g., by Truffle) with Graal
     'server-nograal' : None,  # all compilation with tiered system (i.e., client + server), Graal omitted
     'client-nograal' : None,  # all compilation with client compiler, Graal omitted
@@ -80,8 +80,7 @@
 
 _make_eclipse_launch = False
 
-# @CallerSensitive introduced in 7u25
-_minVersion = mx.VersionSpec('1.7.0_25')
+_minVersion = mx.VersionSpec('1.8')
 
 JDK_UNIX_PERMISSIONS = 0755
 
@@ -150,10 +149,19 @@
 def clean(args):
     """clean the GraalVM source tree"""
     opts = mx.clean(args, parser=ArgumentParser(prog='mx clean'))
+
     if opts.native:
+        def handleRemoveReadonly(func, path, exc):
+            excvalue = exc[1]
+            if mx.get_os() == 'windows' and func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
+                os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  # 0777
+                func(path)
+            else:
+                raise
+
         def rmIfExists(name):
             if os.path.isdir(name):
-                shutil.rmtree(name)
+                shutil.rmtree(name, ignore_errors=False, onerror=handleRemoveReadonly)
             elif os.path.isfile(name):
                 os.unlink(name)
 
@@ -163,49 +171,124 @@
         rmIfExists(mx.distribution('GRAAL').path)
 
 def export(args):
-    """create a GraalVM zip file for distribution"""
+    """create archives of builds split by vmbuild and vm"""
 
     parser = ArgumentParser(prog='mx export')
-    parser.add_argument('--omit-vm-build', action='store_false', dest='vmbuild', help='omit VM build step')
-    parser.add_argument('--omit-dist-init', action='store_false', dest='distInit', help='omit class files and IDE configurations from distribution')
-    parser.add_argument('zipfile', nargs=REMAINDER, metavar='zipfile')
-
     args = parser.parse_args(args)
 
-    tmp = tempfile.mkdtemp(prefix='tmp', dir=_graal_home)
-    if args.vmbuild:
-        # Make sure the product VM binary is up to date
-        with VM(vmbuild='product'):
-            build([])
+    # collect data about export
+    infos = dict()
+    infos['timestamp'] = time.time()
+
+    hgcfg = mx.HgConfig()
+    hgcfg.check()
+    infos['revision'] = hgcfg.tip('.') + ('+' if hgcfg.isDirty('.') else '')
+    # TODO: infos['repository']
+
+    infos['jdkversion'] = str(mx.java().version)
+
+    infos['architecture'] = _arch()
+    infos['platform'] = mx.get_os()
+
+    if mx.get_os != 'windows':
+        pass
+        # infos['ccompiler']
+        # infos['linker']
+
+    infos['hostname'] = socket.gethostname()
 
-    mx.log('Copying Java sources and mx files...')
-    mx.run(('hg archive -I graal -I mx -I mxtool -I mx.sh ' + tmp).split())
+    def _writeJson(suffix, properties):
+        d = infos.copy()
+        for k, v in properties.iteritems():
+            assert not d.has_key(k)
+            d[k] = v
+
+        jsonFileName = 'export-' + suffix + '.json'
+        with open(jsonFileName, 'w') as f:
+            print >> f, json.dumps(d)
+        return jsonFileName
+
+
+    def _genFileName(archivtype, middle):
+        idPrefix = infos['revision'] + '_'
+        idSuffix = '.tar.gz'
+        return join(_graal_home, "graalvm_" + archivtype + "_" + idPrefix + middle + idSuffix)
+
+    def _genFileArchPlatformName(archivtype, middle):
+        return _genFileName(archivtype, infos['platform'] + '_' + infos['architecture'] + '_' + middle)
+
+
+    # archive different build types of hotspot
+    for vmBuild in _vmbuildChoices:
+        jdkpath = join(_jdksDir(), vmBuild)
+        if not exists(jdkpath):
+            mx.logv("skipping " + vmBuild)
+            continue
 
-    # Copy the GraalVM JDK
-    mx.log('Copying GraalVM JDK...')
-    src = _jdk()
-    dst = join(tmp, basename(src))
-    shutil.copytree(src, dst)
-    zfName = join(_graal_home, 'graalvm-' + mx.get_os() + '.zip')
-    zf = zipfile.ZipFile(zfName, 'w')
-    for root, _, files in os.walk(tmp):
-        for f in files:
-            name = join(root, f)
-            arcname = name[len(tmp) + 1:]
-            zf.write(join(tmp, name), arcname)
+        tarName = _genFileArchPlatformName('basejdk', vmBuild)
+        mx.logv("creating basejdk " + tarName)
+        vmSet = set()
+        with tarfile.open(tarName, 'w:gz') as tar:
+            for root, _, files in os.walk(jdkpath):
+                if basename(root) in _vmChoices.keys():
+                    # TODO: add some assert to check path assumption
+                    vmSet.add(root)
+                    continue
+
+                for f in files:
+                    name = join(root, f)
+                    # print name
+                    tar.add(name, name)
+
+            n = _writeJson("basejdk-" + vmBuild, {'vmbuild' : vmBuild})
+            tar.add(n, n)
+
+        # create a separate archive for each VM
+        for vm in vmSet:
+            bVm = basename(vm)
+            vmTarName = _genFileArchPlatformName('vm', vmBuild + '_' + bVm)
+            mx.logv("creating vm " + vmTarName)
 
-    # create class files and IDE configurations
-    if args.distInit:
-        mx.log('Creating class files...')
-        mx.run('mx build'.split(), cwd=tmp)
-        mx.log('Creating IDE configurations...')
-        mx.run('mx ideinit'.split(), cwd=tmp)
+            debugFiles = set()
+            with tarfile.open(vmTarName, 'w:gz') as tar:
+                for root, _, files in os.walk(vm):
+                    for f in files:
+                        # TODO: mac, windows, solaris?
+                        if any(map(f.endswith, [".debuginfo"])):
+                            debugFiles.add(f)
+                        else:
+                            name = join(root, f)
+                            # print name
+                            tar.add(name, name)
+
+                n = _writeJson("vm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+                tar.add(n, n)
 
-    # clean up temp directory
-    mx.log('Cleaning up...')
-    shutil.rmtree(tmp)
+            if len(debugFiles) > 0:
+                debugTarName = _genFileArchPlatformName('debugfilesvm', vmBuild + '_' + bVm)
+                mx.logv("creating debugfilesvm " + debugTarName)
+                with tarfile.open(debugTarName, 'w:gz') as tar:
+                    for f in debugFiles:
+                        name = join(root, f)
+                        # print name
+                        tar.add(name, name)
+
+                    n = _writeJson("debugfilesvm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+                    tar.add(n, n)
 
-    mx.log('Created distribution in ' + zfName)
+    # graal directory
+    graalDirTarName = _genFileName('classfiles', 'javac')
+    mx.logv("creating graal " + graalDirTarName)
+    with tarfile.open(graalDirTarName, 'w:gz') as tar:
+        for root, _, files in os.walk("graal"):
+            for f in [f for f in files if not f.endswith('.java')]:
+                name = join(root, f)
+                # print name
+                tar.add(name, name)
+
+        n = _writeJson("graal", {'javacompiler' : 'javac'})
+        tar.add(n, n)
+
 
 def _run_benchmark(args, availableBenchmarks, runBenchmark):
 
@@ -401,8 +484,21 @@
         if exists(toDelete):
             os.unlink(toDelete)
 
+def _update_graalRuntime_inline_hpp(graalJar):
+    p = mx.project('com.oracle.graal.hotspot.sourcegen')
+    mainClass = 'com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp'
+    if exists(join(p.output_dir(), mainClass.replace('.', os.sep) + '.class')):
+        hsSrcGenDir = join(mx.project('com.oracle.graal.hotspot').source_gen_dir(), 'hotspot')
+        if not exists(hsSrcGenDir):
+            os.makedirs(hsSrcGenDir)
+
+        tmp = StringIO.StringIO()
+        mx.run_java(['-cp', '{}{}{}'.format(graalJar, os.pathsep, p.output_dir()), mainClass], out=tmp.write)
+        mx.update_file(join(hsSrcGenDir, 'graalRuntime.inline.hpp'), tmp.getvalue())
+
 def _installGraalJarInJdks(graalDist):
     graalJar = graalDist.path
+    _update_graalRuntime_inline_hpp(graalJar)
     jdks = _jdksDir()
 
     if exists(jdks):
@@ -607,7 +703,7 @@
             mustBuild = False
             timestamp = os.path.getmtime(timestampFile)
             sources = []
-            for d in ['src', 'make']:
+            for d in ['src', 'make', join('graal', 'com.oracle.graal.hotspot', 'src_gen', 'hotspot')]:
                 for root, dirnames, files in os.walk(join(_graal_home, d)):
                     # ignore <graal>/src/share/tools
                     if root == join(_graal_home, 'src', 'share'):
@@ -829,7 +925,7 @@
     else:
         return [], args
 
-def _run_tests(args, harness, annotations, testfile, whitelist):
+def _run_tests(args, harness, annotations, testfile, whitelist, regex):
 
 
     vmArgs, tests = _extract_VM_args(args)
@@ -853,7 +949,7 @@
         for t in tests:
             found = False
             for c, p in candidates.iteritems():
-                if fnmatch(c, t):
+                if fnmatch.fnmatch(c, t):
                     found = True
                     classes.append(c)
                     projs.add(p.name)
@@ -862,7 +958,10 @@
         projectscp = mx.classpath(projs)
 
     if whitelist:
-        classes = list(set(classes) & set(whitelist))
+        classes = [c for c in classes if any((glob.match(c) for glob in whitelist))]
+
+    if regex:
+        classes = [c for c in classes if re.search(regex, c)]
 
     if len(classes) != 0:
         f_testfile = open(testfile, 'w')
@@ -871,7 +970,7 @@
         f_testfile.close()
         harness(projectscp, vmArgs)
 
-def _unittest(args, annotations, prefixcp="", whitelist=None):
+def _unittest(args, annotations, prefixcp="", whitelist=None, verbose=False, enable_timing=False, regex=None, color=False, eager_stacktrace=False, gc_after_test=False):
     mxdir = dirname(__file__)
     name = 'JUnitWrapper'
     javaSource = join(mxdir, name + '.java')
@@ -880,11 +979,25 @@
     if testfile is None:
         (_, testfile) = tempfile.mkstemp(".testclasses", "graal")
         os.close(_)
+    corecp = mx.classpath(['com.oracle.graal.test', 'ant'])
+
+    if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
+        subprocess.check_call([mx.java().javac, '-cp', corecp, '-d', mxdir, javaSource])
+
+    coreArgs = []
+    if verbose:
+        coreArgs.append('-JUnitVerbose')
+    if enable_timing:
+        coreArgs.append('-JUnitEnableTiming')
+    if color:
+        coreArgs.append('-JUnitColor')
+    if eager_stacktrace:
+        coreArgs.append('-JUnitEagerStackTrace')
+    if gc_after_test:
+        coreArgs.append('-JUnitGCAfterTest')
+
 
     def harness(projectscp, vmArgs):
-        projectscp = mx.classpath("ant") + os.pathsep + projectscp 
-        if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
-            subprocess.check_call([mx.java().javac, '-cp', projectscp, '-d', mxdir, javaSource])
         if _get_vm() != 'graal':
             prefixArgs = ['-esa', '-ea']
         else:
@@ -894,12 +1007,12 @@
         if len(testclasses) == 1:
             # Execute Junit directly when one test is being run. This simplifies
             # replaying the VM execution in a native debugger (e.g., gdb).
-            vm(prefixArgs + vmArgs + ['-cp', prefixcp + projectscp, 'org.junit.runner.JUnitCore'] + testclasses)
+            vm(prefixArgs + vmArgs + ['-cp', prefixcp + corecp + ':' + projectscp, 'com.oracle.graal.test.GraalJUnitCore'] + coreArgs + testclasses)
         else:
-            vm(prefixArgs + vmArgs + ['-cp', prefixcp + projectscp + os.pathsep + mxdir, name] + [testfile])
+            vm(prefixArgs + vmArgs + ['-cp', prefixcp + corecp + ':' + projectscp + os.pathsep + mxdir, name] + [testfile] + coreArgs)
 
     try:
-        _run_tests(args, harness, annotations, testfile, whitelist)
+        _run_tests(args, harness, annotations, testfile, whitelist, regex)
     finally:
         if os.environ.get('MX_TESTFILE') is None:
             os.remove(testfile)
@@ -907,10 +1020,14 @@
 _unittestHelpSuffix = """
     Unittest options:
 
-      --short-only           run short testcases only
-      --long-only            run long testcases only
-      --baseline-whitelist   run only testcases which are known to
-                             work with the baseline compiler
+      --whitelist <file>     run only testcases which are included
+                             in the given whitelist
+      --verbose              enable verbose JUnit output
+      --enable-timing        enable JUnit test timing
+      --regex <regex>        run only testcases matching a regular expression
+      --color                enable colors output
+      --eager-stacktrace     print stacktrace eagerly
+      --gc-after-test        force a GC after each test
 
     To avoid conflicts with VM options '--' can be used as delimiter.
 
@@ -947,10 +1064,13 @@
           formatter_class=RawDescriptionHelpFormatter,
           epilog=_unittestHelpSuffix,
         )
-    group = parser.add_mutually_exclusive_group()
-    group.add_argument('--short-only', action='store_true', help='run short testcases only')
-    group.add_argument('--long-only', action='store_true', help='run long testcases only')
-    parser.add_argument('--baseline-whitelist', action='store_true', help='run baseline testcases only')
+    parser.add_argument('--whitelist', help='run testcases specified in whitelist only', metavar='<path>')
+    parser.add_argument('--verbose', help='enable verbose JUnit output', action='store_true')
+    parser.add_argument('--enable-timing', help='enable JUnit test timing', action='store_true')
+    parser.add_argument('--regex', help='run only testcases matching a regular expression', metavar='<regex>')
+    parser.add_argument('--color', help='enable color output', action='store_true')
+    parser.add_argument('--eager-stacktrace', help='print stacktrace eagerly', action='store_true')
+    parser.add_argument('--gc-after-test', help='force a GC after each test', action='store_true')
 
     ut_args = []
     delimiter = False
@@ -969,34 +1089,19 @@
         # parse all know arguments
         parsed_args, args = parser.parse_known_args(ut_args)
 
-    whitelist = None
-    if parsed_args.baseline_whitelist:
-        baseline_whitelist_file = 'test/baseline_whitelist.txt'
+    if parsed_args.whitelist:
         try:
-            with open(join(_graal_home, baseline_whitelist_file)) as fp:
-                whitelist = [l.rstrip() for l in fp.readlines()]
+            with open(join(_graal_home, parsed_args.whitelist)) as fp:
+                parsed_args.whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
         except IOError:
-            mx.log('warning: could not read baseline whitelist: ' + baseline_whitelist_file)
+            mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
 
-    if parsed_args.long_only:
-        annotations = ['@LongTest', '@Parameters']
-    elif parsed_args.short_only:
-        annotations = ['@Test']
-    else:
-        annotations = ['@Test', '@LongTest', '@Parameters']
-
-    _unittest(args, annotations, whitelist=whitelist)
+    _unittest(args, ['@Test', '@Parameters'], **parsed_args.__dict__)
 
 def shortunittest(args):
-    """alias for 'unittest --short-only'{0}"""
-
-    args.insert(0, '--short-only')
-    unittest(args)
+    """alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}"""
 
-def longunittest(args):
-    """alias for 'unittest --long-only'{0}"""
-
-    args.insert(0, '--long-only')
+    args = ['--whitelist', 'test/whitelist_shortunittest.txt'] + args
     unittest(args)
 
 def buildvms(args):
@@ -1103,7 +1208,12 @@
 
     with VM('server', 'product'):  # hosted mode
         t = Task('UnitTests:hosted-product')
-        unittest([])
+        unittest(['--enable-timing', '--verbose'])
+        tasks.append(t.stop())
+
+    with VM('server', 'product'):  # hosted mode
+        t = Task('UnitTests-BaselineCompiler:hosted-product')
+        unittest(['--enable-timing', '--verbose', '--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler'])
         tasks.append(t.stop())
 
     for vmbuild in ['fastdebug', 'product']:
@@ -1201,13 +1311,13 @@
 
         if mx.get_env('JDT'):
             t = Task('BuildJavaWithEcj')
-            build(['--no-native', '--jdt-warning-as-error'])
+            build(['-p', '--no-native', '--jdt-warning-as-error'])
             tasks.append(t.stop())
 
             _clean('CleanAfterEcjBuild')
 
         t = Task('BuildJavaWithJavac')
-        build(['--no-native', '--force-javac'])
+        build(['-p', '--no-native', '--force-javac'])
         tasks.append(t.stop())
 
         t = Task('Checkheaders')
@@ -1307,10 +1417,10 @@
     else:
         executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer')
 
-    archive = join(libpath, 'c1visualizer.zip')
-    if not exists(executable):
+    archive = join(libpath, 'c1visualizer_2014-04-22.zip')
+    if not exists(executable) or not exists(archive):
         if not exists(archive):
-            mx.download(archive, ['https://java.net/downloads/c1visualizer/c1visualizer.zip'])
+            mx.download(archive, ['https://java.net/downloads/c1visualizer/c1visualizer_2014-04-22.zip'])
         zf = zipfile.ZipFile(archive, 'r')
         zf.extractall(libpath)
 
@@ -1449,10 +1559,12 @@
                     if not mx.library(name, fatalIfMissing=False):
                         mx.log('Skipping ' + groupId + '.' + artifactId + '.jar as ' + name + ' cannot be resolved')
                         return
-        d = mx.Distribution(graalSuite, name=artifactId, path=path, sourcesPath=path, deps=deps, excludedLibs=[])
+        d = mx.Distribution(graalSuite, name=artifactId, path=path, sourcesPath=path, deps=deps, mainClass=None, excludedDependencies=[], distDependencies=[])
         d.make_archive()
-        cmd = ['mvn', '-q', 'install:install-file', '-DgroupId=' + groupId, '-DartifactId=' + artifactId,
+        cmd = ['mvn', 'install:install-file', '-DgroupId=' + groupId, '-DartifactId=' + artifactId,
                '-Dversion=1.0-SNAPSHOT', '-Dpackaging=jar', '-Dfile=' + d.path]
+        if not mx._opts.verbose:
+            cmd.append('-q')
         if args.settings:
             cmd = cmd + ['-s', args.settings]
         mx.run(cmd)
@@ -1483,6 +1595,9 @@
     jmhPath = _get_jmh_path()
     mx.log('JMH benchmarks: ' + jmhPath)
 
+    # Ensure the mx injected dependencies are up to date
+    makejmhdeps(['-p'] + (['-s', args.settings] if args.settings else []))
+
     timestamp = mx.TimeStampFile(join(_graal_home, 'mx', 'jmh', jmhPath.replace(os.sep, '_') + '.timestamp'))
     mustBuild = args.clean
     if not mustBuild:
@@ -1504,7 +1619,6 @@
         env['JAVA_HOME'] = _jdk(vmToCheck='server')
         env['MAVEN_OPTS'] = '-server'
         mx.log("Building benchmarks...")
-        makejmhdeps(['-p'] + (['-s', args.settings] if args.settings else []))
         cmd = ['mvn']
         if args.settings:
             cmd = cmd + ['-s', args.settings]
@@ -1532,8 +1646,11 @@
 
     benchmarks = [b for b in benchmarksAndJsons if not b.startswith('{')]
     jmhArgJsons = [b for b in benchmarksAndJsons if b.startswith('{')]
-
-    jmhArgs = {'-rff' : join(_graal_home, 'mx', 'jmh', 'jmh.out'), '-v' : 'EXTRA' if mx._opts.verbose else 'NORMAL'}
+    jmhOutDir = join(_graal_home, 'mx', 'jmh')
+    if not exists(jmhOutDir):
+        os.makedirs(jmhOutDir)
+    jmhOut = join(jmhOutDir, 'jmh.out')
+    jmhArgs = {'-rff' : jmhOut, '-v' : 'EXTRA' if mx._opts.verbose else 'NORMAL'}
 
     # e.g. '{"-wi" : 20}'
     for j in jmhArgJsons:
@@ -1561,7 +1678,8 @@
 
         microJar = os.path.join(absoluteMicro, "target", "microbenchmarks.jar")
         if not exists(microJar):
-            mx.abort('Missing ' + microJar + ' - please run "mx buildjmh"')
+            mx.log('Missing ' + microJar + ' - please run "mx buildjmh"')
+            continue
         if benchmarks:
             def _addBenchmark(x):
                 if x.startswith("Benchmark:"):
@@ -1710,27 +1828,13 @@
         out = args[0]
     elif len(args) > 1:
         mx.abort('jacocoreport takes only one argument : an output directory')
-    mx.run_java(['-jar', jacocoreport.get_path(True), '-in', 'jacoco.exec', '-g', join(_graal_home, 'graal'), out])
+    mx.run_java(['-jar', jacocoreport.get_path(True), '--in', 'jacoco.exec', '--out', out] + [p.dir for p in mx.projects()])
 
 def sl(args):
     """run an SL program"""
     vmArgs, slArgs = _extract_VM_args(args)
     vm(vmArgs + ['-cp', mx.classpath("com.oracle.truffle.sl"), "com.oracle.truffle.sl.SLMain"] + slArgs)
 
-def trufflejar(args=None):
-    """make truffle.jar"""
-
-    # Test with the built classes
-    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'])
-
-    # We use the DSL processor as the starting point for the classpath - this
-    # therefore includes the DSL processor, the DSL and the API.
-    packagejar(mx.classpath("com.oracle.truffle.dsl.processor").split(os.pathsep), "truffle.jar", None, "com.oracle.truffle.dsl.processor.TruffleProcessor")
-
-    # Test with the JAR
-    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'], "truffle.jar:")
-
-
 def isGraalEnabled(vm):
     return vm != 'original' and not vm.endswith('nograal')
 
@@ -1951,7 +2055,6 @@
         'gate' : [gate, '[-options]'],
         'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'],
         'unittest' : [unittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
-        'longunittest' : [longunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
         'makejmhdeps' : [makejmhdeps, ''],
         'shortunittest' : [shortunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
         'jacocoreport' : [jacocoreport, '[output directory]'],
@@ -1961,8 +2064,7 @@
         'vmfg': [vmfg, '[-options] class [args...]'],
         'deoptalot' : [deoptalot, '[n]'],
         'longtests' : [longtests, ''],
-        'sl' : [sl, '[SL args|@VM options]'],
-        'trufflejar' : [trufflejar, '']
+        'sl' : [sl, '[SL args|@VM options]']
     }
 
     mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append'])
@@ -2008,37 +2110,3 @@
     _vm_prefix = opts.vm_prefix
 
     mx.distribution('GRAAL').add_update_listener(_installGraalJarInJdks)
-
-def packagejar(classpath, outputFile, mainClass=None, annotationProcessor=None, stripDebug=False):
-    prefix = '' if mx.get_os() != 'windows' else '\\??\\'  # long file name hack
-    print "creating", outputFile
-    filecount, totalsize = 0, 0
-    with zipfile.ZipFile(outputFile, 'w', zipfile.ZIP_DEFLATED) as zf:
-        manifest = "Manifest-Version: 1.0\n"
-        if mainClass != None:
-            manifest += "Main-Class: %s\n\n" % (mainClass)
-        zf.writestr("META-INF/MANIFEST.MF", manifest)
-        if annotationProcessor != None:
-            zf.writestr("META-INF/services/javax.annotation.processing.Processor", annotationProcessor)
-        for cp in classpath:
-            print "+", cp
-            if cp.endswith(".jar"):
-                with zipfile.ZipFile(cp, 'r') as jar:
-                    for arcname in jar.namelist():
-                        if arcname.endswith('/') or arcname == 'META-INF/MANIFEST.MF' or arcname.endswith('.java') or arcname.lower().startswith("license") or arcname in [".project", ".classpath"]:
-                            continue
-                        zf.writestr(arcname, jar.read(arcname))
-            else:
-                for root, _, files in os.walk(cp):
-                    for f in files:
-                        fullname = os.path.join(root, f)
-                        arcname = fullname[len(cp) + 1:].replace('\\', '/')
-                        if f.endswith(".class"):
-                            zf.write(prefix + fullname, arcname)
-
-        for zi in zf.infolist():
-            filecount += 1
-            totalsize += zi.file_size
-    print "%d files (total size: %.2f kB, jar size: %.2f kB)" % (filecount, totalsize / 1e3, os.path.getsize(outputFile) / 1e3)
-    mx.run([mx.exe_suffix(join(mx.java().jdk, 'bin', 'pack200')), '-r'] + (['-G'] if stripDebug else []) + [outputFile])
-    print "repacked jar size: %.2f kB" % (os.path.getsize(outputFile) / 1e3)
--- a/mx/projects	Fri May 30 13:23:53 2014 +0200
+++ b/mx/projects	Fri May 30 15:09:09 2014 +0200
@@ -2,8 +2,7 @@
 mxversion=1.0
 suite=graal
 
-library@JDK_TOOLS@path=${JAVA_HOME}/lib/tools.jar
-library@JDK_TOOLS@optional=true
+jrelibrary@JFR@jar=jfr.jar
 
 library@JUNIT@path=lib/junit-4.11.jar
 library@JUNIT@urls=http://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar
@@ -38,40 +37,48 @@
 
 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@FINDBUGS@sha1=539fdc73ef5f65a85c94687f6ec77dcd8493f8c1
 
 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
+library@DACAPO@sha1=2626a9546df09009f6da0df854e6dc1113ef7dd4
 
 library@JACOCOAGENT@path=lib/jacocoagent.jar
-library@JACOCOAGENT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoagent.jar
-library@JACOCOAGENT@sha1=9e2c835289356d86afbf31840f05a0f9007c4e44
+library@JACOCOAGENT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoagent-0.7.1-1.jar
+library@JACOCOAGENT@sha1=2f73a645b02e39290e577ce555f00b02004650b0
 
 library@JACOCOREPORT@path=lib/jacocoreport.jar
-library@JACOCOREPORT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoreport.jar
-library@JACOCOREPORT@sha1=32fb5ba2f12d86c4feb74bcefc17a4e6fad8a323
+library@JACOCOREPORT@urls=http://lafo.ssw.uni-linz.ac.at/jacoco/jacocoreport-0.7.1-2.jar
+library@JACOCOREPORT@sha1=a630436391832d697a12c8f7daef8655d7a1efd2
 
 library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0-20120216.jar
 library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
 library@DACAPO_SCALA@sha1=59b64c974662b5cf9dbd3cf9045d293853dd7a51
 
-library@OKRA@path=lib/okra-1.8.jar
-library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8.jar
-library@OKRA@sourcePath=lib/okra-1.8-src.jar
-library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-src.jar
+library@OKRA@path=lib/okra-1.9.jar
+library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar
+library@OKRA@sha1=df450b04882e6b5a365299e2cbf1622038ae880e
+library@OKRA@sourcePath=lib/okra-1.9-src.jar
+library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar
+library@OKRA@sourceSha1=41dcda5197ca4d87bc94e4d7b5a90e7f22667756
 
-library@OKRA_WITH_SIM@path=lib/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar
-library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar
+library@OKRA_WITH_SIM@path=lib/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@sha1=816fa24814cf51c02f9c05477447bb55a152b388
+library@OKRA_WITH_SIM@sourcePath=lib/okra-1.9-with-sim-src.jar
+library@OKRA_WITH_SIM@sourceSha1=1628919457999a8479d9f39845865de527dbd523
+library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar
 
 library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@sha1=64c0a5329fbcb8284640e58d83252e0a3b08c23e
+library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-c7e3525a6b90.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@sha1=128eb20a4cd3362a4d8b94614e66647808a2e37c
 
 library@VECMATH@path=lib/vecmath-1.3.1.jar
 library@VECMATH@urls=http://mirrors.ibiblio.org/pub/mirrors/maven/java3d/jars/vecmath-1.3.1.jar
+library@VECMATH@sha1=a0ae4f51da409fa0c20fa0ca59e6bbc9413ae71d
 
 distribution@GRAAL@path=graal.jar
+distribution@GRAAL@subDir=graal
 distribution@GRAAL@sourcesPath=graal.src.zip
 distribution@GRAAL@dependencies=\
 com.oracle.graal.hotspot.amd64,\
@@ -80,8 +87,29 @@
 com.oracle.graal.truffle.hotspot.amd64,\
 com.oracle.graal.hotspot.sparc,\
 com.oracle.graal.hotspot,\
+com.oracle.graal.hotspot.jfr,\
 com.oracle.graal.hotspot.hsail
-distribution@GRAAL@excludeLibs=FINDBUGS
+distribution@GRAAL@exclude=FINDBUGS
+
+distribution@TRUFFLE@path=truffle.jar
+distribution@TRUFFLE@subDir=graal
+distribution@TRUFFLE@sourcesPath=truffle-sources.jar
+distribution@TRUFFLE@dependencies=\
+com.oracle.truffle.api.dsl
+
+distribution@TRUFFLE-DSL-PROCESSOR@path=truffle-dsl-processor.jar
+distribution@TRUFFLE-DSL-PROCESSOR@subDir=graal
+distribution@TRUFFLE-DSL-PROCESSOR@sourcesPath=truffle-dsl-processor-sources.jar
+distribution@TRUFFLE-DSL-PROCESSOR@dependencies=\
+com.oracle.truffle.dsl.processor
+distribution@TRUFFLE-DSL-PROCESSOR@distDependencies=TRUFFLE
+
+# graal.api.collections
+project@com.oracle.graal.api.collections@subDir=graal
+project@com.oracle.graal.api.collections@sourceDirs=src
+project@com.oracle.graal.api.collections@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.api.collections@javaCompliance=1.8
+project@com.oracle.graal.api.collections@workingSets=API,Graal
 
 # graal.api.runtime
 project@com.oracle.graal.api.runtime@subDir=graal
@@ -172,15 +200,43 @@
 project@com.oracle.graal.sparc@javaCompliance=1.8
 project@com.oracle.graal.sparc@workingSets=Graal,SPARC
 
+# graal.hotspotvmconfig
+project@com.oracle.graal.hotspotvmconfig@subDir=graal
+project@com.oracle.graal.hotspotvmconfig@sourceDirs=src
+project@com.oracle.graal.hotspotvmconfig@dependencies=com.oracle.graal.compiler.common
+project@com.oracle.graal.hotspotvmconfig@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspotvmconfig@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.hotspotvmconfig@annotationProcessorForDependents=true
+project@com.oracle.graal.hotspotvmconfig@javaCompliance=1.8
+project@com.oracle.graal.hotspotvmconfig@workingSets=Graal,HotSpot
+
 # 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,com.oracle.graal.baseline
+project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer,com.oracle.graal.baseline,com.oracle.graal.hotspotvmconfig
 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.8
 project@com.oracle.graal.hotspot@workingSets=Graal,HotSpot
 
+# graal.hotspot.sourcegen
+project@com.oracle.graal.hotspot.sourcegen@subDir=graal
+project@com.oracle.graal.hotspot.sourcegen@sourceDirs=src
+project@com.oracle.graal.hotspot.sourcegen@dependencies=com.oracle.graal.hotspot
+project@com.oracle.graal.hotspot.sourcegen@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspot.sourcegen@javaCompliance=1.8
+project@com.oracle.graal.hotspot.sourcegen@workingSets=Graal,HotSpot
+
+# graal.hotspot.jfr
+project@com.oracle.graal.hotspot.jfr@subDir=graal
+project@com.oracle.graal.hotspot.jfr@sourceDirs=src
+project@com.oracle.graal.hotspot.jfr@dependencies=com.oracle.graal.hotspot,JFR
+project@com.oracle.graal.hotspot.jfr@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspot.jfr@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.hotspot.jfr@javaCompliance=1.8
+project@com.oracle.graal.hotspot.jfr@profile=
+project@com.oracle.graal.hotspot.jfr@workingSets=Graal,HotSpot
+
 # graal.hotspot.amd64
 project@com.oracle.graal.hotspot.amd64@subDir=graal
 project@com.oracle.graal.hotspot.amd64@sourceDirs=src
@@ -268,7 +324,7 @@
 # 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.compiler.common,FINDBUGS
+project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug,com.oracle.graal.compiler.common,com.oracle.graal.api.collections,com.oracle.graal.api.runtime,FINDBUGS
 project@com.oracle.graal.graph@javaCompliance=1.8
 project@com.oracle.graal.graph@workingSets=Graal,Graph
 
@@ -298,7 +354,7 @@
 # graal.lir
 project@com.oracle.graal.lir@subDir=graal
 project@com.oracle.graal.lir@sourceDirs=src
-project@com.oracle.graal.lir@dependencies=com.oracle.graal.nodes,com.oracle.graal.asm
+project@com.oracle.graal.lir@dependencies=com.oracle.graal.debug,com.oracle.graal.compiler.common,com.oracle.graal.asm
 project@com.oracle.graal.lir@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.lir@javaCompliance=1.8
 project@com.oracle.graal.lir@workingSets=Graal,LIR
@@ -330,7 +386,7 @@
 # graal.alloc
 project@com.oracle.graal.alloc@subDir=graal
 project@com.oracle.graal.alloc@sourceDirs=src
-project@com.oracle.graal.alloc@dependencies=com.oracle.graal.nodes
+project@com.oracle.graal.alloc@dependencies=com.oracle.graal.compiler.common
 project@com.oracle.graal.alloc@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.alloc@javaCompliance=1.8
 project@com.oracle.graal.alloc@workingSets=Graal
@@ -388,7 +444,7 @@
 # graal.nodes
 project@com.oracle.graal.nodes@subDir=graal
 project@com.oracle.graal.nodes@sourceDirs=src
-project@com.oracle.graal.nodes@dependencies=com.oracle.graal.graph,com.oracle.graal.api.replacements
+project@com.oracle.graal.nodes@dependencies=com.oracle.graal.graph,com.oracle.graal.api.replacements,com.oracle.graal.lir
 project@com.oracle.graal.nodes@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.nodes@javaCompliance=1.8
 project@com.oracle.graal.nodes@annotationProcessors=com.oracle.graal.replacements.verifier
@@ -405,7 +461,7 @@
 # graal.phases
 project@com.oracle.graal.phases@subDir=graal
 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@dependencies=com.oracle.graal.nodes
 project@com.oracle.graal.phases@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.phases@javaCompliance=1.8
 project@com.oracle.graal.phases@workingSets=Graal,Phases
@@ -437,10 +493,11 @@
 # graal.compiler
 project@com.oracle.graal.compiler@subDir=graal
 project@com.oracle.graal.compiler@sourceDirs=src
-project@com.oracle.graal.compiler@dependencies=com.oracle.graal.api.runtime,com.oracle.graal.virtual,com.oracle.graal.loop,com.oracle.graal.alloc,com.oracle.graal.lir
+project@com.oracle.graal.compiler@dependencies=com.oracle.graal.virtual,com.oracle.graal.loop,com.oracle.graal.alloc
 project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler@javaCompliance=1.8
 project@com.oracle.graal.compiler@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.compiler@annotationProcessorForDependents=true
 project@com.oracle.graal.compiler@workingSets=Graal
 
 # graal.compiler.amd64
@@ -517,7 +574,7 @@
 # graal.compiler.common
 project@com.oracle.graal.compiler.common@subDir=graal
 project@com.oracle.graal.compiler.common@sourceDirs=src
-project@com.oracle.graal.compiler.common@dependencies=com.oracle.graal.api.code
+project@com.oracle.graal.compiler.common@dependencies=com.oracle.graal.api.code,com.oracle.graal.options
 project@com.oracle.graal.compiler.common@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler.common@javaCompliance=1.8
 project@com.oracle.graal.compiler.common@workingSets=Graal,Java
@@ -557,7 +614,7 @@
 # graal.test
 project@com.oracle.graal.test@subDir=graal
 project@com.oracle.graal.test@sourceDirs=src
-project@com.oracle.graal.test@dependencies=JUNIT
+project@com.oracle.graal.test@dependencies=JUNIT,com.oracle.graal.debug
 project@com.oracle.graal.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.test@javaCompliance=1.8
 project@com.oracle.graal.test@workingSets=Graal,Test
@@ -641,7 +698,7 @@
 # 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@dependencies=com.oracle.graal.test,com.oracle.graal.hotspot.hsail,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.8
 
--- a/mxtool/URLConnectionDownload.java	Fri May 30 13:23:53 2014 +0200
+++ b/mxtool/URLConnectionDownload.java	Fri May 30 15:09:09 2014 +0200
@@ -42,9 +42,11 @@
 	 *            successful one
 	 */
     public static void main(String[] args) {
-    	File path = new File(args[0]);
-    	String[] urls = new String[args.length - 1];
-    	System.arraycopy(args, 1, urls, 0, urls.length);
+        File path = new File(args[0]);
+        boolean verbose = args[1].equals("-v");
+        int offset = verbose ? 2 : 1;
+        String[] urls = new String[args.length - offset];
+        System.arraycopy(args, offset, urls, 0, urls.length);
 
         File parent = path.getParentFile();
         makeDirectory(parent);
@@ -92,8 +94,10 @@
                 int n = 0;
                 while ((read = in.read(buf)) != -1) {
                     n += read;
-                    long percent = ((long) n * 100 / size);
-                    System.err.print("\r " + n + " bytes " + (size == -1 ? "" : " (" + percent + "%)"));
+                    if (verbose) {
+                        long percent = ((long) n * 100 / size);
+                        System.err.print("\r " + n + " bytes " + (size == -1 ? "" : " (" + percent + "%)"));
+                    }
                     out.write(buf, 0, read);
                 }
                 System.err.println();
--- a/mxtool/mx.py	Fri May 30 13:23:53 2014 +0200
+++ b/mxtool/mx.py	Fri May 30 15:09:09 2014 +0200
@@ -33,7 +33,8 @@
 Full documentation can be found at https://wiki.openjdk.java.net/display/Graal/The+mx+Tool
 """
 
-import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile, fnmatch
+import sys, os, errno, time, subprocess, shlex, types, StringIO, zipfile, signal, xml.sax.saxutils, tempfile, fnmatch
+import multiprocessing
 import textwrap
 import socket
 import tarfile
@@ -49,6 +50,7 @@
 
 _projects = dict()
 _libs = dict()
+_jreLibs = dict()
 _dists = dict()
 _suites = dict()
 _annotationProcessors = None
@@ -62,7 +64,7 @@
 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, sourcesPath, deps, excludedLibs):
+    def __init__(self, suite, name, path, sourcesPath, deps, mainClass, excludedDependencies, distDependencies):
         self.suite = suite
         self.name = name
         self.path = path.replace('/', os.sep)
@@ -70,13 +72,15 @@
         self.sourcesPath = _make_absolute(sourcesPath.replace('/', os.sep), suite.dir) if sourcesPath else None
         self.deps = deps
         self.update_listeners = set()
-        self.excludedLibs = excludedLibs
+        self.mainClass = mainClass
+        self.excludedDependencies = excludedDependencies
+        self.distDependencies = distDependencies
 
     def sorted_deps(self, includeLibs=False):
         try:
-            excl = [library(d) for d in self.excludedLibs]
+            excl = [dependency(d) for d in self.excludedDependencies]
         except SystemExit as e:
-            abort('invalid excluded library for {} distribution: {}'.format(self.name, e))
+            abort('invalid excluded dependency 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):
@@ -96,9 +100,17 @@
                 if not hasattr(zf, '_provenance'):
                     zf._provenance = {}
                 existingSource = zf._provenance.get(arcname, None)
-                if existingSource and existingSource != source and not arcname.endswith('/'):
-                    log('warning: ' + self.path + ': overwriting ' + arcname + '\n  new: ' + source + '\n  old: ' + existingSource)
+                isOverwrite = False
+                if existingSource and existingSource != source:
+                    log('warning: ' + self.path + ': avoid overwrite of ' + arcname + '\n  new: ' + source + '\n  old: ' + existingSource)
+                    isOverwrite = True
                 zf._provenance[arcname] = source
+                return isOverwrite
+
+            if self.mainClass:
+                manifest = "Manifest-Version: 1.0\nMain-Class: %s\n\n" % (self.mainClass)
+                if not overwriteCheck(arc.zf, "META-INF/MANIFEST.MF", "project files"):
+                    arc.zf.writestr("META-INF/MANIFEST.MF", manifest)
 
             for dep in self.sorted_deps(includeLibs=True):
                 if dep.isLibrary():
@@ -115,20 +127,29 @@
                                     assert '/' not in service
                                     services.setdefault(service, []).extend(lp.read(arcname).splitlines())
                                 else:
-                                    overwriteCheck(arc.zf, arcname, lpath + '!' + arcname)
-                                    arc.zf.writestr(arcname, lp.read(arcname))
+                                    if not overwriteCheck(arc.zf, arcname, lpath + '!' + arcname):
+                                        arc.zf.writestr(arcname, lp.read(arcname))
                     if srcArc.zf and libSourcePath:
                         with zipfile.ZipFile(libSourcePath, 'r') as lp:
                             for arcname in lp.namelist():
-                                overwriteCheck(srcArc.zf, arcname, lpath + '!' + arcname)
-                                srcArc.zf.writestr(arcname, lp.read(arcname))
-                else:
+                                if not overwriteCheck(srcArc.zf, arcname, lpath + '!' + arcname):
+                                    srcArc.zf.writestr(arcname, lp.read(arcname))
+                elif dep.isProject():
                     p = dep
+
+                    isCoveredByDependecy = False
+                    for d in self.distDependencies:
+                        if p in _dists[d].sorted_deps():
+                            logv("Excluding {0} from {1} because it's provided by the dependency {2}".format(p.name, self.path, d))
+                            isCoveredByDependecy = True
+                            break
+
+                    if isCoveredByDependecy:
+                        continue
+
                     # skip a  Java project if its Java compliance level is "higher" than the configured JDK
                     jdk = java(p.javaCompliance)
-                    if not jdk:
-                        log('Excluding {0} from {2} (Java compliance level {1} required)'.format(p.name, p.javaCompliance, self.path))
-                        continue
+                    assert jdk
 
                     logv('[' + self.path + ': adding project ' + p.name + ']')
                     outputDir = p.output_dir()
@@ -146,8 +167,8 @@
                         else:
                             for f in files:
                                 arcname = join(relpath, f).replace(os.sep, '/')
-                                overwriteCheck(arc.zf, arcname, join(root, f))
-                                arc.zf.write(join(root, f), arcname)
+                                if not overwriteCheck(arc.zf, arcname, join(root, f)):
+                                    arc.zf.write(join(root, f), arcname)
                     if srcArc.zf:
                         sourceDirs = p.source_dirs()
                         if p.source_gen_dir():
@@ -158,8 +179,8 @@
                                 for f in files:
                                     if f.endswith('.java'):
                                         arcname = join(relpath, f).replace(os.sep, '/')
-                                        overwriteCheck(srcArc.zf, arcname, join(root, f))
-                                        srcArc.zf.write(join(root, f), arcname)
+                                        if not overwriteCheck(srcArc.zf, arcname, join(root, f)):
+                                            srcArc.zf.write(join(root, f), arcname)
 
             for service, providers in services.iteritems():
                 arcname = 'META-INF/services/' + service
@@ -195,6 +216,9 @@
     def isLibrary(self):
         return isinstance(self, Library)
 
+    def isJreLibrary(self):
+        return isinstance(self, JreLibrary)
+
     def isProject(self):
         return isinstance(self, Project)
 
@@ -223,7 +247,7 @@
             if not exists(s):
                 os.mkdir(s)
 
-    def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
+    def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
         """
         Add the transitive set of dependencies for this project, including
         libraries if 'includeLibs' is true, to the 'deps' list.
@@ -236,8 +260,8 @@
         for name in childDeps:
             assert name != self.name
             dep = dependency(name)
-            if not dep in deps and (includeLibs or not dep.isLibrary()):
-                dep.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+            if not dep in deps and (dep.isProject or (dep.isLibrary() and includeLibs) or (dep.isJreLibrary() and includeJreLibs)):
+                dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
         if not self in deps and includeSelf:
             deps.append(self)
         return deps
@@ -500,17 +524,74 @@
 
     return path
 
-class Library(Dependency):
-    def __init__(self, suite, name, path, mustExist, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps):
+class BaseLibrary(Dependency):
+    def __init__(self, suite, name, optional):
         Dependency.__init__(self, suite, name)
+        self.optional = optional
+
+    def __ne__(self, other):
+        result = self.__eq__(other)
+        if result is NotImplemented:
+            return result
+        return not result
+
+"""
+A library that will be provided by the JDK but may be absent.
+Any project or normal library that depends on a missing library
+will be removed from the global project and library dictionaries
+(i.e., _projects and _libs).
+
+This mechanism exists primarily to be able to support code
+that may use functionality in one JDK (e.g., Oracle JDK)
+that is not present in another JDK (e.g., OpenJDK). A
+motivating example is the Java Flight Recorder library
+found in the Oracle JDK. 
+"""
+class JreLibrary(BaseLibrary):
+    def __init__(self, suite, name, jar, optional):
+        BaseLibrary.__init__(self, suite, name, optional)
+        self.jar = jar
+
+    def __eq__(self, other):
+        if isinstance(other, JreLibrary):
+            return self.jar == other.jar
+        else:
+            return NotImplemented
+
+    def is_present_in_jdk(self, jdk):
+        for e in jdk.bootclasspath().split(os.pathsep):
+            if basename(e) == self.jar:
+                return True
+        for d in jdk.extdirs().split(os.pathsep):
+            if len(d) and self.jar in os.listdir(d):
+                return True
+        for d in jdk.endorseddirs().split(os.pathsep):
+            if len(d) and self.jar in os.listdir(d):
+                return True
+        return False
+
+    def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
+        """
+        Add the transitive set of dependencies for this JRE library to the 'deps' list.
+        """
+        if includeJreLibs and includeSelf and not self in deps:
+            deps.append(self)
+        return deps
+
+class Library(BaseLibrary):
+    def __init__(self, suite, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps):
+        BaseLibrary.__init__(self, suite, name, optional)
         self.path = path.replace('/', os.sep)
         self.urls = urls
         self.sha1 = sha1
-        self.mustExist = mustExist
         self.sourcePath = sourcePath
         self.sourceUrls = sourceUrls
         self.sourceSha1 = sourceSha1
         self.deps = deps
+        abspath = _make_absolute(self.path, self.suite.dir)
+        if not optional and not exists(abspath):
+            if not len(urls):
+                abort('Non-optional library {} must either exist at {} or specify one or more URLs from which it can be retrieved'.format(name, abspath))
         for url in urls:
             if url.endswith('/') != self.path.endswith(os.sep):
                 abort('Path for dependency directory must have a URL ending with "/": path=' + self.path + ' url=' + url)
@@ -524,14 +605,6 @@
         else:
             return NotImplemented
 
-
-    def __ne__(self, other):
-        result = self.__eq__(other)
-        if result is NotImplemented:
-            return result
-        return not result
-
-
     def get_path(self, resolve):
         path = _make_absolute(self.path, self.suite.dir)
         sha1path = path + '.sha1'
@@ -540,8 +613,7 @@
         if includedInJDK and java().javaCompliance >= JavaCompliance(includedInJDK):
             return None
 
-        return _download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, self.mustExist)
-
+        return _download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, not self.optional)
 
     def get_source_path(self, resolve):
         if self.sourcePath is None:
@@ -556,7 +628,7 @@
         if path and (exists(path) or not resolve):
             cp.append(path)
 
-    def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
+    def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
         """
         Add the transitive set of dependencies for this library to the 'deps' list.
         """
@@ -569,7 +641,7 @@
             assert name != self.name
             dep = library(name)
             if not dep in deps:
-                dep.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+                dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
         if not self in deps and includeSelf:
             deps.append(self)
         return deps
@@ -608,12 +680,24 @@
             else:
                 return None
 
+    def isDirty(self, sDir, abortOnError=True):
+        try:
+            return len(subprocess.check_output(['hg', 'status', '-R', sDir])) > 0
+        except OSError:
+            warn(self.missing)
+        except subprocess.CalledProcessError:
+            if abortOnError:
+                abort('failed to get status')
+            else:
+                return None
+
 class Suite:
     def __init__(self, mxDir, primary, load=True):
         self.dir = dirname(mxDir)
         self.mxDir = mxDir
         self.projects = []
         self.libs = []
+        self.jreLibs = []
         self.dists = []
         self.commands = None
         self.primary = primary
@@ -631,6 +715,7 @@
 
     def _load_projects(self):
         libsMap = dict()
+        jreLibsMap = dict()
         projsMap = dict()
         distsMap = dict()
         projectsFile = join(self.mxDir, 'projects')
@@ -680,6 +765,8 @@
                         m = projsMap
                     elif kind == 'library':
                         m = libsMap
+                    elif kind == 'jrelibrary':
+                        m = jreLibsMap
                     elif kind == 'distribution':
                         m = distsMap
                     else:
@@ -720,16 +807,24 @@
             p.__dict__.update(attrs)
             self.projects.append(p)
 
+        for name, attrs in jreLibsMap.iteritems():
+            jar = attrs.pop('jar')
+            # JRE libraries are optional by default
+            optional = attrs.pop('optional', 'true') != 'false'
+            l = JreLibrary(self, name, jar, optional)
+            self.jreLibs.append(l)
+
         for name, attrs in libsMap.iteritems():
             path = attrs.pop('path')
-            mustExist = attrs.pop('optional', 'false') != 'true'
             urls = pop_list(attrs, 'urls')
             sha1 = attrs.pop('sha1', None)
             sourcePath = attrs.pop('sourcePath', None)
             sourceUrls = pop_list(attrs, 'sourceUrls')
             sourceSha1 = attrs.pop('sourceSha1', None)
             deps = pop_list(attrs, 'dependencies')
-            l = Library(self, name, path, mustExist, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps)
+            # Add support optional libraries once we have a good use case
+            optional = False
+            l = Library(self, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps)
             l.__dict__.update(attrs)
             self.libs.append(l)
 
@@ -737,8 +832,10 @@
             path = attrs.pop('path')
             sourcesPath = attrs.pop('sourcesPath', None)
             deps = pop_list(attrs, 'dependencies')
-            exclLibs = pop_list(attrs, 'excludeLibs')
-            d = Distribution(self, name, path, sourcesPath, deps, exclLibs)
+            mainClass = attrs.pop('mainClass', None)
+            exclDeps = pop_list(attrs, 'exclude')
+            distDeps = pop_list(attrs, 'distDependencies')
+            d = Distribution(self, name, path, sourcesPath, deps, mainClass, exclDeps, distDeps)
             d.__dict__.update(attrs)
             self.dists.append(d)
 
@@ -818,6 +915,12 @@
             if existing is not None and existing != l:
                 abort('inconsistent library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir)
             _libs[l.name] = l
+        for l in self.jreLibs:
+            existing = _jreLibs.get(l.name)
+            # Check that suites that define same library are consistent
+            if existing is not None and existing != l:
+                abort('inconsistent JRE library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir)
+            _jreLibs[l.name] = l
         for d in self.dists:
             existing = _dists.get(d.name)
             if existing is not None:
@@ -826,6 +929,54 @@
                 warn('distribution ' + d.name + ' redefined')
                 d.path = existing.path
             _dists[d.name] = d
+
+        # Remove projects and libraries that (recursively) depend on an optional library
+        # whose artifact does not exist or on a JRE library that is not present in the
+        # JDK for a project. Also remove projects whose Java compliance requirement
+        # cannot be satisfied by the configured JDKs.
+        #
+        # Removed projects and libraries are also removed from
+        # distributions in they are listed as dependencies.
+        for d in sorted_deps(includeLibs=True):
+            if d.isLibrary():
+                if d.optional:
+                    try:
+                        d.optional = False
+                        path = d.get_path(resolve=True)
+                    except SystemExit:
+                        path = None
+                    finally:
+                        d.optional = True
+                    if not path:
+                        logv('[omitting optional library {} as {} does not exist]'.format(d, d.path))
+                        del _libs[d.name]
+                        self.libs.remove(d)
+            elif d.isProject():
+                if java(d.javaCompliance) is None:
+                    logv('[omitting project {} as Java compliance {} cannot be satisfied by configured JDKs]'.format(d, d.javaCompliance))
+                    del _projects[d.name]
+                    self.projects.remove(d)
+                else:
+                    for name in list(d.deps):
+                        jreLib = _jreLibs.get(name)
+                        if jreLib:
+                            if not jreLib.is_present_in_jdk(java(d.javaCompliance)):
+                                if jreLib.optional:
+                                    logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+                                    del _projects[d.name]
+                                    self.projects.remove(d)
+                                else:
+                                    abort('JRE library {} required by {} not found'.format(jreLib, d))
+                        elif not dependency(name, fatalIfMissing=False):
+                            logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+                            del _projects[d.name]
+                            self.projects.remove(d)
+        for dist in _dists.values():
+            for name in list(dist.deps):
+                if not dependency(name, fatalIfMissing=False):
+                    logv('[omitting {} from distribution {}]'.format(name, dist))
+                    dist.deps.remove(name)
+
         if hasattr(self, 'mx_post_parse_cmd_line'):
             self.mx_post_parse_cmd_line(opts)
 
@@ -1007,6 +1158,8 @@
     d = _projects.get(name)
     if d is None:
         d = _libs.get(name)
+        if d is None:
+            d = _jreLibs.get(name)
     if d is None and fatalIfMissing:
         if name in _opts.ignored_projects:
             abort('project named ' + name + ' is ignored')
@@ -1090,7 +1243,7 @@
                     entryPath = zi.filename
                     yield zf, entryPath
 
-def sorted_deps(projectNames=None, includeLibs=False, includeAnnotationProcessors=False):
+def sorted_deps(projectNames=None, includeLibs=False, includeJreLibs=False, includeAnnotationProcessors=False):
     """
     Gets projects and libraries sorted such that dependencies
     are before the projects that depend on them. Unless 'includeLibs' is
@@ -1098,12 +1251,12 @@
     """
     projects = projects_from_names(projectNames)
 
-    return sorted_project_deps(projects, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
-
-def sorted_project_deps(projects, includeLibs=False, includeAnnotationProcessors=False):
+    return sorted_project_deps(projects, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+
+def sorted_project_deps(projects, includeLibs=False, includeJreLibs=False, includeAnnotationProcessors=False):
     deps = []
     for p in projects:
-        p.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+        p.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
     return deps
 
 def _handle_missing_java_home():
@@ -1289,8 +1442,21 @@
         time.sleep(delay)
 
 # Makes the current subprocess accessible to the abort() function
-# This is a tuple of the Popen object and args.
-_currentSubprocess = (None, None)
+# This is a list of tuples of the subprocess.Popen or
+# multiprocessing.Process object and args.
+_currentSubprocesses = []
+
+def _addSubprocess(p, args):
+    entry = (p, args)
+    _currentSubprocesses.append(entry)
+    return entry
+
+def _removeSubprocess(entry):
+    if entry and entry in _currentSubprocesses:
+        try:
+            _currentSubprocesses.remove(entry)
+        except:
+            pass
 
 def waitOn(p):
     if get_os() == 'windows':
@@ -1329,8 +1495,7 @@
     if timeout is None and _opts.ptimeout != 0:
         timeout = _opts.ptimeout
 
-    global _currentSubprocess
-
+    sub = None
     try:
         # On Unix, the new subprocess should be in a separate group so that a timeout alarm
         # can use os.killpg() to kill the whole subprocess group
@@ -1348,15 +1513,23 @@
         stdout = out if not callable(out) else subprocess.PIPE
         stderr = err if not callable(err) else subprocess.PIPE
         p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, creationflags=creationflags, env=env)
-        _currentSubprocess = (p, args)
+        sub = _addSubprocess(p, args)
+        joiners = []
         if callable(out):
             t = Thread(target=redirect, args=(p.stdout, out))
-            t.daemon = True  # thread dies with the program
+            # Don't make the reader thread a daemon otherwise output can be droppped
             t.start()
+            joiners.append(t)
         if callable(err):
             t = Thread(target=redirect, args=(p.stderr, err))
-            t.daemon = True  # thread dies with the program
+            # Don't make the reader thread a daemon otherwise output can be droppped
             t.start()
+            joiners.append(t)
+        while any([t.is_alive() for t in joiners]):
+            # Need to use timeout otherwise all signals (including CTRL-C) are blocked
+            # see: http://bugs.python.org/issue1167930
+            for t in joiners:
+                t.join(10)
         if timeout is None or timeout == 0:
             retcode = waitOn(p)
         else:
@@ -1371,7 +1544,7 @@
     except KeyboardInterrupt:
         abort(1)
     finally:
-        _currentSubprocess = (None, None)
+        _removeSubprocess(sub)
 
     if retcode and nonZeroIsFatal:
         if _opts.verbose:
@@ -1508,8 +1681,11 @@
         self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
         self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
         self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
+        self.pack200 = exe_suffix(join(self.jdk, 'bin', 'pack200'))
         self.toolsjar = join(self.jdk, 'lib', 'tools.jar')
         self._bootclasspath = None
+        self._extdirs = None
+        self._endorseddirs = None
 
         if not exists(self.java):
             abort('Java launcher does not exist: ' + self.java)
@@ -1542,9 +1718,13 @@
 
     def _init_classpaths(self):
         myDir = dirname(__file__)
+        outDir = join(dirname(__file__), '.jdk' + str(self.version))
+        if not exists(outDir):
+            os.makedirs(outDir)
         javaSource = join(myDir, 'ClasspathDump.java')
-        subprocess.check_call([self.javac, '-d', myDir, javaSource])
-        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', myDir, 'ClasspathDump']).split('|')]
+        if not exists(join(outDir, 'ClasspathDump.class')):
+            subprocess.check_call([self.javac, '-d', outDir, javaSource])
+        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', outDir, 'ClasspathDump']).split('|')]
         if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
             warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
         self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
@@ -1648,21 +1828,20 @@
     return result
 
 def _send_sigquit():
-    p, args = _currentSubprocess
-
-    def _isJava():
-        if args:
-            name = args[0].split(os.sep)[-1]
-            return name == "java"
-        return False
-
-    if p is not None and _isJava():
-        if get_os() == 'windows':
-            log("mx: implement me! want to send SIGQUIT to my child process")
-        else:
-            _kill_process_group(p.pid, sig=signal.SIGQUIT)
-        time.sleep(0.1)
-
+    for p, args in _currentSubprocesses:
+
+        def _isJava():
+            if args:
+                name = args[0].split(os.sep)[-1]
+                return name == "java"
+            return False
+
+        if p is not None and _isJava():
+            if get_os() == 'windows':
+                log("mx: implement me! want to send SIGQUIT to my child process")
+            else:
+                _kill_process_group(p.pid, sig=signal.SIGQUIT)
+            time.sleep(0.1)
 
 def abort(codeOrMessage):
     """
@@ -1675,15 +1854,26 @@
     if _opts.killwithsigquit:
         _send_sigquit()
 
-    # import traceback
-    # traceback.print_stack()
-    p, _ = _currentSubprocess
-    if p is not None:
-        if get_os() == 'windows':
-            p.kill()
-        else:
-            _kill_process_group(p.pid, signal.SIGKILL)
-
+    def is_alive(p):
+        if isinstance(p, subprocess.Popen):
+            return p.poll() is None
+        assert isinstance(p, multiprocessing.Process), p
+        return p.is_alive()
+
+    for p, args in _currentSubprocesses:
+        if is_alive(p):
+            try:
+                if get_os() == 'windows':
+                    p.terminate()
+                else:
+                    _kill_process_group(p.pid, signal.SIGKILL)
+            except BaseException as e:
+                if is_alive(p):
+                    log('error while killing subprocess {} "{}": {}'.format(p.pid, ' '.join(args), e))
+
+    if _opts and _opts.verbose:
+        import traceback
+        traceback.print_stack()
     raise SystemExit(codeOrMessage)
 
 def download(path, urls, verbose=False):
@@ -1696,60 +1886,18 @@
     if d != '' and not exists(d):
         os.makedirs(d)
 
-
-    if not path.endswith(os.sep):
-        # Try it with the Java tool first since it can show a progress counter
-        myDir = dirname(__file__)
-        javaSource = join(myDir, 'URLConnectionDownload.java')
-        javaClass = join(myDir, 'URLConnectionDownload.class')
-        if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
-            subprocess.check_call([java().javac, '-d', myDir, javaSource])
-        if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + urls, nonZeroIsFatal=False) == 0:
-            return
-
-    def url_open(url):
-        userAgent = 'Mozilla/5.0 (compatible)'
-        headers = {'User-Agent' : userAgent}
-        req = urllib2.Request(url, headers=headers)
-        return urllib2.urlopen(req)
-
-    for url in urls:
-        try:
-            if verbose:
-                log('Downloading ' + url + ' to ' + path)
-            if url.startswith('zip:') or url.startswith('jar:'):
-                i = url.find('!/')
-                if i == -1:
-                    abort('Zip or jar URL does not contain "!/": ' + url)
-                url, _, entry = url[len('zip:'):].partition('!/')
-                with contextlib.closing(url_open(url)) as f:
-                    data = f.read()
-                    zipdata = StringIO.StringIO(f.read())
-
-                zf = zipfile.ZipFile(zipdata, 'r')
-                data = zf.read(entry)
-                with open(path, 'wb') as f:
-                    f.write(data)
-            else:
-                with contextlib.closing(url_open(url)) as f:
-                    data = f.read()
-                if path.endswith(os.sep):
-                    # Scrape directory listing for relative URLs
-                    hrefs = re.findall(r' href="([^"]*)"', data)
-                    if len(hrefs) != 0:
-                        for href in hrefs:
-                            if not '/' in href:
-                                download(join(path, href), [url + href], verbose)
-                    else:
-                        log('no locals hrefs scraped from ' + url)
-                else:
-                    with open(path, 'wb') as f:
-                        f.write(data)
-            return
-        except IOError as e:
-            log('Error reading from ' + url + ': ' + str(e))
-        except zipfile.BadZipfile as e:
-            log('Error in zip file downloaded from ' + url + ': ' + str(e))
+    assert not path.endswith(os.sep)
+
+    myDir = dirname(__file__)
+    javaSource = join(myDir, 'URLConnectionDownload.java')
+    javaClass = join(myDir, 'URLConnectionDownload.class')
+    if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
+        subprocess.check_call([java().javac, '-d', myDir, javaSource])
+    verbose = []
+    if sys.stderr.isatty():
+        verbose.append("-v")
+    if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + verbose + urls, nonZeroIsFatal=False) == 0:
+        return
 
     abort('Could not download to ' + path + ' from any of the following URLs:\n\n    ' +
               '\n    '.join(urls) + '\n\nPlease use a web browser to do the download manually')
@@ -1779,6 +1927,120 @@
 
 # Builtin commands
 
+def _defaultEcjPath():
+    return get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar'))
+
+class JavaCompileTask:
+    def __init__(self, args, proj, reason, javafilelist, jdk, outputDir, jdtJar, deps):
+        self.proj = proj
+        self.reason = reason
+        self.javafilelist = javafilelist
+        self.deps = deps
+        self.jdk = jdk
+        self.outputDir = outputDir
+        self.done = False
+        self.jdtJar = jdtJar
+        self.args = args
+
+    def __str__(self):
+        return self.proj.name
+
+    def logCompilation(self, compiler):
+        log('Compiling Java sources for {} with {}... [{}]'.format(self.proj.name, compiler, self.reason))
+
+    def execute(self):
+        argfileName = join(self.proj.dir, 'javafilelist.txt')
+        argfile = open(argfileName, 'wb')
+        argfile.write('\n'.join(self.javafilelist))
+        argfile.close()
+
+        processorArgs = []
+
+        aps = self.proj.annotation_processors()
+        if len(aps) > 0:
+            processorPath = classpath(aps, resolve=True)
+            genDir = self.proj.source_gen_dir()
+            if exists(genDir):
+                shutil.rmtree(genDir)
+            os.mkdir(genDir)
+            processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
+        else:
+            processorArgs += ['-proc:none']
+
+        args = self.args
+        jdk = self.jdk
+        outputDir = self.outputDir
+        compliance = str(jdk.javaCompliance)
+        cp = classpath(self.proj.name, includeSelf=True)
+        toBeDeleted = [argfileName]
+
+        try:
+            if not self.jdtJar:
+                mainJava = java()
+                if not args.error_prone:
+                    self.logCompilation('javac')
+                    javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    if jdk.debug_port is not None:
+                        javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
+                    javacCmd += processorArgs
+                    javacCmd += ['@' + argfile.name]
+
+                    if not args.warnAPI:
+                        javacCmd.append('-XDignore.symbol.file')
+                    run(javacCmd)
+                else:
+                    self.logCompilation('javac (with error-prone)')
+                    javaArgs = ['-Xmx1g']
+                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    javacArgs += processorArgs
+                    javacArgs += ['@' + argfile.name]
+                    if not args.warnAPI:
+                        javacArgs.append('-XDignore.symbol.file')
+                    run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
+            else:
+                self.logCompilation('JDT')
+
+                jdtVmArgs = ['-Xmx1g', '-jar', self.jdtJar]
+
+                jdtArgs = ['-' + compliance,
+                         '-cp', cp, '-g', '-enableJavadoc',
+                         '-d', outputDir,
+                         '-bootclasspath', jdk.bootclasspath(),
+                         '-endorseddirs', jdk.endorseddirs(),
+                         '-extdirs', jdk.extdirs()]
+                jdtArgs += processorArgs
+
+                jdtProperties = join(self.proj.dir, '.settings', 'org.eclipse.jdt.core.prefs')
+                rootJdtProperties = join(self.proj.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs')
+                if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties):
+                    # Try to fix a missing properties file by running eclipseinit
+                    eclipseinit([], buildProcessorJars=False)
+                if not exists(jdtProperties):
+                    log('JDT properties file {0} not found'.format(jdtProperties))
+                else:
+                    with open(jdtProperties) as fp:
+                        origContent = fp.read()
+                        content = origContent
+                        if args.jdt_warning_as_error:
+                            content = content.replace('=warning', '=error')
+                        if not args.jdt_show_task_tags:
+                            content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore'
+                    if origContent != content:
+                        jdtPropertiesTmp = jdtProperties + '.tmp'
+                        with open(jdtPropertiesTmp, 'w') as fp:
+                            fp.write(content)
+                        toBeDeleted.append(jdtPropertiesTmp)
+                        jdtArgs += ['-properties', jdtPropertiesTmp]
+                    else:
+                        jdtArgs += ['-properties', jdtProperties]
+                jdtArgs.append('@' + argfile.name)
+
+                run_java(jdtVmArgs + jdtArgs)
+        finally:
+            for n in toBeDeleted:
+                os.remove(n)
+            self.done = True
+
 def build(args, parser=None):
     """compile the Java and C sources, linking the latter
 
@@ -1789,22 +2051,22 @@
     if not suppliedParser:
         parser = ArgumentParser(prog='mx build')
 
-    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('-p', action='store_true', dest='parallelize', help='parallelizes Java compilation')
     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)')
     parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects')
     parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects')
-    parser.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
-    parser.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='<path>')
     parser.add_argument('--jdt-warning-as-error', action='store_true', help='convert all Eclipse batch compiler warnings to errors')
     parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings')
-    parser.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
+    compilerSelect = parser.add_mutually_exclusive_group()
+    compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
+    compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler', default=_defaultEcjPath(), metavar='<path>')
+    compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
 
     if suppliedParser:
         parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
@@ -1817,14 +2079,12 @@
             abort('Path for Eclipse batch compiler does not look like a jar file: ' + args.jdt)
         jdtJar = args.jdt
         if not exists(jdtJar):
-            if os.path.abspath(jdtJar) == os.path.abspath(defaultEcjPath) and get_env('JDT', None) is None:
+            if os.path.abspath(jdtJar) == os.path.abspath(_defaultEcjPath()) and get_env('JDT', None) is None:
                 # Silently ignore JDT if default location is used but does not exist
                 jdtJar = None
             else:
                 abort('Eclipse batch compiler jar does not exist: ' + args.jdt)
 
-    built = set()
-
     if args.only is not None:
         # N.B. This build will not include dependencies including annotation processor dependencies
         sortedProjects = [project(name) for name in args.only.split(',')]
@@ -1857,6 +2117,7 @@
                 shutil.rmtree(join(genDir, f))
         return outputDir
 
+    tasks = {}
     for p in sortedProjects:
         if p.native:
             if args.native:
@@ -1866,7 +2127,6 @@
                     run([gmake_cmd(), 'clean'], cwd=p.dir)
 
                 run([gmake_cmd()], cwd=p.dir)
-                built.add(p.name)
             continue
         else:
             if not args.java:
@@ -1877,21 +2137,20 @@
         # skip building this Java project if its Java compliance level is "higher" than the configured JDK
         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)
+        assert jdk
 
         outputDir = prepareOutputDirs(p, args.clean)
 
-        cp = classpath(p.name, includeSelf=True)
         sourceDirs = p.source_dirs()
-        mustBuild = args.force
-        if not mustBuild:
-            for dep in p.all_deps([], False):
-                if dep.name in built:
-                    mustBuild = True
-
+        buildReason = 'forced build' if args.force else None
+        taskDeps = []
+        if not buildReason:
+            for dep in p.all_deps([], includeLibs=False, includeAnnotationProcessors=True):
+                taskDep = tasks.get(dep.name)
+                if taskDep:
+                    if not buildReason:
+                        buildReason = dep.name + ' rebuilt'
+                    taskDeps.append(taskDep)
 
         jasminAvailable = None
         javafilelist = []
@@ -1940,20 +2199,18 @@
                         if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) < os.path.getmtime(src)):
                             shutil.copyfile(src, dst)
 
-                if not mustBuild:
+                if not buildReason:
                     for javafile in javafiles:
                         classfile = TimeStampFile(outputDir + javafile[len(sourceDir):-len('java')] + 'class')
                         if not classfile.exists() or classfile.isOlderThan(javafile):
-                            mustBuild = True
+                            buildReason = 'class file(s) out of date'
                             break
 
-        aps = p.annotation_processors()
         apsOutOfDate = p.update_current_annotation_processors_file()
         if apsOutOfDate:
-            logv('[annotation processors for {0} changed]'.format(p.name))
-            mustBuild = True
-
-        if not mustBuild:
+            buildReason = 'annotation processor(s) changed'
+
+        if not buildReason:
             logv('[all class files for {0} are up to date - skipping]'.format(p.name))
             continue
 
@@ -1961,95 +2218,106 @@
             logv('[no Java sources for {0} - skipping]'.format(p.name))
             continue
 
-        # Ensure that the output directories are clean
-        # prepareOutputDirs(p, True)
-
-        built.add(p.name)
-
-        argfileName = join(p.dir, 'javafilelist.txt')
-        argfile = open(argfileName, 'wb')
-        argfile.write('\n'.join(javafilelist))
-        argfile.close()
-
-        processorArgs = []
-
-        if len(aps) > 0:
-            processorPath = classpath(aps, resolve=True)
-            genDir = p.source_gen_dir()
-            if exists(genDir):
-                shutil.rmtree(genDir)
-            os.mkdir(genDir)
-            processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
+        task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, jdtJar, taskDeps)
+
+        if args.parallelize:
+            # Best to initialize class paths on main process
+            jdk.bootclasspath()
+            task.proc = None
+            tasks[p.name] = task
         else:
-            processorArgs += ['-proc:none']
-
-        toBeDeleted = [argfileName]
-        try:
-            if not jdtJar:
-                mainJava = java()
-                if not args.error_prone:
-                    log('Compiling Java sources for {0} with javac...'.format(p.name))
-                    javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
-                    if jdk.debug_port is not None:
-                        javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
-                    javacCmd += processorArgs
-                    javacCmd += ['@' + argfile.name]
-
-                    if not args.warnAPI:
-                        javacCmd.append('-XDignore.symbol.file')
-                    run(javacCmd)
+            task.execute()
+
+    if args.parallelize:
+
+        def joinTasks(tasks):
+            failed = []
+            for t in tasks:
+                t.proc.join()
+                _removeSubprocess(t.sub)
+                if t.proc.exitcode != 0:
+                    failed.append(t)
+            return failed
+
+        def checkTasks(tasks):
+            active = []
+            for t in tasks:
+                if t.proc.is_alive():
+                    active.append(t)
+                else:
+                    if t.proc.exitcode != 0:
+                        return ([], joinTasks(tasks))
+            return (active, [])
+
+        def remainingDepsDepth(task):
+            if task._d is None:
+                incompleteDeps = [d for d in task.deps if d.proc is None or d.proc.is_alive()]
+                if len(incompleteDeps) == 0:
+                    task._d = 0
                 else:
-                    log('Compiling Java sources for {0} with javac (with error-prone)...'.format(p.name))
-                    javaArgs = ['-Xmx1g']
-                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
-                    javacArgs += processorArgs
-                    javacArgs += ['@' + argfile.name]
-                    if not args.warnAPI:
-                        javacArgs.append('-XDignore.symbol.file')
-                    run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
-            else:
-                log('Compiling Java sources for {0} with JDT...'.format(p.name))
-
-                jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
-
-                jdtArgs = ['-' + compliance,
-                         '-cp', cp, '-g', '-enableJavadoc',
-                         '-d', outputDir,
-                         '-bootclasspath', jdk.bootclasspath(),
-                         '-endorseddirs', jdk.endorseddirs(),
-                         '-extdirs', jdk.extdirs()]
-                jdtArgs += processorArgs
-
-
-                jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs')
-                rootJdtProperties = join(p.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs')
-                if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties):
-                    # Try to fix a missing properties file by running eclipseinit
-                    eclipseinit([], buildProcessorJars=False)
-                if not exists(jdtProperties):
-                    log('JDT properties file {0} not found'.format(jdtProperties))
+                    task._d = max([remainingDepsDepth(t) for t in incompleteDeps]) + 1
+            return task._d
+
+        def compareTasks(t1, t2):
+            d = remainingDepsDepth(t1) - remainingDepsDepth(t2)
+            if d == 0:
+                t1Work = (1 + len(t1.proj.annotation_processors())) * len(t1.javafilelist)
+                t2Work = (1 + len(t2.proj.annotation_processors())) * len(t2.javafilelist)
+                d = t1Work - t2Work
+            return d
+
+        def sortWorklist(tasks):
+            for t in tasks:
+                t._d = None
+            return sorted(tasks, compareTasks)
+
+        cpus = multiprocessing.cpu_count()
+        worklist = sortWorklist(tasks.values())
+        active = []
+        failed = []
+        while len(worklist) != 0:
+            while True:
+                active, failed = checkTasks(active)
+                if len(failed) != 0:
+                    assert not active, active
+                    break
+                if len(active) == cpus:
+                    # Sleep for 1 second
+                    time.sleep(1)
                 else:
-                    with open(jdtProperties) as fp:
-                        origContent = fp.read()
-                        content = origContent
-                        if args.jdt_warning_as_error:
-                            content = content.replace('=warning', '=error')
-                        if not args.jdt_show_task_tags:
-                            content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore'
-                    if origContent != content:
-                        jdtPropertiesTmp = jdtProperties + '.tmp'
-                        with open(jdtPropertiesTmp, 'w') as fp:
-                            fp.write(content)
-                        toBeDeleted.append(jdtPropertiesTmp)
-                        jdtArgs += ['-properties', jdtPropertiesTmp]
-                    else:
-                        jdtArgs += ['-properties', jdtProperties]
-                jdtArgs.append('@' + argfile.name)
-
-                run_java(jdtVmArgs + jdtArgs)
-        finally:
-            for n in toBeDeleted:
-                os.remove(n)
+                    break
+
+            if len(failed) != 0:
+                break
+
+            def executeTask(task):
+                # Clear sub-process list cloned from parent process
+                del _currentSubprocesses[:]
+                task.execute()
+
+            def depsDone(task):
+                for d in task.deps:
+                    if d.proc is None or d.proc.exitcode is None:
+                        return False
+                return True
+
+            for task in worklist:
+                if depsDone(task):
+                    worklist.remove(task)
+                    task.proc = multiprocessing.Process(target=executeTask, args=(task,))
+                    task.proc.start()
+                    active.append(task)
+                    task.sub = _addSubprocess(task.proc, ['JavaCompileTask', str(task)])
+                if len(active) == cpus:
+                    break
+
+            worklist = sortWorklist(worklist)
+
+        failed += joinTasks(active)
+        if len(failed):
+            for t in failed:
+                log('Compiling {} failed'.format(t.proj.name))
+            abort('{} Java compilation tasks failed'.format(len(failed)))
 
     for dist in _dists.values():
         archive(['@' + dist.name])
@@ -2058,6 +2326,39 @@
         return args
     return None
 
+def _chunk_files_for_command_line(files, limit=None, pathFunction=None):
+    """
+    Returns a generator for splitting up a list of files into chunks such that the
+    size of the space separated file paths in a chunk is less than a given limit.
+    This is used to work around system command line length limits.
+    """
+    chunkSize = 0
+    chunkStart = 0
+    if limit is None:
+        commandLinePrefixAllowance = 3000
+        if get_os() == 'windows':
+            # The CreateProcess function on Windows limits the length of a command line to
+            # 32,768 characters (http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx)
+            limit = 32768 - commandLinePrefixAllowance
+        else:
+            # Using just SC_ARG_MAX without extra downwards adjustment
+            # results in "[Errno 7] Argument list too long" on MacOS.
+            syslimit = os.sysconf('SC_ARG_MAX') - 20000
+            limit = syslimit - commandLinePrefixAllowance
+    for i in range(len(files)):
+        path = files[i] if pathFunction is None else pathFunction(files[i])
+        size = len(path) + 1
+        if chunkSize + size < limit:
+            chunkSize += size
+        else:
+            assert i > chunkStart
+            yield files[chunkStart:i]
+            chunkStart = i
+            chunkSize = 0
+    if chunkStart == 0:
+        assert chunkSize < limit
+        yield files
+
 def eclipseformat(args):
     """run the Eclipse Code Formatter on the Java sources
 
@@ -2160,18 +2461,19 @@
         if res is not batch:
             res.javafiles = res.javafiles + batch.javafiles
 
-    print "we have: " + str(len(batches)) + " batches"
+    log("we have: " + str(len(batches)) + " batches")
     for batch in batches.itervalues():
-        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(batch.removeTrailingWhitespace):
-                modified.append(fi)
+        for chunk in _chunk_files_for_command_line(batch.javafiles, pathFunction=lambda f: f.path):
+            run([args.eclipse_exe,
+                '-nosplash',
+                '-application',
+                'org.eclipse.jdt.core.JavaCodeFormatter',
+                '-vm', java(batch.javaCompliance).java,
+                '-config', batch.path]
+                + [f.path for f in chunk])
+            for fi in chunk:
+                if fi.update(batch.removeTrailingWhitespace):
+                    modified.append(fi)
 
     log('{0} files were modified'.format(len(modified)))
 
@@ -2209,7 +2511,7 @@
         return []
 
     pnames = [p.name for p in projs]
-    build(['--projects', ",".join(pnames)])
+    build(['--jdt-warning-as-error', '--projects', ",".join(pnames)])
     return archive(pnames)
 
 def pylint(args):
@@ -2308,6 +2610,10 @@
             # Atomic on Unix
             shutil.move(self.tmpPath, self.path)
 
+def _archive(args):
+    archive(args)
+    return 0
+
 def archive(args):
     """create jar files for projects and distributions"""
     parser = ArgumentParser(prog='mx archive')
@@ -2325,6 +2631,7 @@
             p = project(name)
             archives.append(p.make_archive())
 
+    logv("generated archives: " + str(archives))
     return archives
 
 def canonicalizeprojects(args):
@@ -2441,9 +2748,7 @@
 
         # skip checking this Java project if its Java compliance level is "higher" than the configured JDK
         jdk = java(p.javaCompliance)
-        if not jdk:
-            log('Excluding {0} from checking (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
-            continue
+        assert jdk
 
         for sourceDir in sourceDirs:
             javafilelist = []
@@ -2503,26 +2808,9 @@
             log('Running Checkstyle on {0} using {1}...'.format(sourceDir, config))
 
             try:
-
-                # Checkstyle is unable to read the filenames to process from a file, and the
-                # CreateProcess function on Windows limits the length of a command line to
-                # 32,768 characters (http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx)
-                # so calling Checkstyle must be done in batches.
-                while len(javafilelist) != 0:
-                    i = 0
-                    size = 0
-                    while i < len(javafilelist):
-                        s = len(javafilelist[i]) + 1
-                        if size + s < 30000:
-                            size += s
-                            i += 1
-                        else:
-                            break
-
-                    batch = javafilelist[:i]
-                    javafilelist = javafilelist[i:]
+                for chunk in _chunk_files_for_command_line(javafilelist):
                     try:
-                        run_java(['-Xmx1g', '-jar', library('CHECKSTYLE').get_path(True), '-f', 'xml', '-c', config, '-o', auditfileName] + batch, nonZeroIsFatal=False)
+                        run_java(['-Xmx1g', '-jar', library('CHECKSTYLE').get_path(True), '-f', 'xml', '-c', config, '-o', auditfileName] + chunk, nonZeroIsFatal=False)
                     finally:
                         if exists(auditfileName):
                             errors = []
@@ -2562,6 +2850,12 @@
 
     args = parser.parse_args(args)
 
+    def _rmtree(dirPath):
+        path = dirPath
+        if get_os() == 'windows':
+            path = unicode("\\\\?\\" + dirPath)
+        shutil.rmtree(path)
+
     for p in projects_opt_limit_to_suites():
         if p.native:
             if args.native:
@@ -2572,13 +2866,13 @@
                 if genDir != '' and exists(genDir):
                     log('Clearing {0}...'.format(genDir))
                     for f in os.listdir(genDir):
-                        shutil.rmtree(join(genDir, f))
+                        _rmtree(join(genDir, f))
 
 
                 outputDir = p.output_dir()
                 if outputDir != '' and exists(outputDir):
                     log('Removing {0}...'.format(outputDir))
-                    shutil.rmtree(outputDir)
+                    _rmtree(outputDir)
 
             for configName in ['netbeans-config.zip', 'eclipse-config.zip']:
                 config = TimeStampFile(join(p.suite.mxDir, configName))
@@ -2646,7 +2940,7 @@
         igv.close('properties')
         igv.open('graph', {'name' : 'dependencies'})
         igv.open('nodes')
-        for p in sorted_deps(includeLibs=True):
+        for p in sorted_deps(includeLibs=True, includeJreLibs=True):
             ident = len(ids)
             ids[p.name] = str(ident)
             igv.open('node', {'id' : str(ident)})
@@ -2698,10 +2992,10 @@
             elif dep.get_source_path(resolve=True):
                 memento = XMLDoc().element('archive', {'detectRoot' : 'true', 'path' : dep.get_source_path(resolve=True)}).xml(standalone='no')
                 slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.debug.core.containerType.externalArchive'})
-        else:
+        elif dep.isProject():
             memento = XMLDoc().element('javaProject', {'name' : dep.name}).xml(standalone='no')
             slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'})
-            if javaCompliance is None or dep.javaCompliance < javaCompliance:
+            if javaCompliance is None or dep.javaCompliance > javaCompliance:
                 javaCompliance = dep.javaCompliance
 
     if javaCompliance:
@@ -2865,9 +3159,7 @@
         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
+        assert java(p.javaCompliance)
 
         if not exists(p.dir):
             os.makedirs(p.dir)
@@ -2908,7 +3200,7 @@
                     libraryDeps -= set(dep.all_deps([], True))
                 else:
                     libraryDeps.add(dep)
-            else:
+            elif dep.isProject():
                 projectDeps.add(dep)
 
         for dep in containerDeps:
@@ -2917,8 +3209,6 @@
         for dep in libraryDeps:
             path = dep.path
             dep.get_path(resolve=True)
-            if not path or (not exists(path) and not dep.mustExist):
-                continue
 
             # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
             # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
@@ -3011,10 +3301,6 @@
             refreshFile = os.path.relpath(join(p.dir, p.name + '.jar'), logicalWorkspaceRoot)
             _genEclipseBuilder(out, p, 'Jar', 'archive ' + p.name, refresh=True, refreshFile=refreshFile, relevantResources=[binFolder], async=True, xmlIndent='', xmlStandalone='no')
 
-        if projToDist.has_key(p.name):
-            dist, distDeps = projToDist[p.name]
-            _genEclipseBuilder(out, p, 'Create' + dist.name + 'Dist', 'archive @' + dist.name, relevantResources=[binFolder], logToFile=True, refresh=False, async=True)
-
         out.close('buildSpec')
         out.open('natures')
         out.element('nature', data='org.eclipse.jdt.core.javanature')
@@ -3075,17 +3361,13 @@
             for ap in p.annotation_processors():
                 for dep in dependency(ap).all_deps([], True):
                     if dep.isLibrary():
-                        if not hasattr(dep, 'eclipse.container') and not hasattr(dep, 'eclipse.project'):
-                            if dep.mustExist:
-                                path = dep.get_path(resolve=True)
-                                if path:
-                                    # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
-                                    # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
-                                    # safest to simply use absolute paths.
-                                    path = _make_absolute(path, p.suite.dir)
-                                    out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
-                                    files.append(path)
-                    else:
+                        # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
+                        # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
+                        # safest to simply use absolute paths.
+                        path = _make_absolute(dep.get_path(resolve=True), p.suite.dir)
+                        out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
+                        files.append(path)
+                    elif dep.isProject():
                         out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + dep.name + '/' + dep.name + '.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'})
             out.close('factorypath')
             update_file(join(p.dir, '.factorypath'), out.xml(indent='\t', newl='\n'))
@@ -3097,6 +3379,43 @@
     _zip_files(files, suite.dir, configZip.path)
     _zip_files(libFiles, suite.dir, configLibsZip)
 
+    # Create an Eclipse project for each distribution that will create/update the archive
+    # for the distribution whenever any project of the distribution is updated.
+    for dist in suite.dists:
+        name = dist.name
+        if hasattr(dist, 'subDir'):
+            projectDir = join(suite.dir, dist.subDir, dist.name + '.dist')
+        else:
+            projectDir = join(suite.dir, dist.name + '.dist')
+        if not exists(projectDir):
+            os.makedirs(projectDir)
+        distProjects = [d for d in dist.sorted_deps() if d.isProject()]
+        relevantResources = []
+        for p in distProjects:
+            for srcDir in p.source_dirs():
+                relevantResources.append(join(p.name, os.path.relpath(srcDir, p.dir)))
+            relevantResources.append(join(p.name, os.path.relpath(p.output_dir(), p.dir)))
+        out = XMLDoc()
+        out.open('projectDescription')
+        out.element('name', data=dist.name)
+        out.element('comment', data='Updates ' + dist.path + ' if a project dependency of ' + dist.name + ' is updated')
+        out.open('projects')
+        for p in distProjects:
+            out.element('project', data=p.name)
+        out.close('projects')
+        out.open('buildSpec')
+        dist.dir = projectDir
+        dist.javaCompliance = max([p.javaCompliance for p in distProjects])
+        _genEclipseBuilder(out, dist, 'Create' + dist.name + 'Dist', 'archive @' + dist.name, relevantResources=relevantResources, logToFile=True, refresh=False, async=True)
+        out.close('buildSpec')
+        out.open('natures')
+        out.element('nature', data='org.eclipse.jdt.core.javanature')
+        out.close('natures')
+        out.close('projectDescription')
+        projectFile = join(projectDir, '.project')
+        update_file(projectFile, out.xml(indent='\t', newl='\n'))
+        files.append(projectFile)
+
 def _zip_files(files, baseDir, zipPath):
     fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(zipPath), dir=baseDir)
     try:
@@ -3388,10 +3707,7 @@
             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
+        assert jdk
 
         jdks.add(jdk)
 
@@ -3432,7 +3748,7 @@
             if dep == p:
                 continue
 
-            if not dep.isLibrary():
+            if dep.isProject():
                 n = dep.name.replace('.', '_')
                 if firstDep:
                     out.open('references', {'xmlns' : 'http://www.netbeans.org/ns/ant-project-references/1'})
@@ -3567,8 +3883,6 @@
                 continue
 
             if dep.isLibrary():
-                if not dep.mustExist:
-                    continue
                 path = dep.get_path(resolve=True)
                 if path:
                     if os.sep == '\\':
@@ -3577,7 +3891,7 @@
                     print >> out, ref + '=' + path
                     libFiles.append(path)
 
-            else:
+            elif dep.isProject():
                 n = dep.name.replace('.', '_')
                 relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/')
                 ref = 'reference.' + n + '.jar'
@@ -3644,9 +3958,7 @@
         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
+        assert java(p.javaCompliance)
 
         if not exists(p.dir):
             os.makedirs(p.dir)
@@ -3693,10 +4005,9 @@
                 continue
 
             if dep.isLibrary():
-                if dep.mustExist:
-                    libraries.add(dep)
-                    moduleXml.element('orderEntry', attributes={'type': 'library', 'name': dep.name, 'level': 'project'})
-            else:
+                libraries.add(dep)
+                moduleXml.element('orderEntry', attributes={'type': 'library', 'name': dep.name, 'level': 'project'})
+            elif dep.isProject():
                 moduleXml.element('orderEntry', attributes={'type': 'module', 'module-name': dep.name})
 
         moduleXml.close('component')
@@ -3768,7 +4079,7 @@
                 for entry in pDep.all_deps([], True):
                     if entry.isLibrary():
                         compilerXml.element('entry', attributes={'name': '$PROJECT_DIR$/' + os.path.relpath(entry.path, suite.dir)})
-                    else:
+                    elif entry.isProject():
                         assert entry.isProject()
                         compilerXml.element('entry', attributes={'name': '$PROJECT_DIR$/' + os.path.relpath(entry.output_dir(), suite.dir)})
             compilerXml.close('processorPath')
@@ -3826,7 +4137,7 @@
 
 
 def ideinit(args, refreshOnly=False, buildProcessorJars=True):
-    """(re)generate Eclipse and NetBeans project configurations"""
+    """(re)generate Eclipse, NetBeans and Intellij project configurations"""
     eclipseinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
     netbeansinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
     intellijinit(args, refreshOnly=refreshOnly)
@@ -3964,7 +4275,13 @@
             try:
                 log('Generating {2} for {0} in {1}'.format(p.name, out, docDir))
                 projectJava = java(p.javaCompliance)
-                run([java().javadoc, memory,
+
+                # Once https://bugs.openjdk.java.net/browse/JDK-8041628 is fixed,
+                # this should be reverted to:
+                # javadocExe = java().javadoc
+                javadocExe = projectJava.javadoc
+
+                run([javadocExe, memory,
                      '-XDignore.symbol.file',
                      '-classpath', cp,
                      '-quiet',
@@ -3974,6 +4291,7 @@
                      '-source', str(projectJava.javaCompliance),
                      '-bootclasspath', projectJava.bootclasspath(),
                      '-extdirs', projectJava.extdirs()] +
+                     ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
                      links +
                      extraArgs +
                      nowarnAPI +
@@ -4011,115 +4329,19 @@
              '-quiet',
              '-d', out,
              '-sourcepath', sp] +
+             ([] if java().javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
              links +
              extraArgs +
              nowarnAPI +
              list(pkgs))
         log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
 
-class Chunk:
-    def __init__(self, content, ldelim, rdelim=None):
-        lindex = content.find(ldelim)
-        if rdelim is not None:
-            rindex = content.find(rdelim)
-        else:
-            rindex = lindex + len(ldelim)
-        self.ldelim = ldelim
-        self.rdelim = rdelim
-        if lindex != -1 and rindex != -1 and rindex > lindex:
-            self.text = content[lindex + len(ldelim):rindex]
-        else:
-            self.text = None
-
-    def replace(self, content, repl):
-        lindex = content.find(self.ldelim)
-        if self.rdelim is not None:
-            rindex = content.find(self.rdelim)
-            rdelimLen = len(self.rdelim)
-        else:
-            rindex = lindex + len(self.ldelim)
-            rdelimLen = 0
-        old = content[lindex:rindex + rdelimLen]
-        return content.replace(old, repl)
-
-# Post-process an overview-summary.html file to move the
-# complete overview to the top of the page
-def _fix_overview_summary(path, topLink):
-    """
-    Processes an "overview-summary.html" generated by javadoc to put the complete
-    summary text above the Packages table.
-    """
-
-    # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
-    with open(path) as fp:
-        content = fp.read()
-
-    chunk1 = Chunk(content, """<div class="header">
-<div class="subTitle">
-<div class="block">""", """</div>
-</div>
-<p>See: <a href="#overview.description">Description</a></p>
-</div>""")
-
-    chunk2 = Chunk(content, """<div class="contentContainer"><a name="overview.description">
-<!--   -->
-</a>
-<div class="block">""", """</div>
-</div>
-<!-- ======= START OF BOTTOM NAVBAR ====== -->""")
-
-    assert chunk1.text, 'Could not find header section in ' + path
-    assert chunk2.text, 'Could not find footer section in ' + path
-
-    content = chunk1.replace(content, '<div class="header"><div class="subTitle"><div class="block">' + topLink + chunk2.text + '</div></div></div>')
-    content = chunk2.replace(content, '')
-
-    with open(path, 'w') as fp:
-        fp.write(content)
-
-
-# Post-process a package-summary.html file to move the
-# complete package description to the top of the page
-def _fix_package_summary(path):
-    """
-    Processes an "overview-summary.html" generated by javadoc to put the complete
-    summary text above the Packages table.
-    """
-
-    # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
-    with open(path) as fp:
-        content = fp.read()
-
-    chunk1 = Chunk(content, """<div class="header">
-<h1 title="Package" class="title">Package""", """<p>See:&nbsp;<a href="#package.description">Description</a></p>
-</div>""")
-
-    chunk2 = Chunk(content, """<a name="package.description">
-<!--   -->
-</a>""", """</div>
-</div>
-<!-- ======= START OF BOTTOM NAVBAR ====== -->""")
-
-    if chunk1.text:
-        if chunk2.text:
-            repl = re.sub(r'<h2 title=(.*) Description</h2>', r'<h1 title=\1</h1>', chunk2.text, 1)
-            content = chunk1.replace(content, '<div class="header">' + repl + '</div></div>')
-            content = chunk2.replace(content, '')
-
-            with open(path, 'w') as fp:
-                fp.write(content)
-        else:
-            log('warning: Could not find package description detail section in ' + path)
-
-    else:
-        # no package description given
-        pass
-
 def site(args):
     """creates a website containing javadoc and the project dependency graph"""
 
     parser = ArgumentParser(prog='site')
     parser.add_argument('-d', '--base', action='store', help='directory for generated site', required=True, metavar='<dir>')
+    parser.add_argument('--tmp', action='store', help='directory to use for intermediate results', metavar='<dir>')
     parser.add_argument('--name', action='store', help='name of overall documentation', required=True, metavar='<name>')
     parser.add_argument('--overview', action='store', help='path to the overview content for overall documentation', required=True, metavar='<path>')
     parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)')
@@ -4130,7 +4352,7 @@
     args = parser.parse_args(args)
 
     args.base = os.path.abspath(args.base)
-    tmpbase = tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base))
+    tmpbase = args.tmp if args.tmp else  tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base))
     unified = join(tmpbase, 'all')
 
     exclude_packages_arg = []
@@ -4179,6 +4401,9 @@
                  '--arg', '@-windowtitle', '--arg', '@' + title,
                  '--arg', '@-doctitle', '--arg', '@' + title,
                  '--arg', '@-overview', '--arg', '@' + args.overview] + exclude_packages_arg + projects_arg + extra_javadoc_args)
+
+        if exists(unified):
+            shutil.rmtree(unified)
         os.rename(join(tmpbase, 'javadoc'), unified)
 
         # Generate dependency graph with Graphviz
@@ -4232,29 +4457,17 @@
             with open(html, 'w') as fp:
                 print >> fp, '<html><body><object data="{}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base)
 
-        top = join(tmpbase, 'all', 'overview-summary.html')
-        for root, _, files in os.walk(tmpbase):
-            for f in files:
-                if f == 'overview-summary.html':
-                    path = join(root, f)
-                    topLink = ''
-                    if top != path:
-                        link = os.path.relpath(join(tmpbase, 'all', 'index.html'), dirname(path))
-                        topLink = '<p><a href="' + link + '", target="_top"><b>[return to the overall ' + args.name + ' documentation]</b></a></p>'
-                    _fix_overview_summary(path, topLink)
-                elif f == 'package-summary.html':
-                    path = join(root, f)
-                    _fix_package_summary(path)
-
-
         if exists(args.base):
             shutil.rmtree(args.base)
-        shutil.move(tmpbase, args.base)
+        if args.tmp:
+            shutil.copytree(tmpbase, args.base)
+        else:
+            shutil.move(tmpbase, args.base)
 
         print 'Created website - root is ' + join(args.base, 'all', 'index.html')
 
     finally:
-        if exists(tmpbase):
+        if not args.tmp and exists(tmpbase):
             shutil.rmtree(tmpbase)
 
 def _kwArg(kwargs):
@@ -4328,6 +4541,7 @@
 
     parser = ArgumentParser(prog='exportlibs')
     parser.add_argument('-b', '--base', action='store', help='base name of archive (default: libs)', default='libs', metavar='<path>')
+    parser.add_argument('-a', '--include-all', action='store_true', help="include all defined libaries")
     parser.add_argument('--arc', action='store', choices=['tgz', 'tbz2', 'tar', 'zip'], default='tgz', help='the type of the archive to create')
     parser.add_argument('--no-sha1', action='store_false', dest='sha1', help='do not create SHA1 signature of archive')
     parser.add_argument('--no-md5', action='store_false', dest='md5', help='do not create MD5 signature of archive')
@@ -4348,9 +4562,44 @@
             else:
                 logv('[already added ' + path + ']')
 
-        for lib in _libs.itervalues():
-            if len(lib.urls) != 0 or args.include_system_libs:
-                add(lib.get_path(resolve=True), lib.path)
+        libsToExport = set()
+        if args.include_all:
+            for lib in _libs.itervalues():
+                libsToExport.add(lib)
+        else:
+            def isValidLibrary(dep):
+                if dep in _libs.iterkeys():
+                    lib = _libs[dep]
+                    if len(lib.urls) != 0 or args.include_system_libs:
+                        return lib
+                return None
+
+            # iterate over all project dependencies and find used libraries
+            for p in _projects.itervalues():
+                for dep in p.deps:
+                    r = isValidLibrary(dep)
+                    if r:
+                        libsToExport.add(r)
+
+            # a library can have other libraries as dependency
+            size = 0
+            while size != len(libsToExport):
+                size = len(libsToExport)
+                for lib in libsToExport.copy():
+                    for dep in lib.deps:
+                        r = isValidLibrary(dep)
+                        if r:
+                            libsToExport.add(r)
+
+        for lib in libsToExport:
+            add(lib.get_path(resolve=True), lib.path)
+            if lib.sha1:
+                add(lib.get_path(resolve=True) + ".sha1", lib.path + ".sha1")
+            if lib.sourcePath:
+                add(lib.get_source_path(resolve=True), lib.sourcePath)
+                if lib.sourceSha1:
+                    add(lib.get_source_path(resolve=True) + ".sha1", lib.sourcePath + ".sha1")
+
         if args.extras:
             for e in args.extras:
                 if os.path.isdir(e):
@@ -4467,7 +4716,7 @@
     'ideclean': [ideclean, ''],
     'ideinit': [ideinit, ''],
     'intellijinit': [intellijinit, ''],
-    'archive': [archive, '[options]'],
+    'archive': [_archive, '[options]'],
     'projectgraph': [projectgraph, ''],
     'pylint': [pylint, ''],
     'javap': [javap, '<class name patterns>'],
--- a/src/cpu/sparc/vm/graalCodeInstaller_sparc.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/cpu/sparc/vm/graalCodeInstaller_sparc.cpp	Fri May 30 15:09:09 2014 +0200
@@ -22,7 +22,7 @@
  */
 
 #include "graal/graalCodeInstaller.hpp"
-#include "graal/graalCompiler.hpp"
+#include "graal/graalRuntime.hpp"
 #include "graal/graalCompilerToVM.hpp"
 #include "graal/graalJavaAccess.hpp"
 
--- a/src/cpu/x86/vm/graalCodeInstaller_x86.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/cpu/x86/vm/graalCodeInstaller_x86.cpp	Fri May 30 15:09:09 2014 +0200
@@ -25,7 +25,6 @@
 #include "compiler/disassembler.hpp"
 #include "runtime/javaCalls.hpp"
 #include "graal/graalEnv.hpp"
-#include "graal/graalCompiler.hpp"
 #include "graal/graalCodeInstaller.hpp"
 #include "graal/graalJavaAccess.hpp"
 #include "graal/graalCompilerToVM.hpp"
--- a/src/cpu/x86/vm/templateTable_x86_64.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/cpu/x86/vm/templateTable_x86_64.cpp	Fri May 30 15:09:09 2014 +0200
@@ -107,10 +107,6 @@
   return Address(rsp,  Interpreter::expr_offset_in_bytes(2));
 }
 
-static inline Address at_tos_p3() {
-  return Address(rsp,  Interpreter::expr_offset_in_bytes(3));
-}
-
 // Condition conversion
 static Assembler::Condition j_not(TemplateTable::Condition cc) {
   switch (cc) {
--- a/src/gpu/hsail/vm/gpu_hsail.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail.cpp	Fri May 30 15:09:09 2014 +0200
@@ -33,7 +33,7 @@
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/ostream.hpp"
 #include "graal/graalEnv.hpp"
-#include "graal/graalCompiler.hpp"
+#include "graal/graalRuntime.hpp"
 #include "graal/graalJavaAccess.hpp"
 #include "hsailKernelArguments.hpp"
 #include "hsailJavaCallArguments.hpp"
@@ -67,7 +67,7 @@
 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"["OBJECT"["JLTHREAD"I)Z",  FN_PTR(Hsail::execute_kernel_void_1d)},
+  {CC"executeKernel0",   CC"("HS_INSTALLED_CODE"I["OBJECT"["OBJECT"["JLTHREAD"I[I)Z",  FN_PTR(Hsail::execute_kernel_void_1d)},
 };
 
 void * Hsail::_device_context = NULL;
@@ -147,7 +147,7 @@
 }
 
 GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args, jobject oops_save,
-                                                      jobject donor_threads, jint allocBytesPerWorkitem))
+                                                      jobject donor_threads, jint allocBytesPerWorkitem, jobject oop_map_array))
 
   ResourceMark rm;
   jlong nmethodValue = InstalledCode::address(kernel_handle);
@@ -163,7 +163,7 @@
     SharedRuntime::throw_and_post_jvmti_exception(JavaThread::current(), vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL);
   }
 
-  return execute_kernel_void_1d_internal((address) kernel, dimX, args, mh, nm, oops_save, donor_threads, allocBytesPerWorkitem, CHECK_0);
+return execute_kernel_void_1d_internal((address) kernel, dimX, args, mh, nm, oops_save, donor_threads, allocBytesPerWorkitem, oop_map_array, CHECK_0);
 GPU_END
 
 static void showRanges(jboolean *a, int len) {
@@ -215,9 +215,141 @@
   tty->print_cr("(%p, %p, %p), siz=%ld, free=%ld (%f%%)", start, top, end, tlabSize, tlabFree, freePct);
 }
 
+class OopSaver : public StackObj {
+private:
+  objArrayOop _oopsSaveArray;
+  typeArrayOop _oopMapArray;
+  jobject  _oops_save;
+  jobject _oop_map_array;
+  int _last_pcoffset;
+  int _last_idx;
+  int _saveAreaCounts;
 
-jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oops_save, 
-                                                jobject donor_threads, int allocBytesPerWorkitem, TRAPS) {
+  enum {
+    SAVEAREACOUNTS_OFST=0,
+    SPAN_OFST=1,
+    HEADERSIZE=2
+  }; 
+  int mapPcOffsetToIndex(int pcOffset) {
+    if (pcOffset == _last_pcoffset) {
+      return _last_idx;
+    }
+    int span = _oopMapArray->int_at(SPAN_OFST);
+    for (int idx = HEADERSIZE; idx < _oopMapArray->length(); idx += span) {
+      int ofst = _oopMapArray->int_at(idx);
+      if (ofst == pcOffset) {
+        _last_pcoffset = pcOffset;
+        _last_idx = idx + 1;
+        return _last_idx;
+      }
+    }
+    ShouldNotReachHere();
+    return -1;
+  }
+
+public:
+  OopSaver(jobject oops_save, jobject oop_map_array) {
+    _oops_save = oops_save;
+    _oop_map_array = oop_map_array;
+    _last_pcoffset = -1;
+    _saveAreaCounts = getSaveAreaCounts(oop_map_array);
+    resolveArrays();
+  }
+ 
+  void resolveArrays() {
+    _oopsSaveArray = (objArrayOop) JNIHandles::resolve(_oops_save);
+    _oopMapArray = (typeArrayOop) JNIHandles::resolve(_oop_map_array);
+  }
+
+  void * getOopForBit(HSAILFrame * hsailFrame, int bit) {
+    assert(isOop(hsailFrame, bit), "");
+    void *oop;
+    if (bit < hsailFrame->num_d_regs()) {
+      // d register
+      oop = (void*) hsailFrame->get_d_reg(bit);
+    } else {
+      // stack slot
+      int stackOffset = (bit - hsailFrame->num_d_regs()) * 8;  // 8 bytes per stack slot
+      oop = (void *) hsailFrame->get_stackslot64(stackOffset);
+    }
+    return oop;
+  }
+
+  void putOopForBit(HSAILFrame * hsailFrame, int bit, void *oop) {
+    assert(isOop(hsailFrame, bit), "");
+    if (bit < hsailFrame->num_d_regs()) {
+      // d register
+      hsailFrame->put_d_reg(bit, (jlong) oop);
+    } else {
+      // stack slot
+      int stackOffset = (bit - hsailFrame->num_d_regs()) * 8;  // 8 bytes per stack slot
+      hsailFrame->put_stackslot64(stackOffset, (jlong) oop);
+    }
+  }
+
+  void saveOopsFromFrame(HSAILFrame * hsailFrame, int deoptSlot){
+    // as used, no need to resolve arrays on each call
+    int oopsPerDeopt = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
+
+    // handle the dregister and stackSlot based oops
+    for (int bit = 0; bit < oopsPerDeopt; bit++) {
+      if (isOop(hsailFrame, bit)) {
+        void* saved_oop = getOopForBit(hsailFrame, bit);
+        int saveArrayIndex = deoptSlot * oopsPerDeopt + bit;
+        _oopsSaveArray->obj_at_put(saveArrayIndex, (oop) saved_oop);
+      }
+    }
+  }
+
+  void restoreOopsToFrame(HSAILFrame * hsailFrame, int deoptSlot, int workitem){
+    // need to re-resolve on each restore
+    resolveArrays();
+    int oopsPerDeopt = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
+
+    // handle the dregister and stackSlot based oops
+    for (int bit = 0; bit < oopsPerDeopt; bit++) {
+      if (isOop(hsailFrame, bit)) {
+        // the dregister or stack slot at this bit is an oop, retrieve it from array and put back in frame
+        int saveArrayIndex = deoptSlot * oopsPerDeopt + bit;
+        void * newValue = (void *) _oopsSaveArray->obj_at(saveArrayIndex);
+        void * oldValue = getOopForBit(hsailFrame, bit);
+        assert((oldValue != 0 ? newValue != 0 : newValue == 0), "bad dregValue retrieved");
+        if (newValue != oldValue) {
+          if (TraceGPUInteraction) {
+            int numDRegs = hsailFrame->num_d_regs();
+            const char *name = (bit < numDRegs ? "$d" : "stk");
+            int num = (bit < numDRegs ? bit : bit - numDRegs);
+            tty->print_cr("oop moved for %s%d, workitem %d, slot %d, old=%p, new=%p",
+                          name, num, workitem, deoptSlot, oldValue, newValue);
+          }
+          putOopForBit(hsailFrame, bit, newValue);
+        }
+      }
+    }
+  }
+
+  bool isOop(HSAILFrame * hsailFrame, int bit){
+    // re-resolve on each access
+    resolveArrays();
+    if (bit > hsailFrame->num_d_regs() + hsailFrame->num_stack_slots()) {
+      return false;
+    }
+    int pcOffset = hsailFrame->pc_offset();
+    int bits_int_idx = mapPcOffsetToIndex(pcOffset) + (bit / 32);
+    int bitpos = bit % 32;
+    int bits = _oopMapArray->int_at(bits_int_idx);
+    return ((bits & (1 << bitpos)) != 0);
+  }
+
+  static int getSaveAreaCounts(jobject oopMapArrayObject) {
+    typeArrayOop oopMapArray = (typeArrayOop) JNIHandles::resolve(oopMapArrayObject);
+    return oopMapArray->int_at(SAVEAREACOUNTS_OFST);
+  }
+
+};
+
+jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oops_save,
+                                                jobject donor_threads, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS) {
   ResourceMark rm(THREAD);
   objArrayOop argsArray = (objArrayOop) JNIHandles::resolve(args);
 
@@ -262,10 +394,14 @@
 
   HSAILDeoptimizationInfo* e;
   if (UseHSAILDeoptimization) {
-    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));
-    e->set_donor_threads(donorThreads);
+    // get how many bytes per deopt save area are required
+    int saveAreaCounts = OopSaver::getSaveAreaCounts(oop_map_array);
+    int numSRegs = saveAreaCounts & 0xff;
+    int numDRegs = (saveAreaCounts >> 8) & 0xff;
+    int numStackSlots = (saveAreaCounts >> 16);
+    int bytesPerSaveArea = numSRegs * 4 + (numDRegs + numStackSlots) * 8;
+
+    e = new (MAX_DEOPT_SLOTS, bytesPerSaveArea) HSAILDeoptimizationInfo(MAX_DEOPT_SLOTS, bytesPerSaveArea, dimX, donorThreads);
   }
 
   // This object sets up the kernel arguments
@@ -316,9 +452,7 @@
   }
 
   if (UseHSAILDeoptimization) {
-    kernelStats.incDeopts();
     // check if any workitem requested a deopt
-    // currently we only support at most one such workitem
     int deoptcode = e->deopt_occurred();
     if (deoptcode != 1) {
       if (deoptcode == 0) {
@@ -332,45 +466,36 @@
         guarantee(deoptcode == 1, msg);
       }
     } else {
+      kernelStats.incDeopts();
 
       {
         TraceTime t3("handle deoptimizing workitems", TraceGPUInteraction);
         if (TraceGPUInteraction) {
           tty->print_cr("deopt happened.");
-          HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[0];
+          HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(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.
+        OopSaver oopSaver(oops_save, oop_map_array);
         // resolve handle only needed once here (not exiting vm mode)
-        objArrayOop oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save);
+        oopSaver.resolveArrays();
 
         // 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");
+        assert(e->num_deopts() < e->num_slots(), "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);
-              }
-            }
-          }
+          HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(k);
+          assert (pdeopt->workitem() >= 0, "bad workitem in deopt");
+          // this is a workitem that deopted
+          oopSaver.saveOopsFromFrame(pdeopt->first_frame(), k);
         }
 
         // Handle any deopting workitems.
         int count_deoptimized = 0;
         for (int k = 0; k < e->num_deopts(); k++) {
-          HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[k];
+          HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(k);
 
           jint workitem = pdeopt->workitem();
           if (workitem != -1) {
@@ -378,25 +503,8 @@
             HSAILFrame *hsailFrame = pdeopt->first_frame();
 
             // update the hsailFrame from the oopsSaveArray
-            // re-resolve the handle
-            oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save);
-
-            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);
-              }
-            }
+            // will re-resolve the handles each time
+            oopSaver.restoreOopsToFrame(hsailFrame, k, workitem);
 
             JavaValue result(T_VOID);
             JavaCallArguments javaArgs;
@@ -410,12 +518,19 @@
             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));
+              tty->print_cr("[HSAIL] Deoptimizing to host for workitem=%d (slot=%d) with deoptId=%d, frame=" INTPTR_FORMAT ", actionAndReason=%d", workitem, k, deoptId, hsailFrame, myActionReason);
+              // show the $d registers or stack slots containing references
+              int maxOopBits = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
+              for (int bit = 0; bit < maxOopBits; bit++) {
+                if (oopSaver.isOop(hsailFrame, bit)) {
+                  if (bit < hsailFrame->num_d_regs()) {
+                    // show $d reg oop
+                    tty->print_cr("  oop $d%d = %p", bit, oopSaver.getOopForBit(hsailFrame, bit));
+                  } else {
+                    // show stack slot oop
+                    int stackOffset = (bit - hsailFrame->num_d_regs()) * 8;  // 8 bytes per stack slot
+                    tty->print_cr("  oop stk:%d = %p", stackOffset, oopSaver.getOopForBit(hsailFrame, bit));
+                  }
                 }
               }
             }
@@ -461,14 +576,13 @@
           }
         }
         TraceGPUInteraction = savedTraceGPUInteraction;
-        if (TraceGPUInteraction) {
+        if (TraceGPUInteraction && (count_never_ran > 0)) {
           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
     }
 
-    FREE_C_HEAP_ARRAY(jboolean, e->never_ran_array(), mtInternal);
     delete e;
   }
   kernelStats.finishDispatch();
--- a/src/gpu/hsail/vm/gpu_hsail.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail.hpp	Fri May 30 15:09:09 2014 +0200
@@ -32,43 +32,70 @@
 class Hsail : public Gpu {
 
   public:
-  class HSAILKernelDeoptimization {
+  class HSAILKernelDeoptimization VALUE_OBJ_CLASS_SPEC {
     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
+    // for now, though we only ever have one hsail frame
     jint  _workitemid;
     jint  _actionAndReason;
-    // the first (innermost) "hsail frame" starts here
-    HSAILFrame _first_frame;
+    // the first (innermost) "hsail frame" starts after the above fields
 
    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; }
+    inline jint pc_offset() { return first_frame()->pc_offset(); }
+    inline HSAILFrame *first_frame() {
+      // starts after the "header" fields
+      return (HSAILFrame *) (((jbyte *) this) + sizeof(*this));
+    }
   };
 
 // 8 compute units * 40 waves per cu * wavesize 64
-#define MAX_DEOPT_SAVE_STATES_SIZE    (8 * 40 * 64)
+// TODO: query the device to get this number
+#define MAX_DEOPT_SLOTS    (8 * 40 * 64)
 
-  class HSAILDeoptimizationInfo : public ResourceObj {
+  class HSAILDeoptimizationInfo : public CHeapObj<mtInternal> {
     friend class VMStructs;
    private:
     jint* _notice_safepoints;
     jint _deopt_occurred;
     jint _deopt_next_index;
     JavaThread** _donor_threads;
-    jboolean * _never_ran_array;
+    jint _num_slots;
+    jint _deopt_span;
+    char _ignore;
+    // keep a pointer last so save area following it is word aligned
+    jboolean * _never_ran_array; 
 
    public:
-    HSAILKernelDeoptimization _deopt_save_states[MAX_DEOPT_SAVE_STATES_SIZE];
+    HSAILKernelDeoptimization _deopt_save_states[1];  // number and size of these can vary per kernel
+
+    static inline size_t hdr_size() {
+      return sizeof(HSAILDeoptimizationInfo);
+    }
 
-    inline HSAILDeoptimizationInfo() {
+    inline jbyte * save_area_start() {
+      return (jbyte*) (this) + hdr_size();
+    }
+
+    inline HSAILDeoptimizationInfo(int numSlots, int bytesPerSaveArea, int dimX, JavaThread** donorThreads) {
       _notice_safepoints = &Hsail::_notice_safepoints;
       _deopt_occurred = 0;
       _deopt_next_index = 0;
+      _num_slots = numSlots;
+      _never_ran_array = NEW_C_HEAP_ARRAY(jboolean, dimX, mtInternal);
+      memset(_never_ran_array, 0, dimX * sizeof(jboolean));
+      _donor_threads = donorThreads;
+      _deopt_span = sizeof(HSAILKernelDeoptimization) + sizeof(HSAILFrame) + bytesPerSaveArea;
+      if (TraceGPUInteraction) {
+        tty->print_cr("HSAILDeoptimizationInfo allocated, %d slots of size %d, total size = 0x%lx bytes", _num_slots, _deopt_span, (_num_slots * _deopt_span + sizeof(HSAILDeoptimizationInfo)));
+      }
+    }
+
+    inline ~HSAILDeoptimizationInfo() {
+      FREE_C_HEAP_ARRAY(jboolean, _never_ran_array, mtInternal);
     }
 
     inline jint deopt_occurred() {
@@ -76,11 +103,24 @@
     }
     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; }
-    inline void  set_donor_threads(JavaThread **threads) { _donor_threads = threads; }
+    inline jint num_slots() {return _num_slots;}
+
+    inline HSAILKernelDeoptimization * get_deopt_save_state(int slot) {
+      // use _deopt_span to index into _deopt_states
+      return (HSAILKernelDeoptimization *) (save_area_start() + _deopt_span * slot);
+    }
+
+    void * operator new (size_t hdrSize, int numSlots, int bytesPerSaveArea) {
+      assert(hdrSize <= hdr_size(), "");
+      size_t totalSizeBytes = hdr_size()  + numSlots * (sizeof(HSAILKernelDeoptimization) + sizeof(HSAILFrame) + bytesPerSaveArea);
+      return NEW_C_HEAP_ARRAY(char, totalSizeBytes, mtInternal);
+    }
+
+    void operator delete (void *ptr) {
+      FREE_C_HEAP_ARRAY(char, ptr, mtInternal);
+    }
   };
 
-
 private:
 
   static JNINativeMethod HSAIL_methods[];
@@ -93,7 +133,7 @@
 
   // 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, jobject oopsSave,
-                                                   jobject donorThreads, int allocBytesPerWorkitem);
+                                                   jobject donorThreads, int allocBytesPerWorkitem, jobject oop_map_array);
 
   // static native void getThreadPointers(Object[] donorThreads, long[] threadPointersOut);
   JNIEXPORT static void get_thread_pointers(JNIEnv *env, jclass, jobject donor_threads_handle, jobject thread_ptrs_handle);
@@ -101,8 +141,8 @@
   static void getNewTlabForDonorThread(ThreadLocalAllocBuffer* tlab, size_t tlabMinHsail);
 
   static jboolean execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oopsSave,
-                                                  jobject donor_threads, int allocBytesPerWorkitem, TRAPS);
-  
+                                                  jobject donorThreads, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS);
+
   static void register_heap();
 
   static GraalEnv::CodeInstallResult install_code(Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations);
--- a/src/gpu/hsail/vm/gpu_hsail_Frame.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail_Frame.hpp	Fri May 30 15:09:09 2014 +0200
@@ -1,3 +1,27 @@
+/*
+ * 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.
+ *
+ */
+
 #ifndef GPU_HSAIL_FRAME_HPP
 #define GPU_HSAIL_FRAME_HPP
 
@@ -5,39 +29,44 @@
 #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 {
+class HSAILFrame VALUE_OBJ_CLASS_SPEC {
   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];  
+  jshort _num_stack_slots; 
 
 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; }
+  jint num_stack_slots() {return _num_stack_slots; }
+  jbyte * data_start() {return (jbyte *) this  + sizeof(*this); }
   jlong get_d_reg(int idx) {
-    char *p = (char *) _save_area;
     int ofst = num_s_regs() * 4 + idx * 8;
-    return(*(jlong *) (p + ofst));
+    return(*(jlong *) (data_start() + ofst));
   }
   jint get_s_reg(int idx) {
-    char *p = (char *) _save_area;
     int ofst = idx * 4;
-    return(*(jint *) (p + ofst));
+    return(*(jint *) (data_start() + 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;
+    (*(jlong *) (data_start() + ofst)) = val;
+  }
+  jint get_stackslot32(int stackOffset) {
+    int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
+    return(*(jint *) (data_start() + ofst));
+  }
+  jlong get_stackslot64(int stackOffset) {
+    int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
+    return(*(jlong *) (data_start() + ofst));
+  }
+  void put_stackslot64(int stackOffset, jlong val) {
+    int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
+    (*(jlong *) (data_start() + ofst)) = val;
   }
 };
   
--- a/src/gpu/hsail/vm/vmStructs_hsail.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/gpu/hsail/vm/vmStructs_hsail.hpp	Fri May 30 15:09:09 2014 +0200
@@ -32,22 +32,20 @@
 // constants required by the Serviceability Agent. This file is
 // referenced by vmStructs.cpp.
 
-#define VM_STRUCTS_GPU_HSAIL(nonstatic_field)                                                                                         \
+#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(HSAILFrame, _num_d_regs,                                                 jbyte)                                     \
+  nonstatic_field(HSAILFrame, _num_stack_slots,                                            jshort)                                    \
                                                                                                                                       \
   nonstatic_field(Hsail::HSAILKernelDeoptimization, _workitemid,                                jint)                                 \
   nonstatic_field(Hsail::HSAILKernelDeoptimization, _actionAndReason,                           jint)                                 \
-  nonstatic_field(Hsail::HSAILKernelDeoptimization, _first_frame,                               HSAILFrame)                           \
                                                                                                                                       \
   nonstatic_field(Hsail::HSAILDeoptimizationInfo, _notice_safepoints,                      jint*)                                     \
   nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_occurred,                         jint)                                      \
   nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_next_index,                       jint)                                      \
   nonstatic_field(Hsail::HSAILDeoptimizationInfo, _donor_threads,                          JavaThread**)                              \
   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)                                  \
--- a/src/gpu/ptx/vm/gpu_ptx.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/gpu/ptx/vm/gpu_ptx.cpp	Fri May 30 15:09:09 2014 +0200
@@ -34,7 +34,7 @@
 #include "runtime/interfaceSupport.hpp"
 #include "runtime/vframe.hpp"
 #include "graal/graalEnv.hpp"
-#include "graal/graalCompiler.hpp"
+#include "graal/graalRuntime.hpp"
 
 #define T_BYTE_SIZE        1
 #define T_BOOLEAN_SIZE     4
--- a/src/share/vm/classfile/systemDictionary.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/classfile/systemDictionary.cpp	Fri May 30 15:09:09 2014 +0200
@@ -216,7 +216,7 @@
 // Forwards to resolve_instance_class_or_null
 
 Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
-  assert(!THREAD->is_Compiler_thread(),
+  assert(THREAD->can_call_java(),
          err_msg("can not load classes with compiler thread: class=%s, classloader=%s",
                  class_name->as_C_string(),
                  class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string()));
@@ -2347,7 +2347,7 @@
                                                           TRAPS) {
   methodHandle empty;
   assert(EnableInvokeDynamic, "");
-  assert(!THREAD->is_Compiler_thread(), "");
+  assert(THREAD->can_call_java() ,"");
   Handle method_type =
     SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty));
   if (false) {  // FIXME: Decide if the Java upcall should resolve signatures.
@@ -2400,7 +2400,7 @@
   if (spe != NULL && spe->method_type() != NULL) {
     assert(java_lang_invoke_MethodType::is_instance(spe->method_type()), "");
     return Handle(THREAD, spe->method_type());
-  } else if (THREAD->is_Compiler_thread()) {
+  } else if (!THREAD->can_call_java()) {
     warning("SystemDictionary::find_method_handle_type called from compiler thread");  // FIXME
     return Handle();  // do not attempt from within compiler, unless it was cached
   }
--- a/src/share/vm/classfile/systemDictionary.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Fri May 30 15:09:09 2014 +0200
@@ -203,7 +203,6 @@
   do_klass(HotSpotCodeInfo_klass,                 com_oracle_graal_hotspot_meta_HotSpotCodeInfo,                Opt) \
   do_klass(HotSpotInstalledCode_klass,            com_oracle_graal_hotspot_meta_HotSpotInstalledCode,           Opt) \
   do_klass(HotSpotNmethod_klass,                  com_oracle_graal_hotspot_meta_HotSpotNmethod,                 Opt) \
-  do_klass(HotSpotJavaType_klass,                 com_oracle_graal_hotspot_meta_HotSpotJavaType,                Opt) \
   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) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri May 30 15:09:09 2014 +0200
@@ -297,8 +297,6 @@
   template(com_oracle_graal_graph_NodeClass,                         "com/oracle/graal/graph/NodeClass")                              \
   /* 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")                       \
   template(com_oracle_graal_hotspot_HotSpotCompiledCode,             "com/oracle/graal/hotspot/HotSpotCompiledCode")                  \
   template(com_oracle_graal_hotspot_HotSpotCompiledCode_Comment,     "com/oracle/graal/hotspot/HotSpotCompiledCode$Comment")          \
   template(com_oracle_graal_hotspot_HotSpotCompiledNmethod,          "com/oracle/graal/hotspot/HotSpotCompiledNmethod")               \
@@ -314,7 +312,6 @@
   template(com_oracle_graal_hotspot_meta_HotSpotCodeInfo,            "com/oracle/graal/hotspot/meta/HotSpotCodeInfo")                 \
   template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode,       "com/oracle/graal/hotspot/meta/HotSpotInstalledCode")            \
   template(com_oracle_graal_hotspot_meta_HotSpotNmethod,             "com/oracle/graal/hotspot/meta/HotSpotNmethod")                  \
-  template(com_oracle_graal_hotspot_meta_HotSpotJavaType,            "com/oracle/graal/hotspot/meta/HotSpotJavaType")                 \
   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")             \
@@ -325,12 +322,10 @@
   template(com_oracle_graal_api_meta_Constant,                       "com/oracle/graal/api/meta/Constant")                            \
   template(com_oracle_graal_api_meta_PrimitiveConstant,              "com/oracle/graal/api/meta/PrimitiveConstant")                   \
   template(com_oracle_graal_api_meta_NullConstant,                   "com/oracle/graal/api/meta/NullConstant")                        \
-  template(com_oracle_graal_api_meta_ConstantPool,                   "com/oracle/graal/api/meta/ConstantPool")                        \
   template(com_oracle_graal_api_meta_ExceptionHandler,               "com/oracle/graal/api/meta/ExceptionHandler")                    \
   template(com_oracle_graal_api_meta_JavaMethod,                     "com/oracle/graal/api/meta/JavaMethod")                          \
   template(com_oracle_graal_api_meta_JavaType,                       "com/oracle/graal/api/meta/JavaType")                            \
   template(com_oracle_graal_api_meta_Kind,                           "com/oracle/graal/api/meta/Kind")                                \
-  template(com_oracle_graal_api_meta_ResolvedJavaField,              "com/oracle/graal/api/meta/ResolvedJavaField")                   \
   template(com_oracle_graal_api_meta_Value,                          "com/oracle/graal/api/meta/Value")                               \
   /* graal.api.code */                                                                                                                \
   template(com_oracle_graal_api_code_Assumptions,                    "com/oracle/graal/api/code/Assumptions")                         \
@@ -360,27 +355,13 @@
   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_hotspot_HotSpotTruffleRuntime,   "com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime")        \
-  template(startCompiler_name,                    "startCompiler")                                                                    \
-  template(bootstrap_name,                        "bootstrap")                                                                        \
-  template(compileTheWorld_name,                  "compileTheWorld")                                                                  \
-  template(shutdownCompiler_name,                 "shutdownCompiler")                                                                 \
+  /* graal method and field names */                                                                                                  \
   template(compileMethod_name,                    "compileMethod")                                                                    \
-  template(compileMethod_signature,               "(JIZ)V")                                                                           \
+  template(compileMethod_signature,               "(JIJZ)V")                                                                          \
   template(setOption_name,                        "setOption")                                                                        \
   template(setOption_signature,                   "(Ljava/lang/String;)Z")                                                            \
-  template(finalizeOptions_name,                  "finalizeOptions")                                                                  \
   template(getVMToCompiler_name,                  "getVMToCompiler")                                                                  \
   template(getVMToCompiler_signature,             "()Lcom/oracle/graal/hotspot/bridge/VMToCompiler;")                                 \
-  template(runtime_name,                          "runtime")                                                                          \
-  template(runtime_signature,                     "()Lcom/oracle/graal/hotspot/HotSpotGraalRuntime;")                                 \
-  template(makeInstance_name,                     "makeInstance")                                                                     \
-  template(makeInstance_signature,                "()Lcom/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime;")                       \
-  template(initialize_name,                       "initialize")                                                                       \
-  template(forObject_name,                        "forObject")                                                                        \
-  template(callbackInternal_name,                 "callbackInternal")                                                                 \
-  template(callback_signature,                    "(Ljava/lang/Object;)Ljava/lang/Object;")                                           \
                                                                       \
   /* common method and field names */                                                             \
   template(object_initializer_name,                   "<init>")                                   \
--- a/src/share/vm/code/debugInfoRec.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/code/debugInfoRec.cpp	Fri May 30 15:09:09 2014 +0200
@@ -235,16 +235,13 @@
 
 
 int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) {
-  // It's always a space win to share and Graal generates quite a bit
-  // of scopes data so always enable the sharing logic with Graal.
-  // Presumably this is disabled in regular HotSpot because it makes
-  // recording more expensive?
-#ifndef GRAAL
-  // Only pull this trick if non-safepoint recording
-  // is enabled, for now.
-  if (!recording_non_safepoints())
+  if (FLAG_IS_DEFAULT(ShareDebugInfo)) {
+    if (!ShareDebugInfo && !recording_non_safepoints()) {
+      return serialized_null;
+    }
+  } else if (!ShareDebugInfo) {
     return serialized_null;
-#endif
+  }
 
   NOT_PRODUCT(++dir_stats.chunks_queried);
   int stream_length = stream()->position() - stream_offset;
--- a/src/share/vm/code/nmethod.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/code/nmethod.cpp	Fri May 30 15:09:09 2014 +0200
@@ -142,6 +142,7 @@
   int handler_table_size;
   int nul_chk_table_size;
   int oops_size;
+  int metadata_size;
 
   void note_nmethod(nmethod* nm) {
     nmethod_count += 1;
@@ -151,6 +152,7 @@
     insts_size          += nm->insts_size();
     stub_size           += nm->stub_size();
     oops_size           += nm->oops_size();
+    metadata_size       += nm->metadata_size();
     scopes_data_size    += nm->scopes_data_size();
     scopes_pcs_size     += nm->scopes_pcs_size();
     dependencies_size   += nm->dependencies_size();
@@ -161,11 +163,13 @@
     if (nmethod_count == 0)  return;
     tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name);
     if (total_size != 0)          tty->print_cr(" total in heap  = %d", total_size);
+    if (nmethod_count != 0)       tty->print_cr(" header         = %d", nmethod_count * sizeof(nmethod));
     if (relocation_size != 0)     tty->print_cr(" relocation     = %d", relocation_size);
     if (consts_size != 0)         tty->print_cr(" constants      = %d", consts_size);
     if (insts_size != 0)          tty->print_cr(" main code      = %d", insts_size);
     if (stub_size != 0)           tty->print_cr(" stub code      = %d", stub_size);
     if (oops_size != 0)           tty->print_cr(" oops           = %d", oops_size);
+    if (metadata_size != 0)       tty->print_cr(" metadata       = %d", metadata_size);
     if (scopes_data_size != 0)    tty->print_cr(" scopes data    = %d", scopes_data_size);
     if (scopes_pcs_size != 0)     tty->print_cr(" scopes pcs     = %d", scopes_pcs_size);
     if (dependencies_size != 0)   tty->print_cr(" dependencies   = %d", dependencies_size);
@@ -180,12 +184,14 @@
   int native_relocation_size;
   int native_insts_size;
   int native_oops_size;
+  int native_metadata_size;
   void note_native_nmethod(nmethod* nm) {
     native_nmethod_count += 1;
     native_total_size       += nm->size();
     native_relocation_size  += nm->relocation_size();
     native_insts_size       += nm->insts_size();
     native_oops_size        += nm->oops_size();
+    native_metadata_size    += nm->metadata_size();
   }
   void print_native_nmethod_stats() {
     if (native_nmethod_count == 0)  return;
@@ -194,6 +200,7 @@
     if (native_relocation_size != 0)  tty->print_cr(" N. relocation  = %d", native_relocation_size);
     if (native_insts_size != 0)       tty->print_cr(" N. main code   = %d", native_insts_size);
     if (native_oops_size != 0)        tty->print_cr(" N. oops        = %d", native_oops_size);
+    if (native_metadata_size != 0)    tty->print_cr(" N. metadata    = %d", native_metadata_size);
   }
 };
 
@@ -229,11 +236,18 @@
 #ifdef GRAAL
 static java_nmethod_stats_struct graal_java_nmethod_stats;
 #endif
+#ifdef SHARK
+static java_nmethod_stats_struct shark_java_nmethod_stats;
+#endif
 static java_nmethod_stats_struct unknown_java_nmethod_stats;
 
 static native_nmethod_stats_struct native_nmethod_stats;
 static pc_nmethod_stats_struct pc_nmethod_stats;
 
+static void note_native_wrapper_nmethod(nmethod* nm) {
+  native_nmethod_stats.note_native_nmethod(nm);
+}
+
 static void note_java_nmethod(nmethod* nm) {
 #ifdef COMPILER1
   if (nm->is_compiled_by_c1()) {
@@ -250,6 +264,11 @@
     graal_java_nmethod_stats.note_nmethod(nm);
   } else
 #endif
+#ifdef SHARK
+  if (nm->is_compiled_by_shark()) {
+    shark_java_nmethod_stats.note_nmethod(nm);
+  } else
+#endif
   {
     unknown_java_nmethod_stats.note_nmethod(nm);
   }
@@ -556,7 +575,7 @@
                                             code_buffer, frame_size,
                                             basic_lock_owner_sp_offset,
                                             basic_lock_sp_offset, oop_maps);
-    if (nm != NULL)  note_java_nmethod(nm);
+    if (nm != NULL)  note_native_wrapper_nmethod(nm);
     if (PrintAssembly && nm != NULL) {
       Disassembler::decode(nm);
     }
@@ -1045,7 +1064,6 @@
 void nmethod::print_on(outputStream* st, const char* msg) const {
   if (st != NULL) {
     ttyLocker ttyl;
-    if (CIPrintCompilerName) st->print("%s:", compiler()->name());
     if (WizardMode) {
       CompileTask::print_compilation(st, this, msg, /*short_form:*/ true);
       st->print_cr(" (" INTPTR_FORMAT ")", this);
@@ -3083,9 +3101,14 @@
 #ifdef GRAAL
   graal_java_nmethod_stats.print_nmethod_stats("Graal");
 #endif
+#ifdef SHARK
+  shark_java_nmethod_stats.print_nmethod_stats("Shark");
+#endif
   unknown_java_nmethod_stats.print_nmethod_stats("Unknown");
   DebugInformationRecorder::print_statistics();
+#ifndef PRODUCT
   pc_nmethod_stats.print_pc_stats();
+#endif
   Dependencies::print_statistics();
   if (xtty != NULL)  xtty->tail("statistics");
 }
--- a/src/share/vm/compiler/compileBroker.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.cpp	Fri May 30 15:09:09 2014 +0200
@@ -370,8 +370,6 @@
 // CompileTask::print_line
 void CompileTask::print_line() {
   ttyLocker ttyl;  // keep the following output all in one block
-  // print compiler name if requested
-  if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
   print_compilation();
 }
 
@@ -384,6 +382,8 @@
   if (!short_form) {
     st->print("%7d ", (int) st->time_stamp().milliseconds());  // print timestamp
   }
+  // print compiler name if requested
+  if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level));
   st->print("%4d ", compile_id);    // print compilation number
 
   // For unloaded methods the transition to zombie occurs after the
@@ -516,7 +516,8 @@
   if (_osr_bci != CompileBroker::standard_entry_bci) {
     log->print(" osr_bci='%d'", _osr_bci);
   }
-  if (_comp_level != CompLevel_highest_tier) {
+  // Always print the level in tiered.
+  if (_comp_level != CompLevel_highest_tier || TieredCompilation) {
     log->print(" level='%d'", _comp_level);
   }
   if (_is_blocking) {
@@ -804,7 +805,7 @@
 
 #if defined(COMPILERGRAAL)
   _compilers[1] = graal;
-  c2_count = 0;
+  c2_count = UseGraalCompilationQueue ? 0 : c2_count;
 #endif // COMPILERGRAAL
 
 #ifdef COMPILER2
@@ -1143,22 +1144,24 @@
     return;
   }
 
-#if defined(COMPILERGRAAL)
-  // In tiered mode we want to only handle highest tier compiles and
-  // in non-tiered mode the default level should be
-  // CompLevel_full_optimization which equals CompLevel_highest_tier.
-  assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level");
-  assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition");
-  if (comp_level == CompLevel_full_optimization) {
-    if (!JavaThread::current()->is_graal_compiling()) {
-      bool blockingCompilation = is_compile_blocking(method, osr_bci);
-      GraalCompiler::instance()->compile_method(method, osr_bci, blockingCompilation);
-    } else {
-      // Can't enqueue this request because there would be no one to service it, so simply return.
+#ifdef COMPILERGRAAL
+  if (UseGraalCompilationQueue) {
+    // In tiered mode we want to only handle highest tier compiles and
+    // in non-tiered mode the default level should be
+    // CompLevel_full_optimization which equals CompLevel_highest_tier.
+    assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level");
+    assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition");
+    if (comp_level == CompLevel_full_optimization) {
+      if (!JavaThread::current()->is_graal_compiling()) {
+        bool blockingCompilation = is_compile_blocking(method, osr_bci);
+        GraalCompiler::instance()->compile_method(method, osr_bci, NULL, blockingCompilation);
+      } else {
+        // Can't enqueue this request because there would be no one to service it, so simply return.
+      }
+      return;
     }
-    return;
+    assert(TieredCompilation, "should only reach here in tiered mode");
   }
-  assert(TieredCompilation, "should only reach here in tiered mode");
 #endif // COMPILERGRAAL
 
   // Outputs from the following MutexLocker block:
@@ -1881,6 +1884,35 @@
   tty->print(s.as_string());
 }
 
+void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) {
+
+  if (success) {
+    task->mark_success();
+    if (ci_env != NULL) {
+      task->set_num_inlined_bytecodes(ci_env->num_inlined_bytecodes());
+    }
+    if (_compilation_log != NULL) {
+      nmethod* code = task->code();
+      if (code != NULL) {
+        _compilation_log->log_nmethod(thread, code);
+      }
+    }
+  }
+
+  // simulate crash during compilation
+  assert(task->compile_id() != CICrashAt, "just as planned");
+  if (event.should_commit()) {
+    event.set_method(task->method());
+    event.set_compileID(task->compile_id());
+    event.set_compileLevel(task->comp_level());
+    event.set_succeded(task->is_success());
+    event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
+    event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
+    event.set_inlinedBytes(task->num_inlined_bytecodes());
+    event.commit();
+  }
+}
+
 // ------------------------------------------------------------------
 // CompileBroker::invoke_compiler_on_method
 //
@@ -1929,6 +1961,21 @@
   push_jni_handle_block();
   Method* target_handle = task->method();
   int compilable = ciEnv::MethodCompilable;
+  AbstractCompiler *comp = compiler(task_level);
+
+#ifdef COMPILERGRAAL
+  if (comp != NULL && comp->is_graal()) {
+    assert(!UseGraalCompilationQueue, "should not reach here");
+    GraalCompiler* graal = (GraalCompiler*) comp;
+
+    TraceTime t1("compilation", &time);
+    EventCompilation event;
+
+    graal->compile_method(target_handle, osr_bci, task, false);
+
+    post_compile(thread, task, event, task->code() != NULL, NULL);
+  } else
+#endif // COMPILERGRAAL
   {
     int system_dictionary_modification_counter;
     {
@@ -1960,7 +2007,6 @@
     TraceTime t1("compilation", &time);
     EventCompilation event;
 
-    AbstractCompiler *comp = compiler(task_level);
     if (comp == NULL) {
       ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
     } else {
@@ -1988,28 +2034,9 @@
             err_msg_res("COMPILE SKIPPED: %s",      ci_env.failure_reason());
         task->print_compilation(tty, msg);
       }
-    } else {
-      task->mark_success();
-      task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes());
-      if (_compilation_log != NULL) {
-        nmethod* code = task->code();
-        if (code != NULL) {
-          _compilation_log->log_nmethod(thread, code);
-        }
-      }
     }
-    // simulate crash during compilation
-    assert(task->compile_id() != CICrashAt, "just as planned");
-    if (event.should_commit()) {
-      event.set_method(target->get_Method());
-      event.set_compileID(compile_id);
-      event.set_compileLevel(task->comp_level());
-      event.set_succeded(task->is_success());
-      event.set_isOsr(is_osr);
-      event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
-      event.set_inlinedBytes(task->num_inlined_bytecodes());
-      event.commit();
-    }
+
+    post_compile(thread, task, event, !ci_env.failing(), &ci_env);
   }
   pop_jni_handle_block();
 
--- a/src/share/vm/compiler/compileBroker.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.hpp	Fri May 30 15:09:09 2014 +0200
@@ -28,6 +28,7 @@
 #include "ci/compilerInterface.hpp"
 #include "compiler/abstractCompiler.hpp"
 #include "runtime/perfData.hpp"
+#include "trace/tracing.hpp"
 
 class nmethod;
 class nmethodLocker;
@@ -339,6 +340,7 @@
   static void wait_for_completion(CompileTask* task);
 
   static void invoke_compiler_on_method(CompileTask* task);
+  static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
   static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level);
   static void push_jni_handle_block();
   static void pop_jni_handle_block();
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Fri May 30 15:09:09 2014 +0200
@@ -202,7 +202,7 @@
     return new LocationValue(Location::new_stk_loc(Location::invalid, 0));
   }
 
-  BasicType type = GraalCompiler::kindToBasicType(Kind::typeChar(Value::kind(value)));
+  BasicType type = GraalRuntime::kindToBasicType(Kind::typeChar(Value::kind(value)));
   Location::Type locationType = Location::normal;
   if (type == T_OBJECT || type == T_ARRAY) locationType = Location::oop;
 
@@ -382,7 +382,7 @@
 
 // constructor used to create a method
 GraalEnv::CodeInstallResult CodeInstaller::install(Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log) {
-  BufferBlob* buffer_blob = GraalCompiler::initialize_buffer_blob();
+  BufferBlob* buffer_blob = GraalRuntime::initialize_buffer_blob();
   if (buffer_blob == NULL) {
     return GraalEnv::cache_full;
   }
@@ -422,12 +422,13 @@
     methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code));
     jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code);
     jint id = HotSpotCompiledNmethod::id(compiled_code);
+    CompileTask* task = (CompileTask*) (address) HotSpotCompiledNmethod::ctask(compiled_code);
     if (id == -1) {
       // Make sure a valid compile_id is associated with every compile
       id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci);
     }
     result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
-        GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, id, false, installed_code, speculation_log);
+        GraalCompiler::instance(), _debug_recorder, _dependencies, task, id, false, installed_code, speculation_log);
     cb = nm;
   }
 
@@ -604,10 +605,11 @@
   Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(context_handle));
   Klass* subtype = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(subtype_handle));
 
-  _dependencies->assert_leaf_type(subtype);
   if (context != subtype) {
     assert(context->is_abstract(), "");
     _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype);
+  } else {
+    _dependencies->assert_leaf_type(subtype);
   }
 }
 
@@ -676,8 +678,11 @@
   oop hotspot_method = BytecodePosition::method(frame);
   Method* method = getMethodFromHotSpotMethod(hotspot_method);
   jint bci = BytecodePosition::bci(frame);
+  if (bci == BytecodeFrame::BEFORE_BCI()) {
+    bci = SynchronizationEntryBCI;
+  }
   bool reexecute;
-  if (bci == -1 || bci == -2){
+  if (bci == SynchronizationEntryBCI){
      reexecute = false;
   } else {
     Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci));
--- a/src/share/vm/graal/graalCompiler.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Fri May 30 15:09:09 2014 +0200
@@ -25,175 +25,99 @@
 #include "memory/oopFactory.hpp"
 #include "runtime/javaCalls.hpp"
 #include "graal/graalCompiler.hpp"
-#include "graal/graalJavaAccess.hpp"
 #include "graal/graalVMToCompiler.hpp"
-#include "graal/graalCompilerToVM.hpp"
 #include "graal/graalEnv.hpp"
 #include "graal/graalRuntime.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/compilationPolicy.hpp"
 #include "runtime/globals_extension.hpp"
 
 GraalCompiler* GraalCompiler::_instance = NULL;
 
 GraalCompiler::GraalCompiler() : AbstractCompiler(graal) {
-  _initialized = false;
+#ifdef COMPILERGRAAL
+  _started = false;
+#endif
   assert(_instance == NULL, "only one instance allowed");
   _instance = this;
 }
 
 // Initialization
 void GraalCompiler::initialize() {
-  
-  ThreadToNativeFromVM trans(JavaThread::current());
-  JavaThread* THREAD = JavaThread::current();
-  TRACE_graal_1("GraalCompiler::initialize");
-
-  uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end();
-  uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024;
-  AMD64_ONLY(guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"));
-  NOT_LP64(error("check TLAB allocation code for address space conflicts"));
-
-  BufferBlob* buffer_blob = initialize_buffer_blob();
-  if (buffer_blob == NULL) {
-    // If we are called from JNI_CreateJavaVM we cannot use set_state yet because it takes a lock.
-    // set_state(failed);
-  } else {
-    // set_state(initialized);
+#ifdef COMPILERGRAAL
+  if (!UseCompiler || !should_perform_init()) {
+    return;
   }
 
-  JNIEnv *env = ((JavaThread *) Thread::current())->jni_environment();
-  jclass klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToVMImpl");
-  if (klass == NULL) {
-    tty->print_cr("graal CompilerToVMImpl class not found");
-    vm_abort(false);
+  BufferBlob* buffer_blob = GraalRuntime::initialize_buffer_blob();
+  if (!UseGraalCompilationQueue) {
+    // This path is used for initialization both by the native queue and the graal queue
+    // but set_state acquires a lock which might not be safe during JVM_CreateJavaVM, so
+    // only update the state flag for the native queue.
+    if (buffer_blob == NULL) {
+      set_state(failed);
+    } else {
+      set_state(initialized);
+    }
   }
-  env->RegisterNatives(klass, CompilerToVM_methods, CompilerToVM_methods_count());
-  
-  ResourceMark rm;
-  HandleMark hm;
-  {
-    GRAAL_VM_ENTRY_MARK;
-    check_pending_exception("Could not register natives");
-  }
-
-  graal_compute_offsets();
-
-  // Ensure _non_oop_bits is initialized
-  Universe::non_oop_word();
 
   {
-    GRAAL_VM_ENTRY_MARK;
     HandleMark hm;
-    VMToCompiler::initOptions();
-    for (int i = 0; i < Arguments::num_graal_args(); ++i) {
-      const char* arg = Arguments::graal_args_array()[i];
-      Handle option = java_lang_String::create_from_str(arg, THREAD);
-      jboolean result = VMToCompiler::setOption(option);
-      if (!result) {
-        tty->print_cr("Invalid option for graal: -G:%s", arg);
-        vm_abort(false);
-      }
-    }
-    VMToCompiler::finalizeOptions(CITime || CITimeEach);
+
+    bool bootstrap = UseGraalCompilationQueue && (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal);
+    VMToCompiler::startCompiler(bootstrap);
+    _started = true;
+
+    // Graal is considered as application code so we need to
+    // stop the VM deferring compilation now.
+    CompilationPolicy::completed_vm_startup();
 
-    if (UseCompiler) {
-      _external_deopt_i2c_entry = create_external_deopt_i2c();
-#ifdef COMPILERGRAAL
-      bool bootstrap = FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal;
-#else
-      bool bootstrap = false;
+    if (bootstrap) {
+      // Avoid -Xcomp and -Xbatch problems by turning on interpreter and background compilation for bootstrapping.
+      FlagSetting a(UseInterpreter, true);
+      FlagSetting b(BackgroundCompilation, true);
+#ifndef PRODUCT
+      // Turn off CompileTheWorld during bootstrap so that a counter overflow event
+      // triggers further compilation (see NonTieredCompPolicy::event()) hence
+      // allowing a complete bootstrap
+      FlagSetting c(CompileTheWorld, false);
 #endif
-      VMToCompiler::startCompiler(bootstrap);
-      _initialized = true;
-      CompilationPolicy::completed_vm_startup();
-      if (bootstrap) {
-        // Avoid -Xcomp and -Xbatch problems by turning on interpreter and background compilation for bootstrapping.
-        FlagSetting a(UseInterpreter, true);
-        FlagSetting b(BackgroundCompilation, true);
-#ifndef PRODUCT
-        // Turn off CompileTheWorld during bootstrap so that a counter overflow event
-        // triggers further compilation (see NonTieredCompPolicy::event()) hence
-        // allowing a complete bootstrap
-        FlagSetting c(CompileTheWorld, false);
-#endif
-        VMToCompiler::bootstrap();
-      }
+      VMToCompiler::bootstrap();
+    }
 
 #ifndef PRODUCT
-      if (CompileTheWorld) {
-        // We turn off CompileTheWorld so that Graal can
-        // be compiled by C1/C2 when Graal does a CTW.
-        CompileTheWorld = false;
-        VMToCompiler::compileTheWorld();
-      }
+    if (CompileTheWorld) {
+      VMToCompiler::compileTheWorld();
+    }
 #endif
-    }
   }
+#endif // COMPILERGRAAL
 }
 
-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();
-  if (buffer_blob == NULL) {
-    buffer_blob = BufferBlob::create("Graal thread-local CodeBuffer", GraalNMethodSizeLimit);
-    if (buffer_blob != NULL) {
-      THREAD->set_buffer_blob(buffer_blob);
-    }
-  }
-  return buffer_blob;
-}
-
-void GraalCompiler::compile_method(methodHandle method, int entry_bci, jboolean blocking) {
+#ifdef COMPILERGRAAL
+void GraalCompiler::compile_method(methodHandle method, int entry_bci, CompileTask* task, jboolean blocking) {
   GRAAL_EXCEPTION_CONTEXT
-  if (!_initialized) {
+  if (!_started) {
     CompilationPolicy::policy()->delay_compilation(method());
     return;
   }
 
-  assert(_initialized, "must already be initialized");
+  assert(_started, "must already be started");
   ResourceMark rm;
   thread->set_is_graal_compiling(true);
-  VMToCompiler::compileMethod(method(), entry_bci, blocking);
+  VMToCompiler::compileMethod(method(), entry_bci, (jlong) (address) task, blocking);
   thread->set_is_graal_compiling(false);
 }
 
+
 // Compilation entry point for methods
 void GraalCompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
   ShouldNotReachHere();
 }
 
-void GraalCompiler::exit() {
-  if (_initialized) {
+void GraalCompiler::shutdown() {
+  if (_started) {
     VMToCompiler::shutdownCompiler();
+    _started = false;
   }
 }
 
@@ -202,22 +126,4 @@
   TRACE_graal_1("GraalCompiler::print_timers");
 }
 
-BasicType GraalCompiler::kindToBasicType(jchar ch) {
-  switch(ch) {
-    case 'z': return T_BOOLEAN;
-    case 'b': return T_BYTE;
-    case 's': return T_SHORT;
-    case 'c': return T_CHAR;
-    case 'i': return T_INT;
-    case 'f': return T_FLOAT;
-    case 'j': return T_LONG;
-    case 'd': return T_DOUBLE;
-    case 'a': return T_OBJECT;
-    case 'r': return T_ADDRESS;
-    case '-': return T_ILLEGAL;
-    default:
-      fatal(err_msg("unexpected Kind: %c", ch));
-      break;
-  }
-  return T_ILLEGAL;
-}
+#endif // COMPILERGRAAL
--- a/src/share/vm/graal/graalCompiler.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.hpp	Fri May 30 15:09:09 2014 +0200
@@ -26,23 +26,23 @@
 
 #include "compiler/abstractCompiler.hpp"
 
-#define LEAF_GRAPH_ARRAY_SIZE (8192)
-
 class GraalCompiler : public AbstractCompiler {
 
 private:
 
-  bool                  _initialized;
+#ifdef COMPILERGRAAL
+  // Set to true once VMToCompiler.startCompiler() returns
+  bool _started;
+#endif
 
   static GraalCompiler* _instance;
-  address               _external_deopt_i2c_entry;
+ 
 public:
 
   GraalCompiler();
 
   static GraalCompiler* instance() { return _instance; }
 
-
   virtual const char* name() { return "Graal"; }
 
   virtual bool supports_native()                 { return true; }
@@ -57,39 +57,17 @@
   // Initialization
   virtual void initialize();
 
+#ifdef COMPILERGRAAL
   // Compilation entry point for methods
   virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
 
-  void compile_method(methodHandle target, int entry_bci, jboolean blocking);
+  void compile_method(methodHandle target, int entry_bci, CompileTask* task, jboolean blocking);
 
   // Print compilation timers and statistics
   virtual void print_timers();
 
-  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();
+  void shutdown();
+#endif
 };
 
-// Tracing macros
-
-#define IF_TRACE_graal_1 if (!(TraceGraal >= 1)) ; else
-#define IF_TRACE_graal_2 if (!(TraceGraal >= 2)) ; else
-#define IF_TRACE_graal_3 if (!(TraceGraal >= 3)) ; else
-#define IF_TRACE_graal_4 if (!(TraceGraal >= 4)) ; else
-#define IF_TRACE_graal_5 if (!(TraceGraal >= 5)) ; else
-
-// using commas and else to keep one-instruction semantics
-
-#define TRACE_graal_1 if (!(TraceGraal >= 1 && (tty->print("TraceGraal-1: "), true))) ; else tty->print_cr
-#define TRACE_graal_2 if (!(TraceGraal >= 2 && (tty->print("   TraceGraal-2: "), true))) ; else tty->print_cr
-#define TRACE_graal_3 if (!(TraceGraal >= 3 && (tty->print("      TraceGraal-3: "), true))) ; else tty->print_cr
-#define TRACE_graal_4 if (!(TraceGraal >= 4 && (tty->print("         TraceGraal-4: "), true))) ; else tty->print_cr
-#define TRACE_graal_5 if (!(TraceGraal >= 5 && (tty->print("            TraceGraal-5: "), true))) ; else tty->print_cr
-
 #endif // SHARE_VM_GRAAL_GRAAL_COMPILER_HPP
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri May 30 15:09:09 2014 +0200
@@ -53,12 +53,6 @@
   TRACE_graal_3("CompilerToVM::" #name); \
   GRAAL_VM_ENTRY_MARK; \
 
-// Entry to native method implementation that calls a JNI function
-// and hence cannot transition current thread to '_thread_in_vm'.
-#define C2V_ENTRY(result_type, name, signature) \
-  JNIEXPORT result_type JNICALL c2v_ ## name signature { \
-  TRACE_graal_3("CompilerToVM::" #name); \
-
 #define C2V_END }
 
 extern "C" {
@@ -91,135 +85,16 @@
 extern uint64_t gHotSpotVMLongConstantEntryArrayStride;
 }
 
-// helpers used to set fields in the HotSpotVMConfig object
-static jfieldID getFieldID(JNIEnv* env, jobject obj, const char* name, const char* sig) {
-  jfieldID id = env->GetFieldID(env->GetObjectClass(obj), name, sig);
-  if (id == NULL) {
-    fatal(err_msg("field not found: %s (%s)", name, sig));
-  }
-  return id;
-}
-
-C2V_ENTRY(void, initializeConfiguration, (JNIEnv *env, jobject, jobject config))
-
-#define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0)
-#define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0)
-#define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0)
-#define set_address(name, value) do { set_long(name, (jlong) value); } while (0)
-
-  guarantee(HeapWordSize == sizeof(char*), "Graal assumption that HeadWordSize == machine word size is wrong");
-
-  set_address("gHotSpotVMStructs", gHotSpotVMStructs);
-  set_long("gHotSpotVMStructEntryTypeNameOffset",   gHotSpotVMStructEntryTypeNameOffset);
-  set_long("gHotSpotVMStructEntryFieldNameOffset",  gHotSpotVMStructEntryFieldNameOffset);
-  set_long("gHotSpotVMStructEntryTypeStringOffset", gHotSpotVMStructEntryTypeStringOffset);
-  set_long("gHotSpotVMStructEntryIsStaticOffset",   gHotSpotVMStructEntryIsStaticOffset);
-  set_long("gHotSpotVMStructEntryOffsetOffset",     gHotSpotVMStructEntryOffsetOffset);
-  set_long("gHotSpotVMStructEntryAddressOffset",    gHotSpotVMStructEntryAddressOffset);
-  set_long("gHotSpotVMStructEntryArrayStride",      gHotSpotVMStructEntryArrayStride);
-
-  set_address("gHotSpotVMTypes", gHotSpotVMTypes);
-  set_long("gHotSpotVMTypeEntryTypeNameOffset",       gHotSpotVMTypeEntryTypeNameOffset);
-  set_long("gHotSpotVMTypeEntrySuperclassNameOffset", gHotSpotVMTypeEntrySuperclassNameOffset);
-  set_long("gHotSpotVMTypeEntryIsOopTypeOffset",      gHotSpotVMTypeEntryIsOopTypeOffset);
-  set_long("gHotSpotVMTypeEntryIsIntegerTypeOffset",  gHotSpotVMTypeEntryIsIntegerTypeOffset);
-  set_long("gHotSpotVMTypeEntryIsUnsignedOffset",     gHotSpotVMTypeEntryIsUnsignedOffset);
-  set_long("gHotSpotVMTypeEntrySizeOffset",           gHotSpotVMTypeEntrySizeOffset);
-  set_long("gHotSpotVMTypeEntryArrayStride",          gHotSpotVMTypeEntryArrayStride);
-
-  set_address("gHotSpotVMIntConstants", gHotSpotVMIntConstants);
-  set_long("gHotSpotVMIntConstantEntryNameOffset",  gHotSpotVMIntConstantEntryNameOffset);
-  set_long("gHotSpotVMIntConstantEntryValueOffset", gHotSpotVMIntConstantEntryValueOffset);
-  set_long("gHotSpotVMIntConstantEntryArrayStride", gHotSpotVMIntConstantEntryArrayStride);
-
-  set_address("gHotSpotVMLongConstants", gHotSpotVMLongConstants);
-  set_long("gHotSpotVMLongConstantEntryNameOffset",  gHotSpotVMLongConstantEntryNameOffset);
-  set_long("gHotSpotVMLongConstantEntryValueOffset", gHotSpotVMLongConstantEntryValueOffset);
-  set_long("gHotSpotVMLongConstantEntryArrayStride", gHotSpotVMLongConstantEntryArrayStride);
-
-  //------------------------------------------------------------------------------------------------
-
-  set_int("arrayLengthOffset", arrayOopDesc::length_offset_in_bytes());
-
-  set_int("extraStackEntries", Method::extra_stack_entries());
-
-  set_int("tlabAlignmentReserve", (int32_t)ThreadLocalAllocBuffer::alignment_reserve());
-  set_long("heapTopAddress", (jlong)(address) Universe::heap()->top_addr());
-  set_long("heapEndAddress", (jlong)(address) Universe::heap()->end_addr());
-
-  set_boolean("inlineContiguousAllocationSupported", !CMSIncrementalMode && Universe::heap()->supports_inline_contig_alloc());
-
-  set_long("verifyOopMask", Universe::verify_oop_mask());
-  set_long("verifyOopBits", Universe::verify_oop_bits());
-
-  set_int("instanceKlassVtableStartOffset", InstanceKlass::vtable_start_offset() * HeapWordSize);
-
-  //------------------------------------------------------------------------------------------------
-
-  set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
-
-  set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
-  set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address);
-  set_address("osrMigrationEndAddress", SharedRuntime::OSR_migration_end);
-
-  set_address("javaTimeMillisAddress", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
-  set_address("javaTimeNanosAddress", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
-  set_address("arithmeticSinAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
-  set_address("arithmeticCosAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
-  set_address("arithmeticTanAddress", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
-
-  set_address("newInstanceAddress", GraalRuntime::new_instance);
-  set_address("newArrayAddress", GraalRuntime::new_array);
-  set_address("newMultiArrayAddress", GraalRuntime::new_multi_array);
-  set_address("dynamicNewArrayAddress", GraalRuntime::dynamic_new_array);
-  set_address("dynamicNewInstanceAddress", GraalRuntime::dynamic_new_instance);
-  set_address("threadIsInterruptedAddress", GraalRuntime::thread_is_interrupted);
-  set_address("vmMessageAddress", GraalRuntime::vm_message);
-  set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code);
-  set_address("exceptionHandlerForPcAddress", GraalRuntime::exception_handler_for_pc);
-  set_address("monitorenterAddress", GraalRuntime::monitorenter);
-  set_address("monitorexitAddress", GraalRuntime::monitorexit);
-  set_address("createNullPointerExceptionAddress", GraalRuntime::create_null_exception);
-  set_address("createOutOfBoundsExceptionAddress", GraalRuntime::create_out_of_bounds_exception);
-  set_address("logPrimitiveAddress", GraalRuntime::log_primitive);
-  set_address("logObjectAddress", GraalRuntime::log_object);
-  set_address("logPrintfAddress", GraalRuntime::log_printf);
-  set_address("vmErrorAddress", GraalRuntime::vm_error);
-  set_address("loadAndClearExceptionAddress", GraalRuntime::load_and_clear_exception);
-  set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre);
-  set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post);
-  set_address("validateObject", GraalRuntime::validate_object);
-
-  set_address("deoptimizationFetchUnrollInfo", Deoptimization::fetch_unroll_info);
-  set_address("deoptimizationUncommonTrap", Deoptimization::uncommon_trap);
-  set_address("deoptimizationUnpackFrames", Deoptimization::unpack_frames);
-
-  //------------------------------------------------------------------------------------------------
-
-  set_int("graalCountersThreadOffset", in_bytes(JavaThread::graal_counters_offset()));
-  set_int("graalCountersSize", (jint) GraalCounterSize);
-
-  //------------------------------------------------------------------------------------------------
-
-  set_long("dllLoad", (jlong) os::dll_load);
-  set_long("dllLookup", (jlong) os::dll_lookup);
-  #if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux)
-  set_long("rtldDefault", (jlong) RTLD_DEFAULT);
-  #endif
-
-#undef set_boolean
-#undef set_int
-#undef set_long
-#undef set_address
-
+C2V_VMENTRY(void, initializeConfiguration, (JNIEnv *, jobject, jobject config))
+  VMStructs::initHotSpotVMConfig(JNIHandles::resolve(config));
 C2V_END
 
-C2V_ENTRY(jbyteArray, initializeBytecode, (JNIEnv *env, jobject, jlong metaspace_method, jbyteArray result))
+C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv *, jobject, jlong metaspace_method))
   methodHandle method = asMethod(metaspace_method);
   ResourceMark rm;
 
   int code_size = method->code_size();
-  jbyte* reconstituted_code = NEW_RESOURCE_ARRAY(jbyte, code_size);
+  typeArrayOop reconstituted_code = oopFactory::new_byteArray(code_size, CHECK_NULL);
 
   guarantee(method->method_holder()->is_rewritten(), "Method's holder should be rewritten");
   // iterate over all bytecodes and replace non-Java bytecodes
@@ -231,9 +106,9 @@
     int len = s.instruction_size();
 
     // Restore original byte code.
-    reconstituted_code[bci] = (jbyte) (s.is_wide()? Bytecodes::_wide : code);
+    reconstituted_code->byte_at_put(bci, (jbyte) (s.is_wide()? Bytecodes::_wide : code));
     if (len > 1) {
-      memcpy(&reconstituted_code[bci+1], s.bcp()+1, len-1);
+      memcpy(reconstituted_code->byte_at_addr(bci + 1), s.bcp()+1, len-1);
     }
 
     if (len > 1) {
@@ -249,41 +124,39 @@
         case Bytecodes::_invokestatic:
         case Bytecodes::_invokeinterface:
         case Bytecodes::_invokehandle: {
-          int cp_index = Bytes::get_native_u2((address) &reconstituted_code[bci + 1]);
-          Bytes::put_Java_u2((address) &reconstituted_code[bci + 1], (u2) cp_index);
+          int cp_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1));
+          Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index);
           break;
         }
 
         case Bytecodes::_invokedynamic:
-          int cp_index = Bytes::get_native_u4((address) &reconstituted_code[bci + 1]);
-          Bytes::put_Java_u4((address) &reconstituted_code[bci + 1], (u4) cp_index);
+          int cp_index = Bytes::get_native_u4((address) reconstituted_code->byte_at_addr(bci + 1));
+          Bytes::put_Java_u4((address) reconstituted_code->byte_at_addr(bci + 1), (u4) cp_index);
           break;
       }
 
       // Not all ldc byte code are rewritten.
       switch (raw_code) {
         case Bytecodes::_fast_aldc: {
-          int cpc_index = reconstituted_code[bci + 1] & 0xff;
+          int cpc_index = reconstituted_code->byte_at(bci + 1) & 0xff;
           int cp_index = method->constants()->object_to_cp_index(cpc_index);
           assert(cp_index < method->constants()->length(), "sanity check");
-          reconstituted_code[bci + 1] = (jbyte) cp_index;
+          reconstituted_code->byte_at_put(bci + 1, (jbyte) cp_index);
           break;
         }
 
         case Bytecodes::_fast_aldc_w: {
-          int cpc_index = Bytes::get_native_u2((address) &reconstituted_code[bci + 1]);
+          int cpc_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1));
           int cp_index = method->constants()->object_to_cp_index(cpc_index);
           assert(cp_index < method->constants()->length(), "sanity check");
-          Bytes::put_Java_u2((address) &reconstituted_code[bci + 1], (u2) cp_index);
+          Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index);
           break;
         }
       }
     }
   }
 
-  env->SetByteArrayRegion(result, 0, code_size, reconstituted_code);
-
-  return result;
+  return (jbyteArray) JNIHandles::make_local(reconstituted_code);
 C2V_END
 
 C2V_VMENTRY(jint, exceptionTableLength, (JNIEnv *, jobject, jlong metaspace_method))
@@ -352,7 +225,7 @@
   return CompilerOracle::should_inline(method) || method->force_inline();
 C2V_END
 
-C2V_VMENTRY(jlong, lookupType, (JNIEnv *env, jobject, jstring jname, jclass accessing_class, jboolean resolve))
+C2V_VMENTRY(jlong, lookupType, (JNIEnv*, jobject, jstring jname, jclass accessing_class, jboolean resolve))
   ResourceMark rm;
   Handle name = JNIHandles::resolve(jname);
   Symbol* class_name = java_lang_String::as_symbol(name, THREAD);
@@ -377,44 +250,46 @@
   return (jlong) (address) resolved_klass;
 C2V_END
 
-C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
   oop result = cp->resolve_constant_at(index, CHECK_NULL);
   return JNIHandles::make_local(THREAD, result);
 C2V_END
 
-C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
   oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
   return JNIHandles::make_local(THREAD, result);
 C2V_END
 
-C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
   return cp->name_and_type_ref_index_at(index);
 C2V_END
 
-C2V_VMENTRY(jlong, lookupNameRefInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, lookupNameRefInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
-  return (jlong) (address) cp->name_ref_at(index);
+  Handle sym = java_lang_String::create_from_symbol(cp->name_ref_at(index), CHECK_NULL);
+  return JNIHandles::make_local(THREAD, sym());
 C2V_END
 
-C2V_VMENTRY(jlong, lookupSignatureRefInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, lookupSignatureRefInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
-  return (jlong) (address) cp->signature_ref_at(index);
+  Handle sym = java_lang_String::create_from_symbol(cp->signature_ref_at(index), CHECK_NULL);
+  return JNIHandles::make_local(THREAD, sym());
 C2V_END
 
-C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
   return cp->klass_ref_index_at(index);
 C2V_END
 
-C2V_VMENTRY(jlong, constantPoolKlassAt, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jlong, constantPoolKlassAt, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
   return (jlong) (address) cp->klass_at(index, THREAD);
 C2V_END
 
-C2V_VMENTRY(jlong, lookupKlassInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
+C2V_VMENTRY(jlong, lookupKlassInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
   KlassHandle loading_klass(cp->pool_holder());
   bool is_accessible = false;
@@ -438,13 +313,13 @@
   return (jlong) CompilerToVM::tag_pointer(klass());
 C2V_END
 
-C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
   oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index);
   return JNIHandles::make_local(THREAD, appendix_oop);
 C2V_END
 
-C2V_VMENTRY(jlong, lookupMethodInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
+C2V_VMENTRY(jlong, lookupMethodInPool, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode))
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
   instanceKlassHandle pool_holder(cp->pool_holder());
   Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF);
@@ -452,12 +327,12 @@
   return (jlong) (address) method();
 C2V_END
 
-C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   ConstantPool* cp = (ConstantPool*) metaspace_constant_pool;
   return cp->remap_instruction_operand_from_cache(index);
 C2V_END
 
-C2V_VMENTRY(jlong, resolveField, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode, jlongArray info_handle))
+C2V_VMENTRY(jlong, resolveField, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode, jlongArray info_handle))
   ResourceMark rm;
   constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool;
   Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF);
@@ -470,11 +345,76 @@
   return (jlong) (address) result.field_holder();
 C2V_END
 
-C2V_VMENTRY(jlong, resolveMethod, (JNIEnv *, jobject, jlong metaspace_klass, jstring name, jstring signature))
+C2V_VMENTRY(jint, getVtableIndexForInterface, (JNIEnv *, jobject, jlong metaspace_klass, jlong metaspace_method))
   Klass* klass = (Klass*) metaspace_klass;
-  Symbol* name_symbol = java_lang_String::as_symbol(JNIHandles::resolve(name), THREAD);
-  Symbol* signature_symbol = java_lang_String::as_symbol(JNIHandles::resolve(signature), THREAD);
-  return (jlong) (address) klass->lookup_method(name_symbol, signature_symbol);
+  Method* method = (Method*) metaspace_method;
+  assert(!klass->is_interface(), "");
+  return LinkResolver::vtable_index_of_interface_method(klass, method);
+C2V_END
+
+C2V_VMENTRY(jlong, resolveMethod, (JNIEnv *, jobject, jlong metaspace_klass_receiver, jlong metaspace_method, jlong metaspace_klass_caller))
+  Klass* recv_klass = (Klass*) metaspace_klass_receiver;
+  Klass* caller_klass = (Klass*) metaspace_klass_caller;
+  Method* method = (Method*) metaspace_method;
+
+  if (recv_klass->oop_is_array() || (InstanceKlass::cast(recv_klass)->is_linked())) {
+    Klass* holder_klass = method->method_holder();
+    Symbol* method_name = method->name();
+    Symbol* method_signature = method->signature();
+
+
+    if (holder_klass->is_interface()) {
+      // do link-time resolution to check all access rules.
+      methodHandle resolved_method;
+      LinkResolver::linktime_resolve_interface_method(resolved_method, holder_klass, method_name, method_signature, caller_klass, true, CHECK_AND_CLEAR_0);
+      if (resolved_method->is_private()) {
+        return (jlong) NULL;
+      }
+      assert(recv_klass->is_subtype_of(holder_klass), "");
+      // do actual lookup
+      methodHandle sel_method;
+      LinkResolver::lookup_instance_method_in_klasses(sel_method, recv_klass,
+                resolved_method->name(),
+                resolved_method->signature(), CHECK_AND_CLEAR_0);
+      return (jlong) (address) sel_method();
+    } else {
+      // do link-time resolution to check all access rules.
+      methodHandle resolved_method;
+      LinkResolver::linktime_resolve_virtual_method(resolved_method, holder_klass, method_name, method_signature, caller_klass, true, CHECK_AND_CLEAR_0);
+      // do actual lookup (see LinkResolver::runtime_resolve_virtual_method)
+      int vtable_index = Method::invalid_vtable_index;
+      Method* selected_method;
+
+      if (resolved_method->method_holder()->is_interface()) { // miranda method
+        vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method);
+        assert(vtable_index >= 0 , "we should have valid vtable index at this point");
+
+        InstanceKlass* inst = InstanceKlass::cast(recv_klass);
+        selected_method = inst->method_at_vtable(vtable_index);
+      } else {
+        // at this point we are sure that resolved_method is virtual and not
+        // a miranda method; therefore, it must have a valid vtable index.
+        assert(!resolved_method->has_itable_index(), "");
+        vtable_index = resolved_method->vtable_index();
+        // We could get a negative vtable_index for final methods,
+        // because as an optimization they are they are never put in the vtable,
+        // unless they override an existing method.
+        // If we do get a negative, it means the resolved method is the the selected
+        // method, and it can never be changed by an override.
+        if (vtable_index == Method::nonvirtual_vtable_index) {
+          assert(resolved_method->can_be_statically_bound(), "cannot override this method");
+          selected_method = resolved_method();
+        } else {
+          // recv_klass might be an arrayKlassOop but all vtables start at
+          // the same place. The cast is to avoid virtual call and assertion.
+          InstanceKlass* inst = (InstanceKlass*)recv_klass;
+          selected_method = inst->method_at_vtable(vtable_index);
+        }
+      }
+      return (jlong) (address) selected_method;
+    }
+  }
+  return (jlong) NULL;
 C2V_END
 
 C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv *, jobject, jlong metaspace_klass))
@@ -488,7 +428,7 @@
   return (jlong) (address) klass->class_initializer();
 C2V_END
 
-C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong addr))
+C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv*, jobject, jlong addr))
   address target_addr = (address) addr;
   if (target_addr != 0x0) {
     int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int));
@@ -624,7 +564,7 @@
   return JNIHandles::make_local(result());
 C2V_END
 
-C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv *env, jobject, jlong metaspace_method, int bci))
+C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv*, jobject, jlong metaspace_method, int bci))
   ResourceMark rm;
   HandleMark hm;
 
@@ -633,7 +573,7 @@
   return JNIHandles::make_local(element);
 C2V_END
 
-C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jobject hotspotInstalledCode))
+C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv*, jobject, jobject args, jobject hotspotInstalledCode))
   ResourceMark rm;
   HandleMark hm;
 
@@ -677,7 +617,7 @@
   }
 C2V_END
 
-C2V_ENTRY(jlongArray, getLineNumberTable, (JNIEnv *env, jobject, jlong metaspace_method))
+C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv *, jobject, jlong metaspace_method))
   Method* method = (Method*) metaspace_method;
   if (!method->has_linenumber_table()) {
     return NULL;
@@ -689,19 +629,19 @@
   }
 
   CompressedLineNumberReadStream stream(method->compressed_linenumber_table());
-  jlongArray result = env->NewLongArray(2 * num_entries);
+  typeArrayOop result = oopFactory::new_longArray(2 * num_entries, CHECK_NULL);
 
   int i = 0;
   jlong value;
   while (stream.read_pair()) {
     value = ((long) stream.bci());
-    env->SetLongArrayRegion(result,i,1,&value);
+    result->long_at_put(i, value);
     value = ((long) stream.line());
-    env->SetLongArrayRegion(result,i + 1,1,&value);
+    result->long_at_put(i + 1, value);
     i += 2;
   }
 
-  return result;
+  return (jlongArray) JNIHandles::make_local(result);
 C2V_END
 
 C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv *, jobject, jlong metaspace_method))
@@ -719,7 +659,7 @@
   return method->localvariable_table_length();
 C2V_END
 
-C2V_VMENTRY(void, reprofile, (JNIEnv *env, jobject, jlong metaspace_method))
+C2V_VMENTRY(void, reprofile, (JNIEnv*, jobject, jlong metaspace_method))
   Method* method = asMethod(metaspace_method);
   MethodCounters* mcs = method->method_counters();
   if (mcs != NULL) {
@@ -743,7 +683,7 @@
 C2V_END
 
 
-C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv *env, jobject, jobject hotspotInstalledCode))
+C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject hotspotInstalledCode))
   jlong nativeMethod = InstalledCode::address(hotspotInstalledCode);
   nmethod* m = (nmethod*)nativeMethod;
   if (m != NULL && !m->is_not_entrant()) {
@@ -754,32 +694,36 @@
   InstalledCode::set_address(hotspotInstalledCode, 0);
 C2V_END
 
-C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv *env, jobject, jlong metaspace_klass))
+C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv*, jobject, jlong metaspace_klass))
   Klass* klass = asKlass(metaspace_klass);
   return JNIHandles::make_local(klass->java_mirror());
 C2V_END
 
-C2V_VMENTRY(jlong, readUnsafeKlassPointer, (JNIEnv *env, jobject, jobject o))
+C2V_VMENTRY(jlong, readUnsafeKlassPointer, (JNIEnv*, jobject, jobject o))
   oop resolved_o = JNIHandles::resolve(o);
   jlong klass = (jlong)(address)resolved_o->klass();
   return klass;
 C2V_END
 
-C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv *env, jobject))
+C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv*, jobject))
   typeArrayOop arrayOop = oopFactory::new_longArray(GraalCounterSize, CHECK_NULL);
   JavaThread::collect_counters(arrayOop);
   return (jlongArray) JNIHandles::make_local(arrayOop);
 C2V_END
 
-C2V_ENTRY(jobject, getGPUs, (JNIEnv *env, jobject))
+// In general we should avoid using regular JNI methods to interact with the JVM but this
+// particular case is just about registering JNI methods so it should be a regular native
+// method.
+JNIEXPORT jobject JNICALL c2v_getGPUs (JNIEnv* env, jobject) {
+  TRACE_graal_3("CompilerToVM::getGPUs" );
 #if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux) || defined(TARGET_OS_FAMILY_windows)
   return Gpu::probe_gpus(env);
 #else
   return env->NewStringUTF("");
 #endif
-C2V_END
+}
 
-C2V_VMENTRY(int, allocateCompileId, (JNIEnv *env, jobject, jlong metaspace_method, int entry_bci))
+C2V_VMENTRY(int, allocateCompileId, (JNIEnv*, jobject, jlong metaspace_method, int entry_bci))
   HandleMark hm;
   ResourceMark rm;
   Method* method = (Method*) metaspace_method;
@@ -787,22 +731,27 @@
 C2V_END
 
 
-C2V_VMENTRY(jboolean, isMature, (JNIEnv *env, jobject, jlong metaspace_method_data))
+C2V_VMENTRY(jboolean, isMature, (JNIEnv*, jobject, jlong metaspace_method_data))
   MethodData* mdo = asMethodData(metaspace_method_data);
   return mdo != NULL && mdo->is_mature();
 C2V_END
 
-C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv *env, jobject, jlong metaspace_method, int entry_bci, int comp_level))
+C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv*, jobject, jlong metaspace_method, int entry_bci, int comp_level))
   Method* method = asMethod(metaspace_method);
   return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL;
 C2V_END
 
-C2V_VMENTRY(jlong, getTimeStamp, (JNIEnv *env, jobject))
+C2V_VMENTRY(jlong, getTimeStamp, (JNIEnv*, jobject))
   // tty->time_stamp is the time since VM start which should be used
   // for all HotSpot log output when a timestamp is required.
   return tty->time_stamp().milliseconds();
 C2V_END
 
+C2V_VMENTRY(jobject, getSymbol, (JNIEnv*, jobject, jlong metaspaceSymbol))
+  Handle sym = java_lang_String::create_from_symbol((Symbol*)(address)metaspaceSymbol, CHECK_NULL);
+  return JNIHandles::make_local(THREAD, sym());
+C2V_END
+
 bool matches(jlongArray methods, Method* method) {
   typeArrayOop methods_oop = (typeArrayOop) JNIHandles::resolve(methods);
 
@@ -814,7 +763,7 @@
   return false;
 }
 
-C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv *env, jobject compilerToVM, jobject hs_frame, jlongArray methods, jint initialSkip))
+C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv*, jobject compilerToVM, jobject hs_frame, jlongArray methods, jint initialSkip))
   ResourceMark rm;
 
   if (!thread->has_last_Java_frame()) return NULL;
@@ -949,7 +898,7 @@
   return NULL;
 C2V_END
 
-C2V_VMENTRY(void, resolveInvokeDynamic, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index))
+C2V_VMENTRY(void, resolveInvokeDynamic, (JNIEnv*, jobject, jlong metaspace_constant_pool, jint index))
   ConstantPool* cp = (ConstantPool*)metaspace_constant_pool;
   CallInfo callInfo;
   LinkResolver::resolve_invokedynamic(callInfo, cp, index, CHECK);
@@ -958,7 +907,7 @@
 C2V_END
 
 // public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
-C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv *env, jobject, jobject hs_frame, bool invalidate))
+C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame, bool invalidate))
   ResourceMark rm;
 
   if (hs_frame == NULL) {
@@ -1073,61 +1022,62 @@
 #define METASPACE_METHOD      "J"
 #define METASPACE_METHOD_DATA "J"
 #define METASPACE_CONSTANT_POOL "J"
-#define METASPACE_SYMBOL      "J"
 
 JNINativeMethod CompilerToVM_methods[] = {
-  {CC"initializeBytecode",                           CC"("METASPACE_METHOD"[B)[B",                                     FN_PTR(initializeBytecode)},
-  {CC"exceptionTableStart",                          CC"("METASPACE_METHOD")J",                                        FN_PTR(exceptionTableStart)},
-  {CC"exceptionTableLength",                         CC"("METASPACE_METHOD")I",                                        FN_PTR(exceptionTableLength)},
-  {CC"hasBalancedMonitors",                          CC"("METASPACE_METHOD")Z",                                        FN_PTR(hasBalancedMonitors)},
-  {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"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)},
-  {CC"lookupType",                                   CC"("STRING CLASS"Z)"METASPACE_KLASS,                             FN_PTR(lookupType)},
-  {CC"resolveConstantInPool",                        CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                           FN_PTR(resolveConstantInPool)},
-  {CC"resolvePossiblyCachedConstantInPool",          CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                           FN_PTR(resolvePossiblyCachedConstantInPool)},
-  {CC"lookupNameRefInPool",                          CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_SYMBOL,                 FN_PTR(lookupNameRefInPool)},
-  {CC"lookupNameAndTypeRefIndexInPool",              CC"("METASPACE_CONSTANT_POOL"I)I",                                FN_PTR(lookupNameAndTypeRefIndexInPool)},
-  {CC"lookupSignatureRefInPool",                     CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_SYMBOL,                 FN_PTR(lookupSignatureRefInPool)},
-  {CC"lookupKlassRefIndexInPool",                    CC"("METASPACE_CONSTANT_POOL"I)I",                                FN_PTR(lookupKlassRefIndexInPool)},
-  {CC"constantPoolKlassAt",                          CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS,                  FN_PTR(constantPoolKlassAt)},
-  {CC"lookupKlassInPool",                            CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS,                  FN_PTR(lookupKlassInPool)},
-  {CC"lookupAppendixInPool",                         CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                           FN_PTR(lookupAppendixInPool)},
-  {CC"lookupMethodInPool",                           CC"("METASPACE_CONSTANT_POOL"IB)"METASPACE_METHOD,                FN_PTR(lookupMethodInPool)},
-  {CC"constantPoolRemapInstructionOperandFromCache", CC"("METASPACE_CONSTANT_POOL"I)I",                                FN_PTR(constantPoolRemapInstructionOperandFromCache)},
-  {CC"resolveField",                                 CC"("METASPACE_CONSTANT_POOL"IB[J)"METASPACE_KLASS,               FN_PTR(resolveField)},
-  {CC"resolveInvokeDynamic",                         CC"("METASPACE_CONSTANT_POOL"I)V",                                FN_PTR(resolveInvokeDynamic)},
-  {CC"resolveMethod",                                CC"("METASPACE_KLASS STRING STRING")"METASPACE_METHOD,            FN_PTR(resolveMethod)},
-  {CC"getClassInitializer",                          CC"("METASPACE_KLASS")"METASPACE_METHOD,                          FN_PTR(getClassInitializer)},
-  {CC"hasFinalizableSubclass",                       CC"("METASPACE_KLASS")Z",                                         FN_PTR(hasFinalizableSubclass)},
-  {CC"getMaxCallTargetOffset",                       CC"(J)J",                                                         FN_PTR(getMaxCallTargetOffset)},
-  {CC"getMetaspaceMethod",                           CC"("CLASS"I)"METASPACE_METHOD,                                   FN_PTR(getMetaspaceMethod)},
-  {CC"initializeConfiguration",                      CC"("HS_CONFIG")V",                                               FN_PTR(initializeConfiguration)},
-  {CC"installCode0",                                 CC"("HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I",         FN_PTR(installCode0)},
-  {CC"notifyCompilationStatistics",                  CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V",                 FN_PTR(notifyCompilationStatistics)},
-  {CC"printCompilationStatistics",                   CC"(ZZ)V",                                                        FN_PTR(printCompilationStatistics)},
-  {CC"resetCompilationStatistics",                   CC"()V",                                                          FN_PTR(resetCompilationStatistics)},
-  {CC"disassembleCodeBlob",                          CC"(J)"STRING,                                                    FN_PTR(disassembleCodeBlob)},
-  {CC"executeCompiledMethodVarargs",                 CC"(["OBJECT INSTALLED_CODE")"OBJECT,                             FN_PTR(executeCompiledMethodVarargs)},
-  {CC"getLineNumberTable",                           CC"("METASPACE_METHOD")[J",                                       FN_PTR(getLineNumberTable)},
-  {CC"getLocalVariableTableStart",                   CC"("METASPACE_METHOD")J",                                        FN_PTR(getLocalVariableTableStart)},
-  {CC"getLocalVariableTableLength",                  CC"("METASPACE_METHOD")I",                                        FN_PTR(getLocalVariableTableLength)},
-  {CC"reprofile",                                    CC"("METASPACE_METHOD")V",                                        FN_PTR(reprofile)},
-  {CC"invalidateInstalledCode",                      CC"("INSTALLED_CODE")V",                                          FN_PTR(invalidateInstalledCode)},
-  {CC"getJavaMirror",                                CC"("METASPACE_KLASS")"CLASS,                                     FN_PTR(getJavaMirror)},
-  {CC"readUnsafeKlassPointer",                       CC"("OBJECT")J",                                                  FN_PTR(readUnsafeKlassPointer)},
-  {CC"collectCounters",                              CC"()[J",                                                         FN_PTR(collectCounters)},
-  {CC"getGPUs",                                      CC"()"STRING,                                                     FN_PTR(getGPUs)},
-  {CC"allocateCompileId",                            CC"("METASPACE_METHOD"I)I",                                       FN_PTR(allocateCompileId)},
-  {CC"isMature",                                     CC"("METASPACE_METHOD_DATA")Z",                                   FN_PTR(isMature)},
-  {CC"hasCompiledCodeForOSR",                        CC"("METASPACE_METHOD"II)Z",                                      FN_PTR(hasCompiledCodeForOSR)},
-  {CC"getTimeStamp",                                 CC"()J",                                                          FN_PTR(getTimeStamp)},
-  {CC"getNextStackFrame",                            CC"("HS_STACK_FRAME_REF "[JI)"HS_STACK_FRAME_REF,                 FN_PTR(getNextStackFrame)},
-  {CC"materializeVirtualObjects",                    CC"("HS_STACK_FRAME_REF"Z)V",                                     FN_PTR(materializeVirtualObjects)},
+  {CC"getBytecode",                                  CC"("METASPACE_METHOD")[B",                                               FN_PTR(getBytecode)},
+  {CC"exceptionTableStart",                          CC"("METASPACE_METHOD")J",                                                FN_PTR(exceptionTableStart)},
+  {CC"exceptionTableLength",                         CC"("METASPACE_METHOD")I",                                                FN_PTR(exceptionTableLength)},
+  {CC"hasBalancedMonitors",                          CC"("METASPACE_METHOD")Z",                                                FN_PTR(hasBalancedMonitors)},
+  {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"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)},
+  {CC"lookupType",                                   CC"("STRING CLASS"Z)"METASPACE_KLASS,                                     FN_PTR(lookupType)},
+  {CC"resolveConstantInPool",                        CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(resolveConstantInPool)},
+  {CC"resolvePossiblyCachedConstantInPool",          CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(resolvePossiblyCachedConstantInPool)},
+  {CC"lookupNameRefInPool",                          CC"("METASPACE_CONSTANT_POOL"I)"STRING,                                   FN_PTR(lookupNameRefInPool)},
+  {CC"lookupNameAndTypeRefIndexInPool",              CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(lookupNameAndTypeRefIndexInPool)},
+  {CC"lookupSignatureRefInPool",                     CC"("METASPACE_CONSTANT_POOL"I)"STRING,                                   FN_PTR(lookupSignatureRefInPool)},
+  {CC"lookupKlassRefIndexInPool",                    CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(lookupKlassRefIndexInPool)},
+  {CC"constantPoolKlassAt",                          CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS,                          FN_PTR(constantPoolKlassAt)},
+  {CC"lookupKlassInPool",                            CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS,                          FN_PTR(lookupKlassInPool)},
+  {CC"lookupAppendixInPool",                         CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(lookupAppendixInPool)},
+  {CC"lookupMethodInPool",                           CC"("METASPACE_CONSTANT_POOL"IB)"METASPACE_METHOD,                        FN_PTR(lookupMethodInPool)},
+  {CC"constantPoolRemapInstructionOperandFromCache", CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(constantPoolRemapInstructionOperandFromCache)},
+  {CC"resolveField",                                 CC"("METASPACE_CONSTANT_POOL"IB[J)"METASPACE_KLASS,                       FN_PTR(resolveField)},
+  {CC"resolveInvokeDynamic",                         CC"("METASPACE_CONSTANT_POOL"I)V",                                        FN_PTR(resolveInvokeDynamic)},
+  {CC"resolveMethod",                                CC"("METASPACE_KLASS METASPACE_METHOD METASPACE_KLASS")"METASPACE_METHOD, FN_PTR(resolveMethod)},
+  {CC"getVtableIndexForInterface",                   CC"("METASPACE_KLASS METASPACE_METHOD")I",                                FN_PTR(getVtableIndexForInterface)},
+  {CC"getClassInitializer",                          CC"("METASPACE_KLASS")"METASPACE_METHOD,                                  FN_PTR(getClassInitializer)},
+  {CC"hasFinalizableSubclass",                       CC"("METASPACE_KLASS")Z",                                                 FN_PTR(hasFinalizableSubclass)},
+  {CC"getMaxCallTargetOffset",                       CC"(J)J",                                                                 FN_PTR(getMaxCallTargetOffset)},
+  {CC"getMetaspaceMethod",                           CC"("CLASS"I)"METASPACE_METHOD,                                           FN_PTR(getMetaspaceMethod)},
+  {CC"initializeConfiguration",                      CC"("HS_CONFIG")V",                                                       FN_PTR(initializeConfiguration)},
+  {CC"installCode0",                                 CC"("HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I",                 FN_PTR(installCode0)},
+  {CC"notifyCompilationStatistics",                  CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V",                         FN_PTR(notifyCompilationStatistics)},
+  {CC"printCompilationStatistics",                   CC"(ZZ)V",                                                                FN_PTR(printCompilationStatistics)},
+  {CC"resetCompilationStatistics",                   CC"()V",                                                                  FN_PTR(resetCompilationStatistics)},
+  {CC"disassembleCodeBlob",                          CC"(J)"STRING,                                                            FN_PTR(disassembleCodeBlob)},
+  {CC"executeCompiledMethodVarargs",                 CC"(["OBJECT INSTALLED_CODE")"OBJECT,                                     FN_PTR(executeCompiledMethodVarargs)},
+  {CC"getLineNumberTable",                           CC"("METASPACE_METHOD")[J",                                               FN_PTR(getLineNumberTable)},
+  {CC"getLocalVariableTableStart",                   CC"("METASPACE_METHOD")J",                                                FN_PTR(getLocalVariableTableStart)},
+  {CC"getLocalVariableTableLength",                  CC"("METASPACE_METHOD")I",                                                FN_PTR(getLocalVariableTableLength)},
+  {CC"reprofile",                                    CC"("METASPACE_METHOD")V",                                                FN_PTR(reprofile)},
+  {CC"invalidateInstalledCode",                      CC"("INSTALLED_CODE")V",                                                  FN_PTR(invalidateInstalledCode)},
+  {CC"getJavaMirror",                                CC"("METASPACE_KLASS")"CLASS,                                             FN_PTR(getJavaMirror)},
+  {CC"readUnsafeKlassPointer",                       CC"("OBJECT")J",                                                          FN_PTR(readUnsafeKlassPointer)},
+  {CC"collectCounters",                              CC"()[J",                                                                 FN_PTR(collectCounters)},
+  {CC"getGPUs",                                      CC"()"STRING,                                                             FN_PTR(getGPUs)},
+  {CC"allocateCompileId",                            CC"("METASPACE_METHOD"I)I",                                               FN_PTR(allocateCompileId)},
+  {CC"isMature",                                     CC"("METASPACE_METHOD_DATA")Z",                                           FN_PTR(isMature)},
+  {CC"hasCompiledCodeForOSR",                        CC"("METASPACE_METHOD"II)Z",                                              FN_PTR(hasCompiledCodeForOSR)},
+  {CC"getSymbol",                                    CC"(J)"STRING,                                                            FN_PTR(getSymbol)},
+  {CC"getTimeStamp",                                 CC"()J",                                                                  FN_PTR(getTimeStamp)},
+  {CC"getNextStackFrame",                            CC"("HS_STACK_FRAME_REF "[JI)"HS_STACK_FRAME_REF,                         FN_PTR(getNextStackFrame)},
+  {CC"materializeVirtualObjects",                    CC"("HS_STACK_FRAME_REF"Z)V",                                             FN_PTR(materializeVirtualObjects)},
 };
 
 int CompilerToVM_methods_count() {
--- a/src/share/vm/graal/graalGlobals.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalGlobals.hpp	Fri May 30 15:09:09 2014 +0200
@@ -52,6 +52,12 @@
   COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true,                 \
           "Bootstrap Graal before running Java main method"))               \
                                                                             \
+  COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, true,       \
+          "Use non-native compilation queue for Graal"))                    \
+                                                                            \
+  product(bool, ForceGraalInitialization, false,                            \
+          "Force VM to initialize the compiler even if not used")           \
+                                                                            \
   product(intx, TraceGraal, 0,                                              \
           "Trace level for Graal")                                          \
                                                                             \
--- a/src/share/vm/graal/graalJavaAccess.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalJavaAccess.cpp	Fri May 30 15:09:09 2014 +0200
@@ -59,10 +59,11 @@
 #define FLOAT_FIELD(klass, name) FIELD(klass, name, "F", false)
 #define OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, false)
 #define STATIC_OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, true)
+#define STATIC_INT_FIELD(klass, name) FIELD(klass, name, "I", true)
 
 
 void graal_compute_offsets() {
-  COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, STATIC_OOP_FIELD)
+  COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD)
   guarantee(InstalledCode::_address_offset == sizeof(oopDesc), "codeBlob must be first field!");
 }
 
@@ -72,7 +73,7 @@
 #define FIELD2(klass, name) int klass::_##name##_offset = 0;
 #define FIELD3(klass, name, sig) FIELD2(klass, name)
 
-COMPILER_CLASSES_DO(EMPTY1, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, FIELD3)
+COMPILER_CLASSES_DO(EMPTY1, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, FIELD3, FIELD2)
 
 
 
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri May 30 15:09:09 2014 +0200
@@ -47,18 +47,13 @@
  *
  */
 
-#define COMPILER_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, float_field, oop_field, static_oop_field)                \
+#define COMPILER_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, float_field, oop_field, static_oop_field, static_int_field) \
   start_class(HotSpotResolvedObjectType)                                                                                                                       \
     oop_field(HotSpotResolvedObjectType, javaClass, "Ljava/lang/Class;")                                                                                       \
   end_class                                                                                                                                                    \
   start_class(HotSpotResolvedJavaMethod)                                                                                                                       \
-    oop_field(HotSpotResolvedJavaMethod, name, "Ljava/lang/String;")                                                                                           \
-    oop_field(HotSpotResolvedJavaMethod, holder, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;")                                                  \
     long_field(HotSpotResolvedJavaMethod, metaspaceMethod)                                                                                                     \
   end_class                                                                                                                                                    \
-  start_class(HotSpotJavaType)                                                                                                                                 \
-    oop_field(HotSpotJavaType, name, "Ljava/lang/String;")                                                                                                     \
-  end_class                                                                                                                                                    \
   start_class(InstalledCode)                                                                                                                                   \
     long_field(InstalledCode, address)                                                                                                                         \
     long_field(InstalledCode, version)                                                                                                                         \
@@ -88,6 +83,7 @@
     oop_field(HotSpotCompiledNmethod, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                     \
     int_field(HotSpotCompiledNmethod, entryBCI)                                                                                                                \
     int_field(HotSpotCompiledNmethod, id)                                                                                                                      \
+    long_field(HotSpotCompiledNmethod, ctask)                                                                                                                  \
   end_class                                                                                                                                                    \
   start_class(HotSpotCompiledRuntimeStub)                                                                                                                      \
     oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;")                                                                                      \
@@ -196,6 +192,7 @@
     int_field(BytecodeFrame, numLocks)                                                                                                                         \
     boolean_field(BytecodeFrame, rethrowException)                                                                                                             \
     boolean_field(BytecodeFrame, duringCall)                                                                                                                   \
+    static_int_field(BytecodeFrame, BEFORE_BCI)                                                                                                                \
   end_class                                                                                                                                                    \
   start_class(BytecodePosition)                                                                                                                                \
     oop_field(BytecodePosition, caller, "Lcom/oracle/graal/api/code/BytecodePosition;")                                                                        \
@@ -313,7 +310,19 @@
         oop_store((oop*)addr, x);                                                                                                                              \
       }                                                                                                                                                        \
     }
-COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, STATIC_OOP_FIELD)
+#define STATIC_INT_FIELD(klassName, name)                                                                                                                      \
+    static int _##name##_offset;                                                                                                                               \
+    static int name() {                                                                                                                                        \
+      InstanceKlass* ik = InstanceKlass::cast(klassName::klass());                                                                                             \
+      address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields());                                                 \
+      return *((jint *)addr);                                                                                                                                  \
+    }                                                                                                                                                          \
+    static void set_##name(int x) {                                                                                                                            \
+      InstanceKlass* ik = InstanceKlass::cast(klassName::klass());                                                                                             \
+      address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields());                                                 \
+      *((jint *)addr) = x;                                                                                                                                     \
+    }
+COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD)
 #undef START_CLASS
 #undef END_CLASS
 #undef FIELD
@@ -324,6 +333,7 @@
 #undef FLOAT_FIELD
 #undef OOP_FIELD
 #undef STATIC_OOP_FIELD
+#undef STATIC_INT_FIELD
 
 void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field);
 
--- a/src/share/vm/graal/graalRuntime.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Fri May 30 15:09:09 2014 +0200
@@ -25,13 +25,103 @@
 #include "asm/codeBuffer.hpp"
 #include "graal/graalRuntime.hpp"
 #include "graal/graalVMToCompiler.hpp"
+#include "graal/graalCompilerToVM.hpp"
+#include "graal/graalJavaAccess.hpp"
+#include "graal/graalEnv.hpp"
 #include "memory/oopFactory.hpp"
 #include "prims/jvm.h"
 #include "runtime/biasedLocking.hpp"
 #include "runtime/interfaceSupport.hpp"
+#include "runtime/arguments.hpp"
 #include "runtime/reflection.hpp"
 #include "utilities/debug.hpp"
 
+address GraalRuntime::_external_deopt_i2c_entry = NULL;
+
+void GraalRuntime::initialize_natives(JNIEnv *env, jclass c2vmClass) {
+  uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end();
+  uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024;
+  AMD64_ONLY(guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"));
+  NOT_LP64(error("check TLAB allocation code for address space conflicts"));
+
+  JavaThread* THREAD = JavaThread::current();
+  {
+    ThreadToNativeFromVM trans(THREAD);
+
+    ResourceMark rm;
+    HandleMark hm;
+
+    graal_compute_offsets();
+
+    _external_deopt_i2c_entry = create_external_deopt_i2c();
+
+    // Ensure _non_oop_bits is initialized
+    Universe::non_oop_word();
+
+    env->RegisterNatives(c2vmClass, CompilerToVM_methods, CompilerToVM_methods_count());
+  }
+  check_pending_exception("Could not register natives");
+}
+
+BufferBlob* GraalRuntime::initialize_buffer_blob() {
+  JavaThread* THREAD = JavaThread::current();
+  BufferBlob* buffer_blob = THREAD->get_buffer_blob();
+  if (buffer_blob == NULL) {
+    buffer_blob = BufferBlob::create("Graal thread-local CodeBuffer", GraalNMethodSizeLimit);
+    if (buffer_blob != NULL) {
+      THREAD->set_buffer_blob(buffer_blob);
+    }
+  }
+  return buffer_blob;
+}
+
+address GraalRuntime::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();
+}
+
+BasicType GraalRuntime::kindToBasicType(jchar ch) {
+  switch(ch) {
+    case 'z': return T_BOOLEAN;
+    case 'b': return T_BYTE;
+    case 's': return T_SHORT;
+    case 'c': return T_CHAR;
+    case 'i': return T_INT;
+    case 'f': return T_FLOAT;
+    case 'j': return T_LONG;
+    case 'd': return T_DOUBLE;
+    case 'a': return T_OBJECT;
+    case 'r': return T_ADDRESS;
+    case '-': return T_ILLEGAL;
+    default:
+      fatal(err_msg("unexpected Kind: %c", ch));
+      break;
+  }
+  return T_ILLEGAL;
+}
+
 // Simple helper to see if the caller of a runtime stub which
 // entered the VM has been deoptimized
 
@@ -546,12 +636,200 @@
   }
 JRT_END
 
-// JVM_InitializeGraalRuntime
-JVM_ENTRY(jobject, JVM_InitializeGraalRuntime(JNIEnv *env, jclass graalclass))
-  return VMToCompiler::graalRuntimePermObject();
+// private static GraalRuntime Graal.initializeRuntime()
+JVM_ENTRY(jobject, JVM_GetGraalRuntime(JNIEnv *env, jclass c))
+  return VMToCompiler::get_HotSpotGraalRuntime_jobject();
+JVM_END
+
+// private static String[] Graal.getServiceImpls(Class service)
+JVM_ENTRY(jobject, JVM_GetGraalServiceImpls(JNIEnv *env, jclass c, jclass serviceClass))
+  HandleMark hm;
+  KlassHandle serviceKlass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(serviceClass)));
+  return JNIHandles::make_local(THREAD, GraalRuntime::get_service_impls(serviceKlass, THREAD)());
+JVM_END
+
+// private static TruffleRuntime Truffle.createRuntime()
+JVM_ENTRY(jobject, JVM_CreateTruffleRuntime(JNIEnv *env, jclass c))
+  return JNIHandles::make_local(VMToCompiler::create_HotSpotTruffleRuntime()());
+JVM_END
+
+// private static void HotSpotGraalRuntime.init(Class compilerToVMClass)
+JVM_ENTRY(void, JVM_InitializeGraalNatives(JNIEnv *env, jclass c, jclass c2vmClass))
+  GraalRuntime::initialize_natives(env, c2vmClass);
+JVM_END
+
+// private static boolean HotSpotOptions.parseVMOptions()
+JVM_ENTRY(jboolean, JVM_ParseGraalOptions(JNIEnv *env, jclass c))
+  HandleMark hm;
+  KlassHandle hotSpotOptionsClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)));
+  return GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK_false);
 JVM_END
 
-// JVM_InitializeTruffleRuntime
-JVM_ENTRY(jobject, JVM_InitializeTruffleRuntime(JNIEnv *env, jclass graalclass))
-  return JNIHandles::make_local(VMToCompiler::truffleRuntime()());
-JVM_END
+bool GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) {
+  ResourceMark rm(THREAD);
+
+  // Process option overrides from graal.options first
+  parse_graal_options_file(hotSpotOptionsClass, CHECK_false);
+
+  // Now process options on the command line
+  int numOptions = Arguments::num_graal_args();
+  for (int i = 0; i < numOptions; i++) {
+    char* arg = Arguments::graal_args_array()[i];
+    parse_argument(hotSpotOptionsClass, arg, CHECK_false);
+  }
+  return CITime || CITimeEach;
+}
+
+void GraalRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) {
+  char first = arg[0];
+  char* name;
+  size_t name_len;
+  Handle name_handle;
+  bool valid = true;
+  if (first == '+' || first == '-') {
+    name = arg + 1;
+    name_len = strlen(name);
+    name_handle = java_lang_String::create_from_str(name, CHECK);
+    valid = set_option(hotSpotOptionsClass, name, (int)name_len, name_handle, arg, CHECK);
+  } else {
+    char* sep = strchr(arg, '=');
+    if (sep != NULL) {
+      name = arg;
+      name_len = sep - name;
+      // Temporarily replace '=' with NULL to create the Java string for the option name
+      *sep = '\0';
+      name_handle = java_lang_String::create_from_str(arg, THREAD);
+      *sep = '=';
+      if (HAS_PENDING_EXCEPTION) {
+        return;
+      }
+      valid = set_option(hotSpotOptionsClass, name, (int)name_len, name_handle, sep + 1, CHECK);
+    } else {
+      char buf[200];
+      jio_snprintf(buf, sizeof(buf), "Value for option %s must use '-G:%s=<value>' format", arg, arg);
+      THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+    }
+  }
+
+  if (!valid) {
+    VMToCompiler::setOption(hotSpotOptionsClass, name_handle, Handle(), ' ', Handle(), 0L);
+    char buf[200];
+    jio_snprintf(buf, sizeof(buf), "Invalid Graal option %s", arg);
+    THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+  }
+}
+
+void GraalRuntime::parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS) {
+  const char* home = Arguments::get_java_home();
+  int path_len = (int)strlen(home) + (int)strlen("/lib/graal.options") + 1;
+  char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len);
+  char sep = os::file_separator()[0];
+  sprintf(path, "%s%clib%cgraal.options", home, sep, sep);
+
+  struct stat st;
+  if (os::stat(path, &st) == 0) {
+    int file_handle = os::open(path, 0, 0);
+    if (file_handle != -1) {
+      char* buffer = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, st.st_size);
+      int num_read = (int) os::read(file_handle, (char*) buffer, st.st_size);
+      if (num_read == -1) {
+        warning("Error reading file %s due to %s", path, strerror(errno));
+      } else if (num_read != st.st_size) {
+        warning("Only read %d of %d bytes from %s", num_read, st.st_size, path);
+      }
+      os::close(file_handle);
+      if (num_read == st.st_size) {
+        char* line = buffer;
+        int lineNo = 1;
+        while (line - buffer < num_read) {
+          char* nl = strchr(line, '\n');
+          if (nl != NULL) {
+            *nl = '\0';
+          }
+          parse_argument(hotSpotOptionsClass, line, THREAD);
+          if (HAS_PENDING_EXCEPTION) {
+            warning("Error in %s:%d", path, lineNo);
+            return;
+          }
+          if (nl != NULL) {
+            line = nl + 1;
+            lineNo++;
+          } else {
+            // File without newline at the end
+            break;
+          }
+        }
+      }
+    } else {
+      warning("Error opening file %s due to %s", path, strerror(errno));
+    }
+  }
+}
+
+jlong GraalRuntime::parse_primitive_option_value(char spec, Handle name, const char* value, TRAPS) {
+  union {
+    jint i;
+    jlong l;
+    double d;
+  } uu;
+  uu.l = 0L;
+  char dummy;
+  switch (spec) {
+    case 'd':
+    case 'f': {
+      if (sscanf(value, "%lf%c", &uu.d, &dummy) == 1) {
+        return uu.l;
+      }
+      break;
+    }
+    case 'i': {
+      if (sscanf(value, "%d%c", &uu.i, &dummy) == 1) {
+        return uu.l;
+      }
+      break;
+    }
+    default:
+      ShouldNotReachHere();
+  }
+  ResourceMark rm(THREAD);
+  char buf[200];
+  jio_snprintf(buf, sizeof(buf), "Invalid %s value for Graal option %s: %s", (spec == 'i' ? "numeric" : "float/double"), java_lang_String::as_utf8_string(name()), value);
+  THROW_MSG_(vmSymbols::java_lang_InternalError(), buf, 0L);
+}
+
+Handle GraalRuntime::get_OptionValue(const char* declaringClass, const char* fieldName, const char* fieldSig, TRAPS) {
+  TempNewSymbol name = SymbolTable::new_symbol(declaringClass, THREAD);
+  Klass* klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NH);
+
+  // The class has been loaded so the field and signature should already be in the symbol
+  // table.  If they're not there, the field doesn't exist.
+  TempNewSymbol fieldname = SymbolTable::probe(fieldName, (int)strlen(fieldName));
+  TempNewSymbol signame = SymbolTable::probe(fieldSig, (int)strlen(fieldSig));
+  if (fieldname == NULL || signame == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), (char*) fieldName, Handle());
+  }
+  // Make sure class is initialized before handing id's out to fields
+  klass->initialize(CHECK_NH);
+
+  fieldDescriptor fd;
+  if (!InstanceKlass::cast(klass)->find_field(fieldname, signame, true, &fd)) {
+    THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), (char*) fieldName, Handle());
+  }
+
+  Handle ret = klass->java_mirror()->obj_field(fd.offset());
+  return ret;
+}
+
+Handle GraalRuntime::create_Service(const char* name, TRAPS) {
+  TempNewSymbol kname = SymbolTable::new_symbol(name, THREAD);
+  Klass* k = SystemDictionary::resolve_or_fail(kname, true, CHECK_NH);
+  instanceKlassHandle klass(THREAD, k);
+  klass->initialize(CHECK_NH);
+  klass->check_valid_for_instantiation(true, CHECK_NH);
+  JavaValue result(T_VOID);
+  instanceHandle service = klass->allocate_instance_handle(CHECK_NH);
+  JavaCalls::call_special(&result, service, klass, vmSymbols::object_initializer_name(), vmSymbols::void_method_signature(), THREAD);
+  return service;
+}
+
+#include "graalRuntime.inline.hpp"
--- a/src/share/vm/graal/graalRuntime.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Fri May 30 15:09:09 2014 +0200
@@ -28,8 +28,85 @@
 #include "memory/allocation.hpp"
 #include "runtime/deoptimization.hpp"
 
-class GraalRuntime: public AllStatic {
+class GraalRuntime: public CHeapObj<mtCompiler> {
+ private:
+
+  static address _external_deopt_i2c_entry;
+
+  /**
+   * Reads the OptionValue object from a specified static field.
+   *
+   * @throws LinkageError if the field could not be resolved
+   */
+  static Handle get_OptionValue(const char* declaringClass, const char* fieldName, const char* fieldSig, TRAPS);
+
+  /**
+   * Parses the string form of a numeric, float or double option into a jlong (using raw bits for floats/doubles).
+   *
+   * @param spec 'i', 'f' or 'd' (see HotSpotOptions.setOption())
+   * @param name name option option
+   * @param value string value to parse
+   * @throws InternalError if value could not be parsed according to spec
+   */
+  static jlong parse_primitive_option_value(char spec, Handle name, const char* value, TRAPS);
+
+  /**
+   * Loads default option value overrides from a <jre_home>/lib/graal.options if it exists. Each
+   * line in this file must have the format of a Graal command line option without the
+   * leading "-G:" prefix. These option values are set prior to processing of any Graal
+   * options present on the command line.
+   */
+  static void parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS);
+
+  /**
+   * Parses a given argument and sets the denoted Graal option.
+   *
+   * @throws InternalError if there was a problem parsing or setting the option
+   */
+  static void parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS);
+
+  /**
+   * Searches for a Graal option denoted by a given name and sets it value.
+   *
+   * The definition of this method is in graalRuntime.inline.hpp
+   * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp.
+   *
+   * @returns true if the option was found
+   * @throws InternalError if there was a problem setting the option's value
+   */
+  static bool set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS);
+
+  /**
+   * Instantiates a service object, calls its default constructor and returns it.
+   *
+   * @param name the name of a class implementing com.oracle.graal.api.runtime.Service
+   */
+  static Handle create_Service(const char* name, TRAPS);
+
  public:
+
+  static void initialize_natives(JNIEnv *env, jclass c2vmClass);
+
+  /**
+   * Given an interface representing a Graal service (i.e. sub-interface of
+   * com.oracle.graal.api.runtime.Service), gets an array of objects, one per
+   * known implementation of the service.
+   *
+   * The definition of this method is in graalRuntime.inline.hpp
+   * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp.
+   */
+  static Handle get_service_impls(KlassHandle serviceKlass, TRAPS);
+
+  static BufferBlob* initialize_buffer_blob();
+
+  static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
+
+  static BasicType kindToBasicType(jchar ch);
+  static address create_external_deopt_i2c();
+  static address get_external_deopt_i2c_entry() {return _external_deopt_i2c_entry;}
+
+  // The following routines are all called from compiled Graal code
+
   static void new_instance(JavaThread* thread, Klass* klass);
   static void new_array(JavaThread* thread, Klass* klass, jint length);
   static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims);
@@ -60,4 +137,20 @@
   static void new_store_pre_barrier(JavaThread* thread);
 };
 
+// Tracing macros
+
+#define IF_TRACE_graal_1 if (!(TraceGraal >= 1)) ; else
+#define IF_TRACE_graal_2 if (!(TraceGraal >= 2)) ; else
+#define IF_TRACE_graal_3 if (!(TraceGraal >= 3)) ; else
+#define IF_TRACE_graal_4 if (!(TraceGraal >= 4)) ; else
+#define IF_TRACE_graal_5 if (!(TraceGraal >= 5)) ; else
+
+// using commas and else to keep one-instruction semantics
+
+#define TRACE_graal_1 if (!(TraceGraal >= 1 && (tty->print("TraceGraal-1: "), true))) ; else tty->print_cr
+#define TRACE_graal_2 if (!(TraceGraal >= 2 && (tty->print("   TraceGraal-2: "), true))) ; else tty->print_cr
+#define TRACE_graal_3 if (!(TraceGraal >= 3 && (tty->print("      TraceGraal-3: "), true))) ; else tty->print_cr
+#define TRACE_graal_4 if (!(TraceGraal >= 4 && (tty->print("         TraceGraal-4: "), true))) ; else tty->print_cr
+#define TRACE_graal_5 if (!(TraceGraal >= 5 && (tty->print("            TraceGraal-5: "), true))) ; else tty->print_cr
+
 #endif // SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP
--- a/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 30 15:09:09 2014 +0200
@@ -26,10 +26,10 @@
 #include "graal/graalVMToCompiler.hpp"
 #include "runtime/gpu.hpp"
 
-// this is a *global* handle
-jobject VMToCompiler::_graalRuntimePermObject = NULL;
-jobject VMToCompiler::_vmToCompilerPermObject = NULL;
-Klass* VMToCompiler::_vmToCompilerPermKlass = NULL;
+// these are *global* handles
+jobject VMToCompiler::_HotSpotGraalRuntime_instance = NULL;
+jobject VMToCompiler::_VMToCompiler_instance = NULL;
+Klass* VMToCompiler::_VMToCompiler_klass = NULL;
 
 static Klass* loadClass(Symbol* name) {
   Klass* klass = SystemDictionary::resolve_or_null(name, SystemDictionary::java_system_loader(), Handle(), Thread::current());
@@ -40,134 +40,156 @@
   return klass;
 }
 
-KlassHandle VMToCompiler::vmToCompilerKlass() {
-  if (_vmToCompilerPermKlass == NULL) {
-    Klass* result = loadClass(vmSymbols::com_oracle_graal_hotspot_bridge_VMToCompiler());
-    _vmToCompilerPermKlass = result;
+KlassHandle VMToCompiler::VMToCompiler_klass() {
+  if (_VMToCompiler_klass == NULL) {
+    TempNewSymbol VMToCompiler = SymbolTable::new_symbol("com/oracle/graal/hotspot/bridge/VMToCompiler", Thread::current());
+    Klass* result = loadClass(VMToCompiler);
+    _VMToCompiler_klass = result;
   }
-  return _vmToCompilerPermKlass;
+  return _VMToCompiler_klass;
 }
 
-Handle VMToCompiler::truffleRuntime() {
-  Symbol* name = vmSymbols::com_oracle_graal_truffle_hotspot_HotSpotTruffleRuntime();
+Handle VMToCompiler::create_HotSpotTruffleRuntime() {
+  Thread* THREAD = Thread::current();
+  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime", THREAD);
   KlassHandle klass = loadClass(name);
 
+  TempNewSymbol makeInstance = SymbolTable::new_symbol("makeInstance", THREAD);
+  TempNewSymbol sig = SymbolTable::new_symbol("()Lcom/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime;", THREAD);
   JavaValue result(T_OBJECT);
-  JavaCalls::call_static(&result, klass, vmSymbols::makeInstance_name(), vmSymbols::makeInstance_signature(), Thread::current());
+  JavaCalls::call_static(&result, klass, makeInstance, sig, THREAD);
   check_pending_exception("Couldn't initialize HotSpotTruffleRuntime");
   return Handle((oop) result.get_jobject());
 }
 
-Handle VMToCompiler::graalRuntime() {
-  if (JNIHandles::resolve(_graalRuntimePermObject) == NULL) {
-    KlassHandle klass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotGraalRuntime());
+Handle VMToCompiler::get_HotSpotGraalRuntime() {
+  if (JNIHandles::resolve(_HotSpotGraalRuntime_instance) == NULL) {
+    Thread* THREAD = Thread::current();
+    TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotGraalRuntime", THREAD);
+    KlassHandle klass = loadClass(name);
+    TempNewSymbol runtime = SymbolTable::new_symbol("runtime", THREAD);
+    TempNewSymbol sig = SymbolTable::new_symbol("()Lcom/oracle/graal/hotspot/HotSpotGraalRuntime;", THREAD);
     JavaValue result(T_OBJECT);
-    JavaCalls::call_static(&result, klass, vmSymbols::runtime_name(), vmSymbols::runtime_signature(), Thread::current());
+    JavaCalls::call_static(&result, klass, runtime, sig, THREAD);
     check_pending_exception("Couldn't initialize HotSpotGraalRuntime");
-    _graalRuntimePermObject = JNIHandles::make_global((oop) result.get_jobject());
+    _HotSpotGraalRuntime_instance = JNIHandles::make_global((oop) result.get_jobject());
   }
-  return Handle(JNIHandles::resolve_non_null(_graalRuntimePermObject));
-}
-
-Handle VMToCompiler::instance() {
-  if (JNIHandles::resolve(_vmToCompilerPermObject) == NULL) {
-    KlassHandle compilerKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotGraalRuntime());
-
-    JavaValue result(T_OBJECT);
-    JavaCallArguments args;
-    args.set_receiver(graalRuntime());
-    JavaCalls::call_virtual(&result, compilerKlass, vmSymbols::getVMToCompiler_name(), vmSymbols::getVMToCompiler_signature(), &args, Thread::current());
-    check_pending_exception("Couldn't get VMToCompiler");
-    _vmToCompilerPermObject = JNIHandles::make_global((oop) result.get_jobject());
-  }
-  return Handle(JNIHandles::resolve_non_null(_vmToCompilerPermObject));
-}
-
-void VMToCompiler::initOptions() {
-  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
-  Thread* THREAD = Thread::current();
-  optionsKlass->initialize(THREAD);
-  check_pending_exception("Error while calling initOptions");
+  return Handle(JNIHandles::resolve_non_null(_HotSpotGraalRuntime_instance));
 }
 
-jboolean VMToCompiler::setOption(Handle option) {
-  assert(!option.is_null(), "");
-  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
-
-  Thread* THREAD = Thread::current();
-  JavaValue result(T_BOOLEAN);
-  JavaCalls::call_static(&result, optionsKlass, vmSymbols::setOption_name(), vmSymbols::setOption_signature(), option, THREAD);
-  check_pending_exception("Error while calling setOption");
-  return result.get_jboolean();
+Handle VMToCompiler::VMToCompiler_instance() {
+  if (JNIHandles::resolve(_VMToCompiler_instance) == NULL) {
+    Thread* THREAD = Thread::current();
+    TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotGraalRuntime", THREAD);
+    KlassHandle klass = loadClass(name);
+    TempNewSymbol getVMToCompiler = SymbolTable::new_symbol("getVMToCompiler", THREAD);
+    TempNewSymbol sig = SymbolTable::new_symbol("()Lcom/oracle/graal/hotspot/bridge/VMToCompiler;", THREAD);
+    JavaValue result(T_OBJECT);
+    JavaCallArguments args;
+    args.set_receiver(get_HotSpotGraalRuntime());
+    JavaCalls::call_virtual(&result, klass, getVMToCompiler, sig, &args, THREAD);
+    check_pending_exception("Couldn't get VMToCompiler");
+    _VMToCompiler_instance = JNIHandles::make_global((oop) result.get_jobject());
+  }
+  return Handle(JNIHandles::resolve_non_null(_VMToCompiler_instance));
 }
 
-void VMToCompiler::finalizeOptions(jboolean ciTime) {
-  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
+void VMToCompiler::setOption(KlassHandle hotSpotOptionsClass, Handle name, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) {
+  assert(!option.is_null(), "npe");
   Thread* THREAD = Thread::current();
-  JavaValue result(T_VOID);
-  JavaCallArguments args;
-  args.push_int(ciTime);
-  JavaCalls::call_static(&result, optionsKlass, vmSymbols::finalizeOptions_name(), vmSymbols::bool_void_signature(), &args, THREAD);
-  check_pending_exception("Error while calling finalizeOptions");
-}
-
-void VMToCompiler::compileMethod(Method* method, int entry_bci, jboolean blocking) {
-  assert(method != NULL, "just checking");
-  Thread* THREAD = Thread::current();
+  TempNewSymbol setOption = SymbolTable::new_symbol("setOption", THREAD);
+  TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;Lcom/oracle/graal/options/OptionValue;CLjava/lang/String;J)V", THREAD);
   JavaValue result(T_VOID);
   JavaCallArguments args;
-  args.push_oop(instance());
-  args.push_long((jlong) (address) method);
-  args.push_int(entry_bci);
-  args.push_int(blocking);
-  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, THREAD);
-  check_pending_exception("Error while calling compileMethod");
+  args.push_oop(name());
+  args.push_oop(option());
+  args.push_int(spec);
+  args.push_oop(stringValue());
+  args.push_long(primitiveValue);
+  JavaCalls::call_static(&result, hotSpotOptionsClass, setOption, sig, &args, THREAD);
+  check_pending_exception("Error while calling setOption");
 }
 
-void VMToCompiler::shutdownCompiler() {
-  if (_graalRuntimePermObject != NULL) {
-    HandleMark hm;
-    JavaThread* THREAD = JavaThread::current();
-    JavaValue result(T_VOID);
-    JavaCallArguments args;
-    args.push_oop(instance());
-    JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::shutdownCompiler_name(), vmSymbols::void_method_signature(), &args, THREAD);
-    check_pending_exception("Error while calling shutdownCompiler");
-
-    JNIHandles::destroy_global(_graalRuntimePermObject);
-    JNIHandles::destroy_global(_vmToCompilerPermObject);
-    //JNIHandles::destroy_global(_vmToCompilerPermKlass);
-
-    _graalRuntimePermObject = NULL;
-    _vmToCompilerPermObject = NULL;
-    _vmToCompilerPermKlass = NULL;
-  }
+#ifdef COMPILERGRAAL
+void VMToCompiler::bootstrap() {
+  JavaThread* THREAD = JavaThread::current();
+  JavaValue result(T_VOID);
+  JavaCallArguments args;
+  TempNewSymbol bootstrap = SymbolTable::new_symbol("bootstrap", THREAD);
+  args.push_oop(VMToCompiler_instance());
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), bootstrap, vmSymbols::void_method_signature(), &args, THREAD);
+  check_pending_exception("Error while calling bootstrap");
 }
 
 void VMToCompiler::startCompiler(jboolean bootstrap_enabled) {
   JavaThread* THREAD = JavaThread::current();
   JavaValue result(T_VOID);
   JavaCallArguments args;
-  args.push_oop(instance());
+  TempNewSymbol startCompiler = SymbolTable::new_symbol("startCompiler", THREAD);
+  args.push_oop(VMToCompiler_instance());
   args.push_int(bootstrap_enabled);
-  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::bool_void_signature(), &args, THREAD);
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), startCompiler, vmSymbols::bool_void_signature(), &args, THREAD);
   check_pending_exception("Error while calling startCompiler");
 }
 
-void VMToCompiler::bootstrap() {
-  JavaThread* THREAD = JavaThread::current();
+void VMToCompiler::compileMethod(Method* method, int entry_bci, jlong ctask, jboolean blocking) {
+  assert(method != NULL, "just checking");
+  Thread* THREAD = Thread::current();
   JavaValue result(T_VOID);
   JavaCallArguments args;
-  args.push_oop(instance());
-  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::bootstrap_name(), vmSymbols::void_method_signature(), &args, THREAD);
-  check_pending_exception("Error while calling bootstrap");
+  args.push_oop(VMToCompiler_instance());
+  args.push_long((jlong) (address) method);
+  args.push_int(entry_bci);
+  args.push_long(ctask);
+  args.push_int(blocking);
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, THREAD);
+  check_pending_exception("Error while calling compileMethod");
 }
 
-void VMToCompiler::compileTheWorld() {
+void VMToCompiler::shutdownCompiler() {
   JavaThread* THREAD = JavaThread::current();
+  HandleMark hm(THREAD);
+  TempNewSymbol shutdownCompiler = SymbolTable::new_symbol("shutdownCompiler", THREAD);
   JavaValue result(T_VOID);
   JavaCallArguments args;
-  args.push_oop(instance());
-  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::compileTheWorld_name(), vmSymbols::void_method_signature(), &args, THREAD);
+  args.push_oop(VMToCompiler_instance());
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), shutdownCompiler, vmSymbols::void_method_signature(), &args, THREAD);
+  check_pending_exception("Error while calling shutdownCompiler");
+}
+#endif // COMPILERGRAAL
+
+void VMToCompiler::shutdownRuntime() {
+  if (_HotSpotGraalRuntime_instance != NULL) {
+    JavaThread* THREAD = JavaThread::current();
+    HandleMark hm(THREAD);
+    TempNewSymbol shutdownRuntime = SymbolTable::new_symbol("shutdownRuntime", THREAD);
+    JavaValue result(T_VOID);
+    JavaCallArguments args;
+    args.push_oop(VMToCompiler_instance());
+    JavaCalls::call_interface(&result, VMToCompiler_klass(), shutdownRuntime, vmSymbols::void_method_signature(), &args, THREAD);
+    check_pending_exception("Error while calling shutdownRuntime");
+
+    JNIHandles::destroy_global(_HotSpotGraalRuntime_instance);
+    JNIHandles::destroy_global(_VMToCompiler_instance);
+
+    _HotSpotGraalRuntime_instance = NULL;
+    _VMToCompiler_instance = NULL;
+    _VMToCompiler_klass = NULL;
+  }
+}
+
+#ifndef PRODUCT
+void VMToCompiler::compileTheWorld() {
+  // We turn off CompileTheWorld so that Graal can
+  // be compiled by C1/C2 when Graal does a CTW.
+  CompileTheWorld = false;
+
+  JavaThread* THREAD = JavaThread::current();
+  TempNewSymbol compileTheWorld = SymbolTable::new_symbol("compileTheWorld", THREAD);
+  JavaValue result(T_VOID);
+  JavaCallArguments args;
+  args.push_oop(VMToCompiler_instance());
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), compileTheWorld, vmSymbols::void_method_signature(), &args, THREAD);
   check_pending_exception("Error while calling compileTheWorld");
 }
+#endif
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 30 15:09:09 2014 +0200
@@ -35,45 +35,53 @@
 class VMToCompiler : public AllStatic {
 
 private:
-  static jobject _graalRuntimePermObject;
-  static jobject _vmToCompilerPermObject;
-  static Klass* _vmToCompilerPermKlass;
+  static jobject _HotSpotGraalRuntime_instance;
+  static jobject _VMToCompiler_instance;
 
-  static KlassHandle vmToCompilerKlass();
-  static Handle instance();
+  static Klass* _VMToCompiler_klass;
+
+  static KlassHandle VMToCompiler_klass();
+  static Handle VMToCompiler_instance();
 
 public:
-  static Handle graalRuntime();
-  static Handle truffleRuntime();
+
+  static bool is_HotSpotGraalRuntime_initialized() { return _HotSpotGraalRuntime_instance != NULL; }
+
+  // Gets the singleton HotSpotGraalRuntime instance, initializing it if necessary
+  static Handle get_HotSpotGraalRuntime();
 
-  static jobject graalRuntimePermObject() {
-    graalRuntime();
-    return _graalRuntimePermObject;
+  // Creates a new HotSpotTruffleRuntime object
+  static Handle create_HotSpotTruffleRuntime();
+
+  static jobject get_HotSpotGraalRuntime_jobject() {
+    get_HotSpotGraalRuntime();
+    return _HotSpotGraalRuntime_instance;
   }
 
-  // public static boolean HotSpotOptions.<clinit>();
-  static void initOptions();
-
-  // public static boolean HotSpotOptions.setOption(String option);
-  static jboolean setOption(Handle option);
+  // public static void HotSpotOptions.setOption(String name, OptionValue<?> option, char spec, String stringValue, long primitiveValue);
+  static void setOption(KlassHandle hotSpotOptionsClass, Handle name, Handle option, jchar spec, Handle stringValue, jlong primitiveValue);
 
-  // public static void HotSpotOptions.finalizeOptions(boolean ciTime);
-  static void finalizeOptions(jboolean ciTime);
+#ifdef COMPILERGRAAL
+  // public abstract void startCompiler(boolean bootstrapEnabled);
+  static void startCompiler(jboolean bootstrap_enabled);
 
-  // public abstract boolean compileMethod(long vmId, int entry_bci, boolean blocking);
-  static void compileMethod(Method* method, int entry_bci, jboolean blocking);
+  // public abstract void bootstrap();
+  static void bootstrap();
+
+  // public abstract boolean compileMethod(long metaspaceMethod, int entryBCI, long ctask, boolean blocking);
+  static void compileMethod(Method* method, int entry_bci, jlong ctask, jboolean blocking);
 
   // public abstract void shutdownCompiler();
   static void shutdownCompiler();
-  
-  // public abstract void startCompiler(boolean bootstrapEnabled);
-  static void startCompiler(jboolean bootstrap_enabled);
+#endif
   
-  // public abstract void bootstrap();
-  static void bootstrap();
-
+  // public abstract void shutdownRuntime();
+  static void shutdownRuntime();
+  
+#ifndef PRODUCT
   // public abstract void compileTheWorld();
   static void compileTheWorld();
+#endif
 };
 
 inline void check_pending_exception(const char* message, bool dump_core = false) {
--- a/src/share/vm/graal/vmStructs_graal.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/graal/vmStructs_graal.hpp	Fri May 30 15:09:09 2014 +0200
@@ -66,5 +66,7 @@
   declare_constant(CodeInstaller::POLL_FAR)                                                       \
   declare_constant(CodeInstaller::POLL_RETURN_FAR)                                                \
   declare_constant(CodeInstaller::INVOKE_INVALID)                                                 \
+                                                                                                  \
+  declare_constant(Method::invalid_vtable_index)                                                  \
 
 #endif // SHARE_VM_GRAAL_VMSTRUCTS_GRAAL_HPP
--- a/src/share/vm/interpreter/linkResolver.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/interpreter/linkResolver.cpp	Fri May 30 15:09:09 2014 +0200
@@ -113,7 +113,7 @@
     // Note: with several active threads, the must_be_compiled may be true
     //       while can_be_compiled is false; remove assert
     // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile");
-    if (THREAD->is_Compiler_thread()) {
+    if (!THREAD->can_call_java()) {
       // don't force compilation, resolve was on behalf of compiler
       return;
     }
@@ -364,7 +364,7 @@
         return;
       }
     } else if (iid == vmIntrinsics::_invokeGeneric
-               && !THREAD->is_Compiler_thread()
+               && THREAD->can_call_java()
                && appendix_result_or_null != NULL) {
       // This is a method with type-checking semantics.
       // We will ask Java code to spin an adapter method for it.
--- a/src/share/vm/interpreter/linkResolver.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/interpreter/linkResolver.hpp	Fri May 30 15:09:09 2014 +0200
@@ -125,7 +125,13 @@
 
  private:
   static void lookup_method_in_klasses          (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, bool checkpolymorphism, bool in_imethod_resolve, TRAPS);
+#ifdef GRAAL
+ public:
+#endif
   static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
+#ifdef GRAAL
+ private:
+#endif
   static void lookup_method_in_interfaces       (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
   static void lookup_polymorphic_method         (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature,
                                                  KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS);
@@ -139,8 +145,14 @@
 
   static void linktime_resolve_static_method    (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
   static void linktime_resolve_special_method   (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
+#ifdef GRAAL
+ public:
+#endif
   static void linktime_resolve_virtual_method   (methodHandle &resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature,KlassHandle current_klass, bool check_access, TRAPS);
   static void linktime_resolve_interface_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
+#ifdef GRAAL
+ private:
+#endif
 
   static void runtime_resolve_special_method    (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, KlassHandle current_klass, bool check_access, TRAPS);
   static void runtime_resolve_virtual_method    (CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass, Handle recv, KlassHandle recv_klass, bool check_null_and_abstract, TRAPS);
--- a/src/share/vm/oops/instanceKlass.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/oops/instanceKlass.cpp	Fri May 30 15:09:09 2014 +0200
@@ -59,6 +59,10 @@
 #include "services/threadService.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/macros.hpp"
+#ifdef GRAAL
+#include "classfile/javaAssertions.hpp"
+#include "graal/graalVMToCompiler.hpp"
+#endif
 #if INCLUDE_ALL_GCS
 #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
@@ -1205,6 +1209,15 @@
 #ifdef GRAAL
   if (this_oop->is_subtype_of(SystemDictionary::Node_klass())) {
     if (this_oop() != SystemDictionary::Node_klass()) {
+      if (!VMToCompiler::is_HotSpotGraalRuntime_initialized() && JavaAssertions::systemClassDefault() == false) {
+        // We want to ensure that the process of initializing HotSpotGraalRuntime
+        // is fast since it executes at VM startup. We must avoid triggering
+        // class initialization of any Node classes during this process.
+        ResourceMark rm;
+        char buf[200];
+        jio_snprintf(buf, sizeof(buf), "Node subclass %s must not be initialized before HotSpotGraalRuntime is initialized", this_oop->name()->as_C_string());
+        THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+      }
       // Create the NodeClass for a Node subclass.
       TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/Class;)Lcom/oracle/graal/graph/NodeClass;", CHECK);
       JavaValue result(T_OBJECT);
--- a/src/share/vm/oops/method.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/oops/method.cpp	Fri May 30 15:09:09 2014 +0200
@@ -1314,7 +1314,7 @@
 
 // These two methods are static since a GC may move the Method
 bool Method::load_signature_classes(methodHandle m, TRAPS) {
-  if (THREAD->is_Compiler_thread()) {
+  if (!THREAD->can_call_java()) {
     // There is nothing useful this routine can do from within the Compile thread.
     // Hopefully, the signature contains only well-known classes.
     // We could scan for this and return true/false, but the caller won't care.
--- a/src/share/vm/prims/jni.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/prims/jni.cpp	Fri May 30 15:09:09 2014 +0200
@@ -35,6 +35,7 @@
 #include "utilities/macros.hpp"
 #ifdef GRAAL
 #include "graal/graalCompiler.hpp"
+#include "graal/graalVMToCompiler.hpp"
 #endif
 #if INCLUDE_ALL_GCS
 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
@@ -5173,13 +5174,20 @@
     *vm = (JavaVM *)(&main_vm);
     *(JNIEnv**)penv = thread->jni_environment();
 
-#ifdef GRAAL
-    // GraalCompiler needs to have been created in compileBroker.cpp
-    GraalCompiler* graal_compiler = GraalCompiler::instance();
-    if (graal_compiler != NULL) {
-      graal_compiler->initialize();
+#ifdef COMPILERGRAAL
+    if (UseGraalCompilationQueue) {
+      // GraalCompiler may have been created in compileBroker.cpp
+      GraalCompiler* graal_compiler = GraalCompiler::instance();
+      if (ForceGraalInitialization && graal_compiler == NULL) {
+        graal_compiler = new GraalCompiler();
+      }
+      if (graal_compiler != NULL) {
+        graal_compiler->initialize();
+      } else {
+        assert(!UseCompiler, "why isn't there any compiler?");
+      }
     } else {
-      assert(!UseCompiler, "why isn't there any compiler?");
+      // Graal is initialized on a CompilerThread
     }
 #endif
 
@@ -5203,7 +5211,19 @@
   #endif
 
     // Check if we should compile all classes on bootclasspath
+#ifdef GRAAL
+#ifndef COMPILERGRAAL
+    if (CompileTheWorld) {
+      // Graal is considered as application code so we need to
+      // stop the VM deferring compilation now.
+      CompilationPolicy::completed_vm_startup();
+
+      VMToCompiler::compileTheWorld();
+    }
+#endif
+#else
     if (CompileTheWorld) ClassLoader::compile_the_world();
+#endif
     if (ReplayCompiles) ciReplay::replay(thread);
 
     // Some platforms (like Win*) need a wrapper around these test
--- a/src/share/vm/prims/jvmtiTagMap.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/prims/jvmtiTagMap.cpp	Fri May 30 15:09:09 2014 +0200
@@ -2790,6 +2790,7 @@
   return true;
 }
 
+#ifdef ASSERT
 // verify that a static oop field is in range
 static inline bool verify_static_oop(InstanceKlass* ik,
                                      oop mirror, int offset) {
@@ -2804,6 +2805,7 @@
     return false;
   }
 }
+#endif // #ifdef ASSERT
 
 // a class references its super class, interfaces, class loader, ...
 // and finally its static fields
--- a/src/share/vm/prims/nativeLookup.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/prims/nativeLookup.cpp	Fri May 30 15:09:09 2014 +0200
@@ -124,8 +124,11 @@
   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
   void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
 #ifdef GRAAL
-  jobject JNICALL JVM_InitializeGraalRuntime(JNIEnv *env, jclass graalclass);
-  jobject JNICALL JVM_InitializeTruffleRuntime(JNIEnv *env, jclass graalclass);
+  void     JNICALL JVM_InitializeGraalNatives(JNIEnv *env, jclass c, jclass compilerToVMClass);
+  jobject  JNICALL JVM_GetGraalRuntime(JNIEnv *env, jclass c);
+  jobject  JNICALL JVM_GetGraalServiceImpls(JNIEnv *env, jclass c);
+  jobject  JNICALL JVM_CreateTruffleRuntime(JNIEnv *env, jclass c);
+  jboolean JNICALL JVM_ParseGraalOptions(JNIEnv *env, jclass hotspotOptionsClass);
 #endif
 }
 
@@ -138,8 +141,11 @@
   { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
 #ifdef GRAAL
-  { CC"Java_com_oracle_graal_api_runtime_Graal_initializeRuntime", NULL, FN_PTR(JVM_InitializeGraalRuntime)      },
-  { CC"Java_com_oracle_truffle_api_Truffle_initializeRuntime",     NULL, FN_PTR(JVM_InitializeTruffleRuntime)    },
+  { CC"Java_com_oracle_graal_api_runtime_Graal_initializeRuntime",   NULL, FN_PTR(JVM_GetGraalRuntime)             },
+  { CC"Java_com_oracle_graal_api_runtime_Services_getServiceImpls",  NULL, FN_PTR(JVM_GetGraalServiceImpls)        },
+  { CC"Java_com_oracle_truffle_api_Truffle_createRuntime",           NULL, FN_PTR(JVM_CreateTruffleRuntime)        },
+  { CC"Java_com_oracle_graal_hotspot_HotSpotGraalRuntime_init",      NULL, FN_PTR(JVM_InitializeGraalNatives)      },
+  { CC"Java_com_oracle_graal_hotspot_HotSpotOptions_parseVMOptions", NULL, FN_PTR(JVM_ParseGraalOptions)           },
 #endif
 };
 
--- a/src/share/vm/runtime/deoptimization.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp	Fri May 30 15:09:09 2014 +0200
@@ -88,7 +88,7 @@
 #endif
 
 #ifdef GRAAL
-#include "graal/graalCompiler.hpp"
+#include "graal/graalRuntime.hpp"
 #include "graal/graalJavaAccess.hpp"
 #endif
 
@@ -359,7 +359,8 @@
 #ifdef ASSERT
   assert(cb->is_deoptimization_stub() ||
          cb->is_uncommon_trap_stub() ||
-         strcmp("Stub<DeoptimizationStub.uncommonTrapHandler>", cb->name()) == 0,
+         strcmp("Stub<DeoptimizationStub.deoptimizationHandler>", cb->name()) == 0 ||
+         strcmp("Stub<UncommonTrapStub.uncommonTrapHandler>", cb->name()) == 0,
          err_msg("unexpected code blob: %s", cb->name()));
 #endif
 #else
@@ -1347,7 +1348,7 @@
     ScopeDesc*      trap_scope  = cvf->scope();
     
     if (TraceDeoptimization) {
-      tty->print_cr("  bci=%d pc=%d, relative_pc=%d, method=%s" GRAAL_ONLY(", debug_id=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string()
+      tty->print_cr("  bci=%d pc=" INTPTR_FORMAT ", relative_pc=%d, method=%s" GRAAL_ONLY(", debug_id=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string()
 #ifdef GRAAL
           , debug_id
 #endif
--- a/src/share/vm/runtime/globals.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/globals.cpp	Fri May 30 15:09:09 2014 +0200
@@ -477,12 +477,12 @@
 }
 
 // Search the flag table for a named flag
-Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked) {
+Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked, bool allow_constant) {
   for (Flag* current = &flagTable[0]; current->_name != NULL; current++) {
     if (str_equal(current->_name, name, length)) {
       // Found a matching entry.
       // Don't report notproduct and develop flags in product builds.
-      if (current->is_constant_in_binary()) {
+      if (current->is_constant_in_binary() && !allow_constant) {
         return NULL;
       }
       // Report locked flags only if allowed.
--- a/src/share/vm/runtime/globals.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/globals.hpp	Fri May 30 15:09:09 2014 +0200
@@ -256,7 +256,7 @@
   // number of flags
   static size_t numFlags;
 
-  static Flag* find_flag(const char* name, size_t length, bool allow_locked = false);
+  static Flag* find_flag(const char* name, size_t length, bool allow_locked = false, bool allow_constant = false);
   static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false);
 
   void check_writable();
@@ -980,6 +980,9 @@
   product(bool, PrintNMethodStatistics, false,                              \
           "Print a summary statistic for the generated nmethods")           \
                                                                             \
+  product(bool, ShareDebugInfo, IS_GRAAL_DEFINED,                           \
+          "Always tries to share similar debug info inside a nmethod")      \
+                                                                            \
   diagnostic(bool, PrintNMethods, false,                                    \
           "Print assembly code for nmethods when generated")                \
                                                                             \
@@ -3055,7 +3058,7 @@
           "If non-zero, maximum number of words that malloc/realloc can "   \
           "allocate (for testing only)")                                    \
                                                                             \
-  product(intx, TypeProfileWidth,     2,                                    \
+  product_pd(intx, TypeProfileWidth,                                        \
           "Number of receiver types to record in call/cast profile")        \
                                                                             \
   product_pd(intx, MethodProfileWidth,                                      \
--- a/src/share/vm/runtime/gpu.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/gpu.cpp	Fri May 30 15:09:09 2014 +0200
@@ -32,10 +32,10 @@
 void Gpu::initialized_gpu(Gpu* gpu) {
   // GPUs are always initialized on the same thread so no need for locking
   guarantee(_initialized_gpus_count < MAX_GPUS, "oob");
+  _initialized_gpus[_initialized_gpus_count++] = gpu;
   if (TraceGPUInteraction) {
-    tty->print_cr("[GPU] registered initialization of %s (total initialized: %d)", gpu->name(), _initialized_gpus);
+    tty->print_cr("[GPU] registered initialization of %s (total initialized: %d)", gpu->name(), _initialized_gpus_count);
   }
-  _initialized_gpus[_initialized_gpus_count++] = gpu;
 }
 
 void Gpu::safepoint_event(SafepointEvent event) {
--- a/src/share/vm/runtime/java.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/java.cpp	Fri May 30 15:09:09 2014 +0200
@@ -32,6 +32,7 @@
 #include "interpreter/bytecodeHistogram.hpp"
 #ifdef GRAAL
 #include "graal/graalCompiler.hpp"
+#include "graal/graalVMToCompiler.hpp"
 #endif
 #include "memory/genCollectedHeap.hpp"
 #include "memory/oopFactory.hpp"
@@ -461,12 +462,6 @@
   #define BEFORE_EXIT_DONE    2
   static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;
 
-#ifdef GRAAL
-  if (GraalCompiler::instance() != NULL) {
-    GraalCompiler::instance()->exit();
-  }
-#endif
-
   // Note: don't use a Mutex to guard the entire before_exit(), as
   // JVMTI post_thread_end_event and post_vm_death_event will run native code.
   // A CAS or OSMutex would work just fine but then we need to manipulate
@@ -488,6 +483,15 @@
     }
   }
 
+#ifdef GRAAL
+#ifdef COMPILERGRAAL
+  if (GraalCompiler::instance() != NULL) {
+    GraalCompiler::instance()->shutdown();
+  }
+#endif
+  VMToCompiler::shutdownRuntime();
+#endif
+
   // The only difference between this and Win32's _onexit procs is that
   // this version is invoked before any threads get killed.
   ExitProc* current = exit_procs;
--- a/src/share/vm/runtime/javaCalls.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/javaCalls.cpp	Fri May 30 15:09:09 2014 +0200
@@ -41,7 +41,7 @@
 #include "runtime/stubRoutines.hpp"
 #include "runtime/thread.inline.hpp"
 #include "graal/graalJavaAccess.hpp"
-#include "graal/graalCompiler.hpp"
+#include "graal/graalRuntime.hpp"
 
 // -----------------------------------------------------
 // Implementation of JavaCallWrapper
@@ -52,7 +52,7 @@
 
   guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code");
   assert(!thread->owns_locks(), "must release all locks when leaving VM");
-  guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler");
+  guarantee(thread->can_call_java(), "cannot make java calls from the compiler");
   _result   = result;
 
   // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub,
@@ -366,7 +366,7 @@
 #endif
 
 
-  assert(!thread->is_Compiler_thread(), "cannot compile from the compiler");
+  assert(thread->can_call_java(), "cannot compile from the compiler");
   if (CompilationPolicy::must_be_compiled(method)) {
     CompileBroker::compile_method(method, InvocationEntryBci,
                                   CompilationPolicy::policy()->initial_compile_level(),
@@ -413,7 +413,7 @@
       ((JavaThread*) THREAD)->set_graal_alternate_call_target(nm->verified_entry_point());
       oop graalInstalledCode = nm->graal_installed_code();
       if (graalInstalledCode != NULL && graalInstalledCode->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isExternal(graalInstalledCode)) {
-        entry_point = GraalCompiler::instance()->get_external_deopt_i2c_entry();
+        entry_point = GraalRuntime::get_external_deopt_i2c_entry();
       } else {
       entry_point = method->adapter()->get_i2c_entry();
       }
--- a/src/share/vm/runtime/mutex.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/mutex.cpp	Fri May 30 15:09:09 2014 +0200
@@ -280,16 +280,6 @@
   return x & 0x7FFFFFFF ;
 }
 
-static inline jint MarsagliaXOR (jint * const a) {
-  jint x = *a ;
-  if (x == 0) x = UNS(a)|1 ;
-  x ^= x << 6;
-  x ^= ((unsigned)x) >> 21;
-  x ^= x << 7 ;
-  *a = x ;
-  return x & 0x7FFFFFFF ;
-}
-
 static int Stall (int its) {
   static volatile jint rv = 1 ;
   volatile int OnFrame = 0 ;
--- a/src/share/vm/runtime/mutexLocker.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/mutexLocker.cpp	Fri May 30 15:09:09 2014 +0200
@@ -280,7 +280,6 @@
   def(JfrStream_lock               , Mutex,   nonleaf+2,   true);
   def(JfrStacktrace_lock           , Mutex,   special,     true );
 #endif
-
 }
 
 GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/share/vm/runtime/thread.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/thread.cpp	Fri May 30 15:09:09 2014 +0200
@@ -1680,9 +1680,11 @@
   if (_thread_stat != NULL) delete _thread_stat;
 
 #ifdef GRAAL
-  if (GraalCounterSize > 0 && graal_counters_include(threadObj())) {
-    for (int i = 0; i < GraalCounterSize; i++) {
-      _graal_old_thread_counters[i] += _graal_counters[i];
+  if (GraalCounterSize > 0) {
+    if (graal_counters_include(threadObj())) {
+      for (int i = 0; i < GraalCounterSize; i++) {
+        _graal_old_thread_counters[i] += _graal_counters[i];
+      }
     }
     FREE_C_HEAP_ARRAY(jlong, _graal_counters, mtInternal);
   }
@@ -2251,7 +2253,7 @@
 
   // Do not throw asynchronous exceptions against the compiler thread
   // (the compiler thread should not be a Java thread -- fix in 1.4.2)
-  if (is_Compiler_thread()) return;
+  if (!can_call_java()) return;
 
   {
     // Actually throw the Throwable against the target Thread - however
@@ -3309,6 +3311,12 @@
 #endif
 }
 
+#ifdef COMPILERGRAAL
+bool CompilerThread::can_call_java() const {
+  return _compiler != NULL && _compiler->is_graal();
+}
+#endif
+
 void CompilerThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
   JavaThread::oops_do(f, cld_f, cf);
   if (_scanned_nmethod != NULL && cf != NULL) {
@@ -4332,7 +4340,7 @@
   {
     MutexLockerEx ml(doLock ? Threads_lock : NULL);
     ALL_JAVA_THREADS(p) {
-      if (p->is_Compiler_thread()) continue;
+      if (!p->can_call_java()) continue;
 
       address pending = (address)p->current_pending_monitor();
       if (pending == monitor) {             // found a match
--- a/src/share/vm/runtime/thread.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/thread.hpp	Fri May 30 15:09:09 2014 +0200
@@ -321,6 +321,9 @@
   virtual bool is_Named_thread() const               { return false; }
   virtual bool is_Worker_thread() const              { return false; }
 
+  // Can this thread make Java upcalls
+  virtual bool can_call_java() const                 { return true;  }
+
   // Casts
   virtual WorkerThread* as_Worker_thread() const     { return NULL; }
 
@@ -1876,8 +1879,13 @@
   CompilerThread(CompileQueue* queue, CompilerCounters* counters);
 
   bool is_Compiler_thread() const                { return true; }
+
+#ifdef COMPILERGRAAL
+  virtual bool can_call_java() const;
+#endif
+
   // Hide this compiler thread from external view.
-  bool is_hidden_from_external_view() const      { return true; }
+  bool is_hidden_from_external_view() const      { return !can_call_java(); }
 
   void set_compiler(AbstractCompiler* c)         { _compiler = c; }
   AbstractCompiler* compiler() const             { return _compiler; }
--- a/src/share/vm/runtime/vmStructs.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/vmStructs.cpp	Fri May 30 15:09:09 2014 +0200
@@ -70,6 +70,9 @@
 #include "oops/constMethod.hpp"
 #include "oops/constantPool.hpp"
 #include "oops/cpCache.hpp"
+#ifdef GRAAL
+#include "oops/fieldStreams.hpp"
+#endif
 #include "oops/instanceClassLoaderKlass.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/instanceMirrorKlass.hpp"
@@ -105,7 +108,9 @@
 #include "utilities/hashtable.hpp"
 #include "utilities/macros.hpp"
 #ifdef GRAAL
+# include "graal/graalRuntime.hpp"
 # include "graal/vmStructs_graal.hpp"
+# include "hsail/vm/vmStructs_hsail.hpp"
 #endif
 #ifdef TARGET_ARCH_x86
 # include "vmStructs_x86.hpp"
@@ -153,8 +158,6 @@
 # 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"
@@ -1307,6 +1310,7 @@
   nonstatic_field(CompileTask,                 _osr_bci,                                     int)                                    \
   nonstatic_field(CompileTask,                 _comp_level,                                  int)                                    \
   nonstatic_field(CompileTask,                 _compile_id,                                  uint)                                   \
+  nonstatic_field(CompileTask,                 _num_inlined_bytecodes,                       int)                                    \
   nonstatic_field(CompileTask,                 _next,                                        CompileTask*)                           \
   nonstatic_field(CompileTask,                 _prev,                                        CompileTask*)                           \
                                                                                                                                      \
@@ -3041,7 +3045,9 @@
                  GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY,
                  GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY)
 
+#ifdef GRAAL
   VM_STRUCTS_GPU_HSAIL(GENERATE_NONSTATIC_VM_STRUCT_ENTRY)
+#endif
           
   VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
                     GENERATE_STATIC_VM_STRUCT_ENTRY,
@@ -3093,8 +3099,10 @@
                GENERATE_C2_VM_TYPE_ENTRY,
                GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY)
 
+#ifdef GRAAL
   VM_TYPES_GPU_HSAIL(GENERATE_VM_TYPE_ENTRY,
                GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
+#endif
 
   VM_TYPES_OS_CPU(GENERATE_VM_TYPE_ENTRY,
                   GENERATE_TOPLEVEL_VM_TYPE_ENTRY,
@@ -3119,6 +3127,7 @@
 #ifdef GRAAL
   VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY,
                          GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
+
 #endif
 
 #if INCLUDE_ALL_GCS
@@ -3200,7 +3209,9 @@
                  CHECK_NO_OP,
                  CHECK_NO_OP);
 
-  VM_STRUCTS_GPU_HSAIL(CHECK_NONSTATIC_VM_STRUCT_ENTRY);
+#ifdef GRAAL
+  VM_STRUCTS_GPU_HSAIL(CHECK_NONSTATIC_VM_STRUCT_ENTRY)
+#endif
 
   VM_STRUCTS_OS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
                     CHECK_STATIC_VM_STRUCT_ENTRY,
@@ -3242,8 +3253,10 @@
                CHECK_C2_VM_TYPE_ENTRY,
                CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY);
 
+#ifdef GRAAL
   VM_TYPES_GPU_HSAIL(CHECK_VM_TYPE_ENTRY,
                CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
+#endif
 
   VM_TYPES_OS_CPU(CHECK_VM_TYPE_ENTRY,
                   CHECK_SINGLE_ARG_VM_TYPE_NO_OP,
@@ -3470,3 +3483,11 @@
   }
 }
 #endif
+
+
+#ifdef GRAAL
+// Emit intialization code for HotSpotVMConfig.  It's placed here so
+// it can take advantage of the relaxed access checking enjoyed by
+// VMStructs.
+#include "HotSpotVMConfig.inline.hpp"
+#endif
--- a/src/share/vm/runtime/vmStructs.hpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/runtime/vmStructs.hpp	Fri May 30 15:09:09 2014 +0200
@@ -126,6 +126,12 @@
   static void test();
 #endif
 
+#ifdef GRAAL
+  // The definition of this method is generated by
+  // com.oracle.graal.hotspotvmconfig.HotSpotVMConfigProcessor.
+static void initHotSpotVMConfig(oop config);
+#endif
+
 private:
   // Look up a type in localHotSpotVMTypes using strcmp() (debug build only).
   // Returns 1 if found, 0 if not.
--- a/src/share/vm/utilities/exceptions.cpp	Fri May 30 13:23:53 2014 +0200
+++ b/src/share/vm/utilities/exceptions.cpp	Fri May 30 15:09:09 2014 +0200
@@ -84,7 +84,7 @@
 #endif // ASSERT
 
   if (thread->is_VM_thread()
-      || thread->is_Compiler_thread() ) {
+      || !thread->can_call_java() ) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
     thread->set_pending_exception(Universe::vm_exception(), file, line);
@@ -107,7 +107,7 @@
   }
 
   if (thread->is_VM_thread()
-      || thread->is_Compiler_thread() ) {
+      || !thread->can_call_java() ) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
     thread->set_pending_exception(Universe::vm_exception(), file, line);
--- a/test/baseline_whitelist.txt	Fri May 30 13:23:53 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-com.oracle.graal.jtt.loop.Loop03
-com.oracle.graal.jtt.loop.Loop04
-com.oracle.graal.jtt.loop.Loop08
-com.oracle.graal.jtt.loop.Loop11
-com.oracle.graal.jtt.bytecode.BC_iadd
-com.oracle.graal.jtt.bytecode.BC_iadd2
-com.oracle.graal.jtt.bytecode.BC_iadd3
-com.oracle.graal.jtt.bytecode.BC_ifeq_2
-com.oracle.graal.jtt.bytecode.BC_ifeq_3
-com.oracle.graal.jtt.bytecode.BC_ifeq
-com.oracle.graal.jtt.bytecode.BC_aload_3
-com.oracle.graal.jtt.bytecode.BC_aload_2
-com.oracle.graal.jtt.bytecode.BC_aload_1
-com.oracle.graal.jtt.bytecode.BC_aload_0
-com.oracle.graal.jtt.bytecode.BC_areturn
-com.oracle.graal.jtt.bytecode.BC_freturn
-com.oracle.graal.jtt.bytecode.BC_iconst
-com.oracle.graal.jtt.bytecode.BC_ireturn
-com.oracle.graal.jtt.bytecode.BC_lreturn
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/whitelist_baseline.txt	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,28 @@
+com.oracle.graal.jtt.loop.Loop03
+com.oracle.graal.jtt.loop.Loop04
+com.oracle.graal.jtt.loop.Loop08
+com.oracle.graal.jtt.loop.Loop11
+com.oracle.graal.jtt.bytecode.BC_iadd
+com.oracle.graal.jtt.bytecode.BC_iadd2
+com.oracle.graal.jtt.bytecode.BC_iadd3
+com.oracle.graal.jtt.bytecode.BC_ifeq_2
+com.oracle.graal.jtt.bytecode.BC_ifeq_3
+com.oracle.graal.jtt.bytecode.BC_ifeq
+com.oracle.graal.jtt.bytecode.BC_aload_3
+com.oracle.graal.jtt.bytecode.BC_aload_2
+com.oracle.graal.jtt.bytecode.BC_aload_1
+com.oracle.graal.jtt.bytecode.BC_aload_0
+com.oracle.graal.jtt.bytecode.BC_areturn
+com.oracle.graal.jtt.bytecode.BC_freturn
+com.oracle.graal.jtt.bytecode.BC_iconst
+com.oracle.graal.jtt.bytecode.BC_ireturn
+com.oracle.graal.jtt.bytecode.BC_lreturn
+com.oracle.graal.jtt.bytecode.BC_getstatic_b
+com.oracle.graal.jtt.bytecode.BC_getstatic_c
+com.oracle.graal.jtt.bytecode.BC_getstatic_d
+com.oracle.graal.jtt.bytecode.BC_getstatic_f
+com.oracle.graal.jtt.bytecode.BC_getstatic_i
+com.oracle.graal.jtt.bytecode.BC_getstatic_l
+com.oracle.graal.jtt.bytecode.BC_getstatic_s
+com.oracle.graal.jtt.bytecode.BC_getstatic_z
+com.oracle.graal.jtt.bytecode.BC_arraylength
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/whitelist_shortunittest.txt	Fri May 30 15:09:09 2014 +0200
@@ -0,0 +1,3 @@
+com.oracle.graal.jtt.bytecode.*
+com.oracle.graal.jtt.loop.*
+com.oracle.graal.jtt.except.*