changeset 15606:357e7202de5b

Merge with d556971b409ca9f5ff13900d8b7b82549fd1f17a
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Mon, 12 May 2014 21:29:29 -0700
parents bb9473723904 (current diff) d556971b409c (diff)
children e0e1aa1b9295 2d63ce48d222
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadExceptionObjectNode.java
diffstat 187 files changed, 4812 insertions(+), 1894 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon May 12 20:17:25 2014 -0700
+++ b/.hgtags	Mon May 12 21:29:29 2014 -0700
@@ -405,3 +405,4 @@
 41f4cad94c581034d4c427d2aaabcc20f26342d0 hs25-b63
 b124e22eb772806c13d942cc110de38da0108147 graal-0.1
 483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2
+9535eccd2a115f6c6f0b15efb508b11ff74cc0d3 graal-0.3
--- a/CHANGELOG.md	Mon May 12 20:17:25 2014 -0700
+++ b/CHANGELOG.md	Mon May 12 21:29:29 2014 -0700
@@ -2,6 +2,16 @@
 
 ## `tip`
 ### Graal
+* Made initialization of Graal runtime lazy in hosted mode.
+
+### 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).
@@ -9,18 +19,16 @@
 * 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.
+* 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)
@@ -67,4 +75,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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Mon May 12 21:29:29 2014 -0700
@@ -166,16 +166,16 @@
             }
 
             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);
                     }
--- /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	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 21:29:29 2014 -0700
@@ -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);
+    }
+}
--- a/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java	Mon May 12 21:29:29 2014 -0700
@@ -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");
     }
 
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Mon May 12 21:29:29 2014 -0700
@@ -35,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.*;
@@ -92,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);
@@ -120,7 +127,7 @@
             // add loops ? how do we add looks when we haven't parsed the bytecode?
 
             // create the control flow graph
-            BaselineControlFlowGraph cfg = new BaselineControlFlowGraph(blockMap);
+            BaselineControlFlowGraph cfg = BaselineControlFlowGraph.compute(blockMap);
 
             // create the LIR
             List<? extends AbstractBlock<?>> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.blocks.size(), blockMap.startBlock);
@@ -471,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
@@ -488,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
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineControlFlowGraph.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineControlFlowGraph.java	Mon May 12 21:29:29 2014 -0700
@@ -24,24 +24,33 @@
 
 import java.util.*;
 
-import com.oracle.graal.compiler.common.*;
 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 BciBlock[] blocks;
+    private List<BciBlock> blocks;
     private Collection<Loop<BciBlock>> loops;
-    private BitSet visited;
 
-    public BaselineControlFlowGraph(BciBlockMapping blockMap) {
-        blocks = blockMap.blocks.toArray(new BciBlock[0]);
-        loops = new ArrayList<>();
-        computeLoopInformation();
+    public 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);
+        }
     }
 
-    public BciBlock[] getBlocks() {
+    private BaselineControlFlowGraph(BciBlockMapping blockMap) {
+        blocks = blockMap.blocks;
+        loops = new ArrayList<>();
+    }
+
+    public List<BciBlock> getBlocks() {
         return blocks;
     }
 
@@ -50,50 +59,53 @@
     }
 
     public BciBlock getStartBlock() {
-        if (blocks.length > 0) {
-            return blocks[0];
+        if (!blocks.isEmpty()) {
+            return blocks.get(0);
         }
         return null;
     }
 
-    private void computeLoopInformation() {
-        visited = new BitSet(blocks.length);
-        Deque<BaselineLoop> stack = new ArrayDeque<>();
-        for (int i = blocks.length - 1; i >= 0; i--) {
-            BciBlock block = blocks[i];
-            calcLoop(block, stack);
+    private void 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 void calcLoop(BciBlock block, Deque<BaselineLoop> stack) {
-        if (visited.get(block.getId())) {
-            return;
+    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);
         }
-        visited.set(block.getId());
-        if (block.isLoopEnd()) {
-            BciBlock loopHeader = getLoopHeader(block);
-            BaselineLoop l = new BaselineLoop(stack.peek(), loops.size(), loopHeader);
-            loops.add(l);
-            stack.push(l);
-        }
-        block.loop = stack.peek();
-        if (block.isLoopHeader()) {
-            assert block.loop.header.equals(block);
-            stack.pop();
-        }
-        for (BciBlock pred : block.getPredecessors()) {
-            calcLoop(pred, stack);
+        return loop;
+    }
+
+    private void calcLoop(BciBlock block, BciBlockMapping blockMap) {
+        int loopId = block.getLoopId();
+        if (loopId != -1) {
+            block.setLoop(getLoop(loopId, blockMap));
+
         }
     }
 
-    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.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon May 12 21:29:29 2014 -0700
@@ -601,7 +601,7 @@
         }
     }
 
-    protected Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+    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;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -56,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)), state(deopt)));
-    }
-
-    @Override
     protected boolean peephole(ValueNode valueNode) {
         if ((valueNode instanceof IntegerDivNode) || (valueNode instanceof IntegerRemNode)) {
             FixedBinaryNode divRem = (FixedBinaryNode) valueNode;
@@ -316,7 +310,7 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
-    private AMD64Arithmetic getOp(ValueNode operation, Access access) {
+    protected AMD64Arithmetic getOp(ValueNode operation, Access access) {
         Kind memoryKind = getMemoryKind(access);
         if (operation.getClass() == IntegerAddNode.class) {
             switch (memoryKind) {
@@ -455,7 +449,7 @@
         return null;
     }
 
-    @MatchRule("(Write Narrow=narrow value)")
+    @MatchRule("(Write Narrow=narrow location value)")
     public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
         return builder -> {
             PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp());
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java	Mon May 12 21:29:29 2014 -0700
@@ -30,6 +30,8 @@
 
     Loop<T> getLoop();
 
+    void setLoop(Loop<T> loop);
+
     int getLoopDepth();
 
     boolean isLoopHeader();
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/BlockMap.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/Loop.java	Mon May 12 21:29:29 2014 -0700
@@ -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;
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon May 12 21:29:29 2014 -0700
@@ -183,7 +183,7 @@
 
     private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
         assert getBits() == other.getBits();
-        if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0) {
+        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;
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -25,11 +25,9 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.hsail.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -63,14 +61,6 @@
     }
 
     @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, 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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon May 12 21:29:29 2014 -0700
@@ -894,4 +894,9 @@
         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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -40,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);
 
@@ -60,10 +55,6 @@
         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
@@ -134,12 +125,6 @@
     }
 
     @Override
-    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
-        assert v.getKind() == Kind.Object;
-        append(new PTXMove.NullCheckOp(gen.load(operand(v)), 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/SPARCNodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -29,7 +29,6 @@
 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.*;
 
 /**
@@ -59,12 +58,6 @@
     }
 
     @Override
-    public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
-        assert v.getKind() == Kind.Object;
-        append(new NullCheckOp(gen.load(operand(v)), state(deopting)));
-    }
-
-    @Override
     public void visitInfopointNode(InfopointNode i) {
         // TODO Auto-generated method stub
         throw GraalInternalError.unimplemented();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Mon May 12 21:29:29 2014 -0700
@@ -384,7 +384,7 @@
 
     public StructuredGraph visualize(StructuredGraph graph, String title) {
         DebugConfig debugConfig = DebugScope.getConfig();
-        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
         try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
             Debug.dump(graph, title);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon May 12 21:29:29 2014 -0700
@@ -164,7 +164,7 @@
     @Test
     public void testLoop1() {
         SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(6, schedule.getCFG().getBlocks().length);
+        assertEquals(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);
+        assertEquals(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);
+        assertEquals(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(10, schedule.getCFG().getBlocks().length);
+        assertEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -285,7 +285,7 @@
     @Test
     public void testIfRead1() {
         SchedulePhase schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(3, schedule.getCFG().getBlocks().length);
+        assertEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
     }
@@ -306,7 +306,7 @@
     @Test
     public void testIfRead2() {
         SchedulePhase schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(3, schedule.getCFG().getBlocks().length);
+        assertEquals(3, schedule.getCFG().getBlocks().size());
         assertEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -328,7 +328,7 @@
     @Test
     public void testIfRead3() {
         SchedulePhase schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(4, schedule.getCFG().getBlocks().length);
+        assertEquals(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);
+        assertEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
         assertReadAndWriteInSameBlock(schedule, true);
@@ -368,7 +368,7 @@
     @Test
     public void testIfRead5() {
         SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(4, schedule.getCFG().getBlocks().length);
+        assertEquals(4, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
@@ -397,7 +397,7 @@
         StructuredGraph graph = schedule.getCFG().graph;
         NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class);
 
-        assertEquals(1, schedule.getCFG().getBlocks().length);
+        assertEquals(1, schedule.getCFG().getBlocks().size());
         assertEquals(8, writeNodes.count());
         assertEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Mon May 12 21:29:29 2014 -0700
@@ -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/SimpleCFGTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Mon May 12 21:29:29 2014 -0700
@@ -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);
+        assertEquals(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));
+        assertEquals(blocks.get(0), cfg.blockFor(graph.start()));
+        assertEquals(blocks.get(0), cfg.blockFor(ifNode));
+        assertEquals(blocks.get(1), cfg.blockFor(trueBegin));
+        assertEquals(blocks.get(1), cfg.blockFor(trueEnd));
+        assertEquals(blocks.get(2), cfg.blockFor(falseBegin));
+        assertEquals(blocks.get(2), cfg.blockFor(falseEnd));
+        assertEquals(blocks.get(3), cfg.blockFor(merge));
+        assertEquals(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();
+            assertEquals(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/TypeSystemTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Mon May 12 21:29:29 2014 -0700
@@ -25,6 +25,7 @@
 import java.io.*;
 
 import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -181,6 +182,19 @@
         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");
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon May 12 21:29:29 2014 -0700
@@ -218,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;
@@ -228,8 +228,8 @@
         List<Block> linearScanOrder = null;
         try (Scope ds = Debug.scope("MidEnd")) {
             try (Scope s = Debug.scope("ComputeLinearScanOrder")) {
-                codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
-                linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
+                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");
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Mon May 12 21:29:29 2014 -0700
@@ -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)")
@@ -79,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;
@@ -91,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()) {
@@ -122,6 +127,14 @@
         return isEnabled(meterFilter);
     }
 
+    public boolean isMetderEnabled() {
+        return isEnabled(meterFilter);
+    }
+
+    public boolean isMemUseTrackingEnabled() {
+        return isEnabled(trackMemUseFilter);
+    }
+
     public boolean isDumpEnabled() {
         return isEnabled(dumpFilter);
     }
@@ -218,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/LinearScan.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon May 12 21:29:29 2014 -0700
@@ -702,7 +702,7 @@
                                     Debug.log("liveGen for operand %d", operandNum);
                                 }
                                 if (block.getLoop() != null) {
-                                    intervalInLoop.setBit(operandNum, block.getLoop().index);
+                                    intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
                                 }
                             }
 
@@ -733,7 +733,7 @@
                                 liveKill.set(varNum);
                                 Debug.log("liveKill for operand %d", varNum);
                                 if (block.getLoop() != null) {
-                                    intervalInLoop.setBit(varNum, block.getLoop().index);
+                                    intervalInLoop.setBit(varNum, block.getLoop().getIndex());
                                 }
                             }
 
@@ -1185,7 +1185,7 @@
                         // 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)) {
+                        if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
                             intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd);
                         }
                     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -26,7 +26,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.lir.gen.*;
 
-public class BytecodeLIRBuilder {
+public abstract class BytecodeLIRBuilder {
     protected final LIRGeneratorTool gen;
     protected final BytecodeParserTool parser;
 
@@ -61,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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -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();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.gen;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
@@ -55,6 +56,36 @@
 /**
  * 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;
@@ -71,7 +102,9 @@
         this.gen = gen;
         this.nodeOperands = graph.createNodeMap();
         this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
-        matchRules = MatchRuleRegistry.lookup(getClass());
+        if (MatchExpressions.getValue()) {
+            matchRules = MatchRuleRegistry.lookup(getClass());
+        }
     }
 
     @SuppressWarnings("hiding")
@@ -210,11 +243,9 @@
 
         List<ScheduledNode> nodes = blockMap.get(block);
 
-        if (MatchExpressions.getValue()) {
-            // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
-            // of instructions
-            matchComplexExpressions(nodes);
-        }
+        // 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);
@@ -274,6 +305,13 @@
     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);
+                    }
+                }
+
                 // Match the nodes in backwards order to encourage longer matches.
                 for (int index = nodes.size() - 1; index >= 0; index--) {
                     ScheduledNode snode = nodes.get(index);
@@ -281,6 +319,9 @@
                         continue;
                     }
                     ValueNode node = (ValueNode) snode;
+                    if (getOperand(node) != null) {
+                        continue;
+                    }
                     // See if this node is the root of any MatchStatements
                     List<MatchStatement> statements = matchRules.get(node.getClass());
                     if (statements != null) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Mon May 12 20:17:25 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +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.match;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Helper class to describe the matchable nodes in the core Graal IR. These could possibly live in
- * their respective classes but for simplicity in the {@link MatchProcessor} they are grouped here.
- */
-@MatchableNode(nodeClass = ConstantNode.class, inputs = 0)
-@MatchableNode(nodeClass = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(nodeClass = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(nodeClass = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
-@MatchableNode(nodeClass = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class)
-@MatchableNode(nodeClass = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(nodeClass = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(nodeClass = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(nodeClass = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
-@MatchableNode(nodeClass = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class)
-@MatchableNode(nodeClass = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(nodeClass = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class)
-@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(nodeClass = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(nodeClass = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-public class GraalMatchableNodes {
-    public static class BinaryNodeAdapter extends MatchNodeAdapter {
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((BinaryNode) node).x();
-        }
-
-        @Override
-        protected ValueNode getSecondInput(ValueNode node) {
-            return ((BinaryNode) node).y();
-        }
-    }
-
-    public static class WriteNodeAdapter extends MatchNodeAdapter {
-
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((WriteNode) node).object();
-        }
-
-        @Override
-        protected ValueNode getSecondInput(ValueNode node) {
-            return ((WriteNode) node).value();
-        }
-    }
-
-    public static class ConvertNodeAdapter extends MatchNodeAdapter {
-
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((ConvertNode) node).getInput();
-        }
-    }
-
-    public static class ReinterpretNodeAdapter extends MatchNodeAdapter {
-
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((ReinterpretNode) node).value();
-        }
-    }
-
-    public static class IfNodeAdapter extends MatchNodeAdapter {
-
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((IfNode) node).condition();
-        }
-    }
-
-    public static class ReadNodeAdapter extends MatchNodeAdapter {
-
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((Access) node).object();
-        }
-    }
-
-    public static class BinaryOpLogicNodeAdapter extends MatchNodeAdapter {
-
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((BinaryOpLogicNode) node).x();
-        }
-
-        @Override
-        protected ValueNode getSecondInput(ValueNode node) {
-            return ((BinaryOpLogicNode) node).y();
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Mon May 12 21:29:29 2014 -0700
@@ -31,7 +31,7 @@
 import com.oracle.graal.compiler.match.MatchPattern.Result;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -100,16 +100,16 @@
         // 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 ConstantNode || node instanceof LocationNode || node instanceof VirtualObjectNode || node instanceof ParameterNode) {
-                // these can be evaluated lazily so don't worry about them. This should probably be
-                // captured by some interface that indicates that their generate method is empty.
+            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) {
+            } 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.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode);
+                        Debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode);
                     }
                 }
                 return Result.NOT_SAFE(node, rule.getPattern());
@@ -147,14 +147,16 @@
     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());
         }
 
-        int index = nodes.indexOf(node);
-        if (index == -1) {
-            return Result.NOT_IN_BLOCK(node, rule.getPattern());
-        }
         startIndex = Math.min(startIndex, index);
         if (consumed == null) {
             consumed = new ArrayList<>(2);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java	Mon May 12 20:17:25 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.match;
-
-import com.oracle.graal.nodes.*;
-
-/**
- * Helper class to visit the matchable inputs of a node in a specified order. This may not be needed
- * in the end since this could probably be done using the inputs iterator but it simplifies things
- * for the moment.
- */
-public class MatchNodeAdapter {
-    @SuppressWarnings("unused")
-    protected ValueNode getFirstInput(ValueNode node) {
-        throw new InternalError();
-    }
-
-    @SuppressWarnings("unused")
-    protected ValueNode getSecondInput(ValueNode node) {
-        throw new InternalError();
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Mon May 12 21:29:29 2014 -0700
@@ -22,8 +22,10 @@
  */
 package com.oracle.graal.compiler.match;
 
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -111,48 +113,62 @@
      * The expected type of the node. It must match exactly.
      */
     private final Class<? extends ValueNode> nodeClass;
+
     /**
      * An optional name for this node. A name can occur multiple times in a match and that name must
      * always refer to the same node of the match will fail.
      */
     private final String name;
-    /**
-     * An optional pattern for the first input.
-     */
-    private final MatchPattern first;
+
     /**
-     * An optional pattern for the second input.
+     * Patterns to match the inputs.
      */
-    private final MatchPattern second;
+    private final MatchPattern[] patterns;
+
     /**
-     * Helper class to visit the inputs.
+     * The inputs to match the patterns against.
      */
-    private final MatchNodeAdapter adapter;
+    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, null, null, null, singleUser);
+        this(null, name, singleUser);
     }
 
     public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) {
-        this(nodeClass, name, null, null, null, singleUser);
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.patterns = EMPTY_PATTERNS;
+        this.inputs = null;
     }
 
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchNodeAdapter adapter, boolean singleUser) {
-        this(nodeClass, name, first, null, adapter, singleUser);
-    }
-
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchNodeAdapter adapter, boolean singleUser) {
+    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.first = first;
-        this.second = second;
-        this.adapter = adapter;
+        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() {
@@ -181,6 +197,36 @@
         return result;
     }
 
+    /**
+     * 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(Class<? extends ValueNode> theClass, String[] names) {
+        NodeClass.Position[] result = new NodeClass.Position[names.length];
+        NodeClass nodeClass = NodeClass.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 Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) {
         Result result = matchType(node);
         if (result != Result.OK) {
@@ -197,10 +243,10 @@
             result = context.captureNamedValue(name, nodeClass, node);
         }
 
-        if (first != null) {
-            result = first.matchUsage(adapter.getFirstInput(node), context, false);
-            if (result == Result.OK && second != null) {
-                result = second.matchUsage(adapter.getSecondInput(node), context, false);
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchUsage(getInput(input, node), context, false);
+            if (result != Result.OK) {
+                return result;
             }
         }
 
@@ -231,10 +277,10 @@
             }
         }
 
-        if (first != null) {
-            result = first.matchShape(adapter.getFirstInput(node), statement, false);
-            if (result == Result.OK && second != null) {
-                result = second.matchShape(adapter.getSecondInput(node), statement, false);
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchShape(getInput(input, node), statement, false);
+            if (result != Result.OK) {
+                return result;
             }
         }
 
@@ -248,23 +294,45 @@
      */
     public String formatMatch(ValueNode root) {
         String result = String.format("%s", root);
-        if (first == null && second == null) {
+        if (patterns.length == 0) {
             return result;
         } else {
-            return "(" + result + (first != null ? " " + first.formatMatch(adapter.getFirstInput(root)) : "") + (second != null ? " " + second.formatMatch(adapter.getSecondInput(root)) : "") + ")";
+            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 pre = first != null || second != null ? "(" : "";
-            String post = first != null || second != null ? ")" : "";
             String nodeName = nodeClass.getSimpleName();
             nodeName = nodeName.substring(0, nodeName.length() - 4);
-            return pre + nodeName + (name != null ? "=" + name : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post;
+            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();
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Mon May 12 21:29:29 2014 -0700
@@ -36,6 +36,7 @@
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -50,9 +51,13 @@
  *     }
  * </pre>
  */
-@SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode"})
+@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();
@@ -69,6 +74,8 @@
         }
     }
 
+    private static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+
     private class RuleParser {
         private ArrayList<TypeDescriptor> capturedTypes = new ArrayList<>();
 
@@ -92,7 +99,7 @@
                 m.region(m.end(), m.regionEnd());
             }
             if (end != m.regionEnd()) {
-                throw new RuleParseError("Unnexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
+                throw new RuleParseError("Unexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
             }
             tokens = list.toArray(new String[0]);
 
@@ -126,14 +133,14 @@
             if (peek("(").equals("(")) {
                 next();
                 MatchDescriptor descriptor = parseType(true);
-                for (int n = 0; n < descriptor.nodeType.inputs; n++) {
+                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; n++) {
+                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
                     if (descriptor.inputs[n] == null) {
                         throw new RuleParseError("not enough inputs for " + descriptor.name);
                     }
@@ -142,6 +149,7 @@
                     next();
                     return descriptor;
                 }
+                throw new RuleParseError("Too many arguments to " + descriptor.nodeType.nodeClass);
             }
             throw new RuleParseError("Extra tokens following match pattern: " + peek(null));
         }
@@ -185,6 +193,13 @@
         }
 
         /**
+         * 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
          */
@@ -197,7 +212,63 @@
         }
     }
 
-    static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+    /**
+     * 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 MATCHPROCESSOR_LOG = "/tmp/matchprocessor.log";
+
+    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(MATCHPROCESSOR_LOG, 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;
@@ -206,25 +277,21 @@
          * The name uses in match expressions to refer to this type.
          */
         final String shortName;
+
         /**
-         * The {@link ValueNode} class represented by this type.
+         * The simple name of the {@link ValueNode} class represented by this type.
          */
         final String nodeClass;
 
         /**
-         * The {@link ValueNode} class represented by this type.
+         * The package of {@link ValueNode} class represented by this type.
          */
         final String nodePackage;
 
         /**
-         * Expected number of matchable inputs. Should be less <= 2 at the moment.
+         * The matchable inputs of the node.
          */
-        final int inputs;
-
-        /**
-         * An adapter class to read the proper matchable inputs of the class.
-         */
-        final String adapter;
+        final String[] inputs;
 
         /**
          * Should swapped variants of this match be generated. The user of the match is expected to
@@ -237,20 +304,19 @@
          * Can multiple users of this node subsume it. Constants can be swallowed into a match even
          * if there are multiple users.
          */
-        final boolean cloneable;
+        final boolean shareable;
 
         final Set<Element> originatingElements = new HashSet<>();
 
-        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
+        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.adapter = adapter;
             this.commutative = commutative;
-            this.cloneable = (nodePackage + "." + nodeClass).equals(ConstantNode.class.getName());
-            assert !commutative || inputs == 2;
+            this.shareable = shareable;
+            assert !commutative || inputs.length == 2;
         }
     }
 
@@ -265,13 +331,22 @@
     List<String> requiredPackages = new ArrayList<>();
 
     /**
-     * The automatically generated wrapper class for a method based MatchRule.
+     * The java.lang.reflect.Method for invoking a method based MatchRule.
      */
     private Map<ExecutableElement, MethodInvokerItem> invokers = new LinkedHashMap<>();
+
     private TypeDescriptor valueType;
 
-    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative, Element element) {
-        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, adapter, commutative);
+    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)) {
@@ -279,13 +354,10 @@
         }
     }
 
-    private static String findPackage(Element type) {
-        Element enclosing = type.getEnclosingElement();
-        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
-            enclosing = enclosing.getEnclosingElement();
-        }
-        if (enclosing != null && enclosing.getKind() == ElementKind.PACKAGE) {
-            return ((PackageElement) enclosing).getQualifiedName().toString();
+    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);
     }
@@ -299,12 +371,43 @@
             this.nodeType = nodeType;
             this.name = name;
             if (forExpression) {
-                this.inputs = new MatchDescriptor[nodeType.inputs];
+                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.
@@ -315,23 +418,15 @@
             String prefix = formatPrefix();
             String suffix = formatSuffix();
             ArrayList<String> variants = new ArrayList<>();
-            if (inputs.length == 2) {
-                // Generate this version and a swapped version
-                for (String first : inputs[0].generateVariants()) {
-                    for (String second : inputs[1].generateVariants()) {
-                        variants.add(prefix + ", " + first + ", " + second + suffix);
-                        if (nodeType.commutative) {
-                            variants.add(prefix + ", " + second + ", " + first + suffix);
-                        }
-                    }
-                }
-            } else if (inputs.length == 1) {
-                for (String first : inputs[0].generateVariants()) {
-                    variants.add(prefix + ", " + first + suffix);
+            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;
         }
 
@@ -345,13 +440,13 @@
 
         private String formatSuffix() {
             if (nodeType != null) {
-                if (inputs.length != nodeType.inputs) {
+                if (inputs.length != nodeType.inputs.length) {
                     return ", true)";
                 } else {
-                    if (nodeType.adapter != null) {
-                        return ", " + nodeType.adapter + "," + !nodeType.cloneable + ")";
+                    if (nodeType.inputs.length > 0) {
+                        return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ")";
                     }
-                    if (nodeType.cloneable) {
+                    if (nodeType.shareable) {
                         return ", false)";
                     }
                 }
@@ -359,12 +454,16 @@
             return ")";
         }
 
+        String generatePositionDeclaration() {
+            return String.format("private static final NodeClass.Position[] %s_positions = MatchPattern.findPositions(%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.
      */
-    static String fullClassName(Element element) {
+    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);
@@ -377,7 +476,7 @@
         String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
         Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
 
-        Types typeUtils = processingEnv.getTypeUtils();
+        Types typeUtils = typeUtils();
         Filer filer = processingEnv.getFiler();
         try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) {
 
@@ -391,12 +490,23 @@
             out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
             out.println("import " + GraalInternalError.class.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();
+            out.println("    private static Method lookupMethod(Class<?> theClass, String name, Class<?>... args) {");
+            out.println("        try {");
+            out.println("            return theClass.getDeclaredMethod(name, args);");
+            out.println("        } catch (Exception e) {");
+            out.println("            throw new GraalInternalError(e);");
+            out.println("        }");
+            out.println("    }");
+            out.println();
+
             // Generate declarations for the reflective invocation of the code generation methods.
             for (MethodInvokerItem invoker : invokers.values()) {
                 StringBuilder args = new StringBuilder();
@@ -413,22 +523,17 @@
                         types.append(", ");
                     }
                 }
-                out.printf("        private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
-                out.printf("        private static final Method %s;\n", invoker.reflectiveMethodName());
-                out.printf("        static {\n");
-                out.printf("            Method result = null;\n");
-                out.printf("            try {\n");
-                out.printf("                result = %s.class.getDeclaredMethod(\"%s\", %s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);
-                out.printf("             } catch (Exception e) {\n");
-                out.printf("                 throw new GraalInternalError(e);\n");
-                out.printf("             }\n");
-                out.printf("             %s = result;\n", invoker.reflectiveMethodName());
-                out.printf("        }\n");
-
+                out.printf("    private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
+                out.printf("    private static final Method %s = lookupMethod(%s.class, \"%s\", %s);\n", invoker.reflectiveMethodName(), invoker.nodeLIRBuilderClass, invoker.methodName, types);
                 out.println();
 
             }
 
+            for (String positionDeclaration : info.positionDeclarations) {
+                out.println("    " + positionDeclaration);
+            }
+            out.println();
+
             String desc = MatchStatement.class.getSimpleName();
             out.println("    // CheckStyle: stop line length check");
             out.println("    private static final List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList(");
@@ -536,6 +641,7 @@
         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;
@@ -551,40 +657,40 @@
         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 the generic node but don't enter it into the nodeTypes table
-            // since it shouldn't mentioned in match rules.
-            TypeMirror mirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
-            valueType = new TypeDescriptor(mirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), 0, null, false);
+            // 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);
 
-            // Import default definitions
-            processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName()));
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodeImport.class)) {
-                // Import any other definitions required by this element
-                String[] imports = element.getAnnotation(MatchableNodeImport.class).value();
-                for (String m : imports) {
-                    TypeElement el = processingEnv.getElementUtils().getTypeElement(m);
-                    processMatchableNode(el);
-                }
-            }
+            Map<TypeElement, MatchRuleDescriptor> map = new LinkedHashMap<>();
 
-            // Process any local MatchableNode declarations
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) {
-                processMatchableNode(element);
-            }
-
-            Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>();
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
-                processMatchRule(map, element);
+                processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
             }
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
-                processMatchRule(map, element);
+                processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror));
             }
 
             for (MatchRuleDescriptor info : map.values()) {
@@ -605,46 +711,23 @@
         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);
-                MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class);
-                for (MatchableNode matchable : matchables) {
-                    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);
-
-                    TypeMirror nodeAdapterMirror = null;
-                    try {
-                        matchable.adapter();
-                    } catch (MirroredTypeException e) {
-                        nodeAdapterMirror = e.getTypeMirror();
-                    }
-                    if (nodeAdapterMirror == null) {
-                        throw new GraalInternalError("Can't get mirror for adapter %s", element);
-                    }
-                    String nodeAdapter = null;
-                    if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) {
-                        nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString());
-                    }
-
-                    declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative(), 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);
@@ -652,11 +735,55 @@
         }
     }
 
-    private void reportExceptionThrow(Element element, Throwable t) {
-        processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)), element);
+    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) {
+    private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
         if (!processedMatchRule.contains(element)) {
             try {
                 processedMatchRule.add(element);
@@ -664,15 +791,22 @@
                 // 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)) {
-                    // System.err.println(matchRule);
-                    processMethodMatchRule((ExecutableElement) element, info, matchRule);
+                    processMethodMatchRule((ExecutableElement) element, info, matchRule, mirrors != null ? mirrors.get(i++) : mirror);
                 }
             } catch (Throwable t) {
                 reportExceptionThrow(element, t);
@@ -680,8 +814,42 @@
         }
     }
 
-    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule) {
-        Types typeUtils = processingEnv.getTypeUtils();
+    /**
+     * 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());
@@ -761,12 +929,144 @@
 
             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);
+            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;
+        }
+
+    }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Mon May 12 21:29:29 2014 -0700
@@ -27,15 +27,18 @@
 import com.oracle.graal.nodes.*;
 
 /**
- * This annotation declares a textual pattern for matching an HIR DAG. It's an s-expression with a
- * node followed by its inputs. Node types are always uppercase and lowercase words are the names of
- * nodes.
+ * 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>
- *   NAME := [a-z][a-zA-Z0-9]*
- *   NODETYPE := [A-Z][a-zA-Z0-9]*
- *   NODEORNAME :=  NODE [ = NAME ] | NAME
- *   EXPRESSION := ( NODEORNAME [ EXPRESSION | NODEORNAME [ EXPRESSION | NODEORNAME ] )
+ *   &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.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Mon May 12 21:29:29 2014 -0700
@@ -29,7 +29,7 @@
 
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 
 public class MatchRuleRegistry {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Mon May 12 21:29:29 2014 -0700
@@ -99,8 +99,15 @@
                 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));
+                }
             } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                 throw new GraalInternalError(e);
             }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Mon May 12 21:29:29 2014 -0700
@@ -34,7 +34,7 @@
     public Class<? extends NodeLIRBuilder> forClass();
 
     /**
-     * @return the {@link MatchStatement}s available with this {@link NodeLIRBuilder} subclass.
+     * @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass.
      */
     public List<MatchStatement> statements();
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Mon May 12 21:29:29 2014 -0700
@@ -27,7 +27,9 @@
 import com.oracle.graal.nodes.*;
 
 /**
- * Describes the properties of a node for use when building a {@link MatchPattern}.
+ * 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)
@@ -42,19 +44,18 @@
     Class<? extends ValueNode> nodeClass();
 
     /**
-     * The number of matchable inputs, which may be less than the real number of inputs.
+     * The names of the inputs in the order they should appear in the match.
      */
-    int inputs() default 0;
-
-    /**
-     * A helper class to visit the inputs in a specified order. Should be a subclass of
-     * {@link MatchNodeAdapter}.
-     */
-    Class<?> adapter() default MatchableNode.class;
+    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;
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java	Mon May 12 20:17:25 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +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.match;
-
-import java.lang.annotation.*;
-
-/**
- * A list of classes which contain one or more {@link MatchableNode} annotations describing nodes
- * that may be used in match expressions. Those {@link MatchableNode} declarations are parsed before
- * processing any {@link MatchRule}s.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface MatchableNodeImport {
-    String[] value() default {};
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java	Mon May 12 21:29:29 2014 -0700
@@ -25,7 +25,7 @@
 import java.lang.annotation.*;
 
 /**
- * The repeatable representation of {@link MatchableNode}. Should never be used directly.
+ * The repeatable representation of {@link MatchableNode}.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon May 12 21:29:29 2014 -0700
@@ -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;
@@ -586,6 +590,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
@@ -702,10 +769,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 +791,11 @@
             }
 
             @Override
+            public boolean isMemUseTrackingEnabled() {
+                return isMemUseTrackingEnabled;
+            }
+
+            @Override
             public boolean isDumpEnabled() {
                 return isDumpEnabled;
             }
@@ -783,6 +855,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 +958,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;
     }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java	Mon May 12 21:29:29 2014 -0700
@@ -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}
      * .
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugMemUseTracker.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugTimer.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Mon May 12 21:29:29 2014 -0700
@@ -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/DebugScope.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 21:29:29 2014 -0700
@@ -0,0 +1,102 @@
+/*
+ * 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 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();
+
+    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 = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId());
+        }
+
+        @Override
+        public void close() {
+            long end = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId());
+            long allocated = end - start;
+            if (parent != null) {
+                parent.nestedAmountToSubtract += allocated;
+            }
+            currentTracker.set(parent);
+            MemUseTrackerImpl.this.addToCurrentValue(allocated);
+            flat.addToCurrentValue(allocated - nestedAmountToSubtract);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/DefaultNodeCollectionsProvider.java	Mon May 12 21:29:29 2014 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.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/NodeClass.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon May 12 21:29:29 2014 -0700
@@ -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.*;
@@ -1371,12 +1372,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	Mon May 12 21:29:29 2014 -0700
@@ -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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/util/CollectionsAccess.java	Mon May 12 21:29:29 2014 -0700
@@ -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/AMD64HotSpotBytecodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -28,6 +28,7 @@
 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.*;
 
@@ -79,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();
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon May 12 21:29:29 2014 -0700
@@ -636,4 +636,9 @@
         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));
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -41,6 +41,7 @@
 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.*;
@@ -54,7 +55,6 @@
 /**
  * LIR generator specialized for AMD64 HotSpot.
  */
-@MatchableNodeImport({"com.oracle.graal.hotspot.nodes.HotSpotMatchableNodes"})
 public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
     private static ValueNode filterCompression(ValueNode node) {
@@ -65,7 +65,7 @@
         return result;
     }
 
-    private void emitCompareCompressedMemory(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
+    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.
@@ -95,6 +95,22 @@
         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);
         assert gen instanceof AMD64HotSpotLIRGenerator;
@@ -244,14 +260,116 @@
         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 ifCompareCompressedMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+    public ComplexMatchResult ifCompareMemoryObject(IfNode root, CompareNode compare, ValueNode value, Access access) {
         if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
             return builder -> {
-                emitCompareCompressedMemory(root, value, access, compare);
+                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;
             };
         }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Mon May 12 21:29:29 2014 -0700
@@ -766,17 +766,16 @@
             int numStackSlots = (numStackSlotBytes + 7) / 8;
 
             final int offsetToDeoptSaveStates = config.hsailSaveStatesOffset0;
-            final int sizeofKernelDeoptHeader = config.hsailKernelDeoptimizationHeaderSize;
             final int bytesPerSaveArea = 4 * numSRegs + 8 * numDRegs + 8 * numStackSlots;
-            final int sizeofKernelDeopt = sizeofKernelDeoptHeader + bytesPerSaveArea;
+            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);
@@ -1149,10 +1148,10 @@
         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) {
-            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) {
-            long offset = config.hsailFrameSaveAreaOffset + intSize * numSRegs + longSize * (regNumber - HSAIL.d0.number);
+            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);
@@ -1167,7 +1166,7 @@
         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.hsailFrameSaveAreaOffset + (intSize * numSRegs) + (longSize * numDRegs) + HSAIL.getStackOffsetStart(slot, slotSizeInBits);
+            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;
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Mon May 12 21:29:29 2014 -0700
@@ -285,4 +285,11 @@
         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.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java	Mon May 12 21:29:29 2014 -0700
@@ -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;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Mon May 12 21:29:29 2014 -0700
@@ -40,6 +40,7 @@
 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.extended.*;
@@ -340,4 +341,9 @@
 
         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));
+    }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Mon May 12 21:29:29 2014 -0700
@@ -692,7 +692,7 @@
             };
 
             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);
                 new WriteBarrierVerificationPhase().apply(graph);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon May 12 21:29:29 2014 -0700
@@ -25,6 +25,7 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*;
+import static sun.reflect.Reflection.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -34,11 +35,13 @@
 
 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.graph.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -52,9 +55,26 @@
  */
 public final class HotSpotGraalRuntime implements GraalRuntime, RuntimeProvider, StackIntrospection {
 
-    private static final HotSpotGraalRuntime instance = new HotSpotGraalRuntime();
+    private static final HotSpotGraalRuntime instance;
+
+    /**
+     * Initializes the native part of the Graal runtime.
+     */
+    private static native void init(Class<?> compilerToVMClass);
+
     static {
+        init(CompilerToVMImpl.class);
+
+        // The options must be processed before any code using them...
+        HotSpotOptions.initialize();
+
+        // ... including code in the constructor
+        instance = new HotSpotGraalRuntime();
+
+        // Why deferred initialization? See comment in completeInitialization().
         instance.completeInitialization();
+
+        registerFieldsToFilter(HotSpotGraalRuntime.class, "instance");
     }
 
     /**
@@ -73,10 +93,6 @@
         return instance;
     }
 
-    static {
-        Reflection.registerFieldsToFilter(HotSpotGraalRuntime.class, "instance");
-    }
-
     /**
      * Do deferred initialization.
      */
@@ -102,6 +118,8 @@
 
         this.vmToCompiler = toCompiler;
         this.compilerToVm = toVM;
+
+        this.vmToCompiler.startRuntime();
     }
 
     // Options must not be directly declared in HotSpotGraalRuntime - see VerifyOptionsPhase
@@ -359,11 +377,15 @@
         return getClass().getSimpleName();
     }
 
+    private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider();
+
     @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) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Mon May 12 21:29:29 2014 -0700
@@ -33,6 +33,7 @@
 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.*;
@@ -86,7 +87,7 @@
             try {
                 for (String line : Files.readAllLines(graalDotOptions, Charset.defaultCharset())) {
                     if (!line.startsWith("#")) {
-                        if (!setOption(line)) {
+                        if (!parseOption(line, null)) {
                             throw new InternalError("Invalid option \"" + line + "\" specified in " + graalDotOptions);
                         }
                     }
@@ -97,14 +98,39 @@
         }
     }
 
+    /**
+     * Gets the Graal specific options specified to HotSpot (e.g., on the command line).
+     *
+     * @param timeCompilations (out) true if the CITime or CITimeEach HotSpot VM options are set
+     */
+    private static native String[] getVMOptions(boolean[] timeCompilations);
+
     static {
         initializeOptions();
         loadOptionOverrides();
+
+        boolean[] timeCompilations = {false};
+        for (String option : getVMOptions(timeCompilations)) {
+            if (!parseOption(option, null)) {
+                throw new InternalError("Invalid Graal option \"-G:" + option + "\"");
+            }
+        }
+
+        if (timeCompilations[0] || 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");
+        }
     }
 
-    // Called from VM code
-    public static boolean setOption(String option) {
-        return parseOption(option, null);
+    /**
+     * Ensures {@link HotSpotOptions} is initialized.
+     */
+    public static void initialize() {
     }
 
     interface OptionConsumer {
@@ -237,23 +263,6 @@
     }
 
     /**
-     * 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
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon May 12 21:29:29 2014 -0700
@@ -1029,12 +1029,11 @@
 
     @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::_num_d_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumDRegOffset;
-    @HotSpotVMConstant(name = "sizeof(HSAILFrame)") @Stable public int hsailFrameSaveAreaOffset;
+    @HotSpotVMConstant(name = "sizeof(HSAILFrame)") @Stable public int hsailFrameHeaderSize;
     @HotSpotVMConstant(name = "sizeof(Hsail::HSAILKernelDeoptimization)") @Stable public int hsailKernelDeoptimizationHeaderSize;
     @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[0]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset0;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Mon May 12 21:29:29 2014 -0700
@@ -30,6 +30,12 @@
  */
 public interface VMToCompiler {
 
+    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).
@@ -40,9 +46,7 @@
 
     void shutdownCompiler() throws Exception;
 
-    void startCompiler(boolean bootstrapEnabled) throws Throwable;
-
-    void bootstrap() throws Throwable;
+    void shutdownRuntime() throws Throwable;
 
     void compileTheWorld() throws Throwable;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon May 12 21:29:29 2014 -0700
@@ -136,15 +136,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 {
@@ -192,6 +190,15 @@
             }
         }
 
+        BenchmarkCounters.initialize(runtime.getCompilerToVM());
+
+        runtimeStartTime = System.nanoTime();
+    }
+
+    public void startCompiler(boolean bootstrapEnabled) throws Throwable {
+
+        bootstrapRunning = bootstrapEnabled;
+
         if (runtime.getConfig().useGraalCompilationQueue) {
 
             // Create compilation queue.
@@ -243,9 +250,6 @@
                 t.start();
             }
         }
-        BenchmarkCounters.initialize(runtime.getCompilerToVM());
-
-        compilerStartTime = System.nanoTime();
     }
 
     /**
@@ -274,7 +278,7 @@
             TTY.flush();
         }
 
-        long startTime = System.currentTimeMillis();
+        long boostrapStartTime = System.currentTimeMillis();
 
         boolean firstRun = true;
         do {
@@ -310,12 +314,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);
@@ -326,7 +330,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();
@@ -366,11 +370,14 @@
                 });
             }
         }
+    }
+
+    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 {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Mon May 12 21:29:29 2014 -0700
@@ -192,10 +192,8 @@
             if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
                 newObjectSnippets.lower((NewMultiArrayNode) n, tool);
             }
-        } else if (n instanceof ExceptionObjectNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                lowerExceptionObjectNode((ExceptionObjectNode) n, tool);
-            }
+        } else if (n instanceof 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.
@@ -203,7 +201,7 @@
             boxingSnippets.lower((BoxNode) n, tool);
         } else if (n instanceof UnboxNode) {
             boxingSnippets.lower((UnboxNode) n, tool);
-        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
+        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode || n instanceof FloatRemNode) {
             /* No lowering, we generate LIR directly for these nodes. */
         } else {
             throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
@@ -734,19 +732,6 @@
         }
     }
 
-    private void lowerExceptionObjectNode(ExceptionObjectNode n, LoweringTool tool) {
-        LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) n.predecessor()).getLocationIdentity();
-        BeginNode entry = n.graph().add(new KillingBeginNode(locationsKilledByInvoke));
-        LoadExceptionObjectNode loadException = n.graph().add(new LoadExceptionObjectNode(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Throwable.class))));
-
-        loadException.setStateAfter(n.stateAfter());
-        n.replaceAtUsages(InputType.Value, loadException);
-        n.graph().replaceFixedWithFixed(n, entry);
-        entry.graph().addAfterFixed(entry, loadException);
-
-        exceptionObjectSnippets.lower(loadException, registers, tool);
-    }
-
     public static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
         StructuredGraph graph = commit.graph();
         for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Mon May 12 21:29:29 2014 -0700
@@ -90,13 +90,17 @@
                 }
                 break;
         }
-        throw GraalInternalError.shouldNotReachHere();
+        throw GraalInternalError.shouldNotReachHere(String.format("Unexpected input stamp %s", input));
     }
 
     public ValueNode getInput() {
         return input;
     }
 
+    public CompressEncoding getEncoding() {
+        return encoding;
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (input instanceof CompressionNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Mon May 12 20:17:25 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.compiler.match.*;
-import com.oracle.graal.nodes.*;
-
-@MatchableNode(nodeClass = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class)
-public class HotSpotMatchableNodes {
-    public static class CompressionNodeAdapter extends MatchNodeAdapter {
-        @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((CompressionNode) node).getInput();
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadExceptionObjectNode.java	Mon May 12 20:17:25 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
-
-    public LoadExceptionObjectNode(Stamp stamp) {
-        super(stamp);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, tool);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -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) {
@@ -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/LoadExceptionObjectSnippets.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Mon May 12 21:29:29 2014 -0700
@@ -30,9 +30,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
--- a/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/Decompiler.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/Decompiler.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerLoopBlock.java	Mon May 12 21:29:29 2014 -0700
@@ -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/AbstractFrameStateBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -124,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
@@ -144,6 +151,16 @@
     }
 
     /**
+     * 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];
+    }
+
+    /**
      * 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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Mon May 12 21:29:29 2014 -0700
@@ -154,6 +154,10 @@
             return loop;
         }
 
+        public void setLoop(Loop<BciBlock> loop) {
+            this.loop = loop;
+        }
+
         public int getLoopDepth() {
             return Long.bitCount(loops);
         }
@@ -178,6 +182,67 @@
             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;
         }
@@ -631,26 +696,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);
             }
@@ -659,6 +710,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;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon May 12 21:29:29 2014 -0700
@@ -337,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.jtt/src/com/oracle/graal/jtt/bytecode/BC_arraylength.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_arraylength.java	Mon May 12 21:29:29 2014 -0700
@@ -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.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon May 12 21:29:29 2014 -0700
@@ -63,6 +63,8 @@
 
     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);
 
     /**
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon May 12 21:29:29 2014 -0700
@@ -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)) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Mon May 12 21:29:29 2014 -0700
@@ -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;
@@ -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/LoopFragmentWhole.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Mon May 12 21:29:29 2014 -0700
@@ -58,7 +58,7 @@
     public NodeIterable<Node> 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/LoopsData.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -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.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java	Mon May 12 21:29:29 2014 -0700
@@ -122,6 +122,24 @@
     }
 
     @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));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon May 12 21:29:29 2014 -0700
@@ -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/calc/FloatRemNode.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Mon May 12 21:29:29 2014 -0700
@@ -31,7 +31,7 @@
 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,6 +57,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
     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/cfg/Block.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Mon May 12 21:29:29 2014 -0700
@@ -56,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() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Mon May 12 21:29:29 2014 -0700
@@ -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) {
@@ -64,12 +64,12 @@
         this.nodeToBlock = graph.createNodeMap(true);
     }
 
-    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,7 +200,7 @@
     private void connectBlocks() {
         for (Block block : reversePostOrder) {
             List<Block> predecessors = new ArrayList<>(4);
-            double probability = 0;
+            double probability = block.getBeginNode() instanceof StartNode ? 1D : 0D;
             for (Node predNode : block.getBeginNode().cfgPredecessors()) {
                 Block predBlock = nodeToBlock.get(predNode);
                 if (predBlock.getId() >= 0) {
@@ -257,10 +257,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();
@@ -279,10 +279,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);
@@ -293,13 +293,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);
             }
@@ -307,9 +307,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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Mon May 12 21:29:29 2014 -0700
@@ -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/extended/NullCheckNode.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Mon May 12 21:29:29 2014 -0700
@@ -41,7 +41,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/java/ExceptionObjectNode.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon May 12 21:29:29 2014 -0700
@@ -47,7 +47,22 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, 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))));
+
+            loadException.setStateAfter(stateAfter());
+            replaceAtUsages(InputType.Value, loadException);
+            graph().replaceFixedWithFixed(this, entry);
+            entry.graph().addAfterFixed(entry, loadException);
+
+            loadException.lower(tool);
+        }
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Mon May 12 21:29:29 2014 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
+
+    public LoadExceptionObjectNode(Stamp stamp) {
+        super(stamp);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Mon May 12 21:29:29 2014 -0700
@@ -41,7 +41,7 @@
     @Input(InputType.State) private FrameState stateAfter;
 
     public LoweredAtomicReadAndWriteNode(ValueNode object, LocationNode location, ValueNode newValue, BarrierType barrierType, boolean compressible) {
-        super(object, location, newValue.stamp(), barrierType, compressible);
+        super(object, location, newValue.stamp().unrestricted(), barrierType, compressible);
         this.newValue = newValue;
     }
 
@@ -65,7 +65,7 @@
 
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
-        Value result = gen.getLIRGeneratorTool().emitAtomicReadAndWrite(address, gen.operand(newValue));
+        Value result = gen.getLIRGeneratorTool().emitAtomicReadAndWrite(address, gen.operand(getNewValue()));
         gen.setResult(this, result);
     }
 
@@ -81,4 +81,7 @@
         return false;
     }
 
+    public final ValueNode getNewValue() {
+        return newValue;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Mon May 12 21:29:29 2014 -0700
@@ -39,8 +39,6 @@
     // TODO (je) remove and move into the Node
     LIRFrameState state(DeoptimizingNode deopt);
 
-    void emitNullCheck(ValueNode v, DeoptimizingNode deopting);
-
     void emitIf(IfNode i);
 
     void emitConditional(ConditionalNode i);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -185,7 +185,8 @@
                             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);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.common;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -101,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);
@@ -330,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);
@@ -349,6 +351,7 @@
             if (falseConstant.usages().isEmpty()) {
                 graph.removeFloating(falseConstant);
             }
+            super.finished();
         }
 
         private void registerCondition(boolean isTrue, LogicNode condition, ValueNode anchor) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -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,7 +116,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = new IdentityHashMap<>();
+        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) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.phases.common;
 
 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/ProfileCompiledMethodsPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -69,9 +69,9 @@
 
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
         for (Loop<Block> loop : cfg.getLoops()) {
-            double loopProbability = probabilities.applyAsDouble(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);
             }
         }
         // don't put the counter increase directly after the start (problems with OSR)
@@ -79,7 +79,7 @@
         while (current.next() instanceof FixedWithNextNode) {
             current = (FixedWithNextNode) current.next();
         }
-        addSectionCounters(current, Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+        addSectionCounters(current, cfg.getBlocks(), cfg.getLoops(), schedule, probabilities);
 
         if (WITH_INVOKES) {
             for (Node node : graph.getNodes()) {
@@ -96,7 +96,7 @@
                     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.applyAsDouble(start);
         DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -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());
         }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Mon May 12 21:29:29 2014 -0700
@@ -30,7 +30,7 @@
 import com.oracle.graal.graph.spi.CanonicalizerTool;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.phases.graph.PostOrderNodeIterator;
+import com.oracle.graal.phases.graph.SinglePassNodeIterator;
 import com.oracle.graal.phases.tiers.PhaseContext;
 
 import java.util.ArrayList;
@@ -55,12 +55,13 @@
  * </p>
  *
  */
-public abstract class BaseReduction extends PostOrderNodeIterator<State> {
+public abstract class BaseReduction extends SinglePassNodeIterator<State> {
 
-    protected static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved");
-    protected static final DebugMetric metricGuardingPiNodeRemoved = Debug.metric("GuardingPiNodeRemoved");
-    protected static final DebugMetric metricFixedGuardNodeRemoved = Debug.metric("FixedGuardNodeRemoved");
-    protected static final DebugMetric metricMethodResolved = Debug.metric("MethodResolved");
+    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>
@@ -95,6 +96,7 @@
          * 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));
@@ -193,7 +195,7 @@
 
     protected final PostponedDeopts postponedDeopts = new PostponedDeopts();
 
-    protected BaseReduction(FixedNode start, State initialState, PhaseContext context) {
+    protected BaseReduction(StartNode start, State initialState, PhaseContext context) {
         super(start, initialState);
         graph = start.graph();
         trueConstant = LogicConstantNode.tautology(graph);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java	Mon May 12 21:29:29 2014 -0700
@@ -50,7 +50,7 @@
  */
 public abstract class CheckCastReduction extends GuardingPiReduction {
 
-    public CheckCastReduction(FixedNode start, State initialState, PhaseContext context) {
+    public CheckCastReduction(StartNode start, State initialState, PhaseContext context) {
         super(start, initialState, context);
     }
 
@@ -122,7 +122,7 @@
         assert !StampTool.isObjectAlwaysNull(subject) : "Null as per stamp subjects should have been handled above";
 
         // --------- checkCast deemed unsatisfiable by subject-stamp alone ---------
-        if (state.knownNotToConform(subject, toType)) {
+        if (state.knownNotToPassCheckCast(subject, toType)) {
             postponedDeopts.addDeoptBefore(checkCast, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException);
             state.impossiblePath();
             // let FixedGuardNode(false).simplify() prune the dead-code control-path
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Mon May 12 21:29:29 2014 -0700
@@ -22,29 +22,22 @@
  */
 package com.oracle.graal.phases.common.cfs;
 
-import com.oracle.graal.api.meta.ResolvedJavaType;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.NodeBitMap;
-import com.oracle.graal.graph.spi.CanonicalizerTool;
+import 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.FloatingNode;
-import com.oracle.graal.nodes.calc.IsNullNode;
-import com.oracle.graal.nodes.calc.ObjectEqualsNode;
-import com.oracle.graal.nodes.extended.GuardedNode;
-import com.oracle.graal.nodes.extended.GuardingNode;
-import com.oracle.graal.nodes.java.CheckCastNode;
-import com.oracle.graal.nodes.java.InstanceOfNode;
-import com.oracle.graal.nodes.spi.ValueProxy;
-import com.oracle.graal.compiler.common.type.IllegalStamp;
-import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.nodes.type.StampTool;
-import com.oracle.graal.nodes.util.GraphUtil;
-
-import java.util.IdentityHashMap;
-import java.util.Set;
+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>
@@ -65,11 +58,12 @@
  */
 public final class EquationalReasoner {
 
-    private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved");
-    private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved");
-    private static final DebugMetric metricObjectEqualsRemoved = Debug.metric("ObjectEqualsRemoved");
-    private static final DebugMetric metricEquationalReasoning = Debug.metric("EquationalReasoning");
-    private static final DebugMetric metricDowncasting = Debug.metric("Downcasting");
+    private 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;
@@ -87,7 +81,7 @@
      * {@link com.oracle.graal.graph.NodeBitMap NodeBitMap} but in this set instead (those nodes are
      * added after the {@link com.oracle.graal.graph.NodeBitMap} was obtained).
      */
-    final Set<ValueNode> added = java.util.Collections.newSetFromMap(new IdentityHashMap<ValueNode, Boolean>());
+    final Set<ValueNode> added = newNodeIdentitySet();
 
     /**
      * The reduction of a FloatingNode performed by {@link EquationalReasoner EquationalReasoner}
@@ -97,7 +91,7 @@
      * The substitutions tracked in this field become invalid as described in
      * {@link #updateState(com.oracle.graal.phases.common.cfs.State) updateState(State)}
      */
-    private final IdentityHashMap<ValueNode, ValueNode> substs = new IdentityHashMap<>();
+    private final Map<ValueNode, ValueNode> substs = newNodeIdentityMap();
 
     public EquationalReasoner(StructuredGraph graph, CanonicalizerTool tool, LogicConstantNode trueConstant, LogicConstantNode falseConstant, ConstantNode nullConstant) {
         this.graph = graph;
@@ -114,6 +108,7 @@
      */
     public void forceState(State s) {
         state = s;
+        assert state.repOK();
         substs.clear();
         added.clear();
         visited = null;
@@ -235,6 +230,17 @@
             // 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;
         }
@@ -252,25 +258,13 @@
          * Past this point, if we ever want `n` to be deverbosified, it must be looked-up by one of
          * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)`
          */
-        if (v instanceof ValueProxy) {
-            return downcast(v);
-        }
 
-        if (n instanceof FloatingNode) {
-            /*
-             * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not
-             * possible anymore it resorts to calling `downcast()`. Thus it's ok to take the
-             * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be
-             * missed.
-             */
-            return deverbosifyFloatingNode((FloatingNode) n);
-        }
-
-        if (FlowUtil.hasLegalObjectStamp(v)) {
-            return downcast(v);
-        }
-
-        return n;
+        /*
+         * `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);
     }
 
     /**
@@ -334,16 +328,7 @@
         }
         if (changed == null) {
             assert visited.contains(f) || added.contains(f);
-            if (FlowUtil.hasLegalObjectStamp(f)) {
-                /*
-                 * No input has changed doesn't imply there's no witness to refine the
-                 * floating-object value.
-                 */
-                ValueNode d = downcast(f);
-                return d;
-            } else {
-                return f;
-            }
+            return f;
         }
         FlowUtil.inferStampAndCheck(changed);
         added.add(changed);
@@ -441,6 +426,8 @@
                 return baseCaseIsNullNode((IsNullNode) condition);
             } else if (condition instanceof ObjectEqualsNode) {
                 return baseCaseObjectEqualsNode((ObjectEqualsNode) condition);
+            } else if (condition instanceof ShortCircuitOrNode) {
+                return baseCaseShortCircuitOrNode((ShortCircuitOrNode) condition);
             }
         }
         return condition;
@@ -465,6 +452,11 @@
         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;
@@ -477,21 +469,19 @@
      *         performed; otherwise the unmodified argument.
      *
      */
-    private FloatingNode baseCaseIsNullNode(IsNullNode isNull) {
-        ValueNode object = isNull.object();
+    private FloatingNode baseCaseIsNullNode(IsNullNode isNu) {
+        ValueNode object = isNu.object();
         if (!FlowUtil.hasLegalObjectStamp(object)) {
-            return isNull;
+            return isNu;
         }
-        ValueNode scrutinee = GraphUtil.unproxify(isNull.object());
-        GuardingNode evidence = nonTrivialNullAnchor(scrutinee);
-        if (evidence != null) {
+        if (state.isNull(object)) {
             metricNullCheckRemoved.increment();
             return trueConstant;
-        } else if (state.isNonNull(scrutinee)) {
+        } else if (state.isNonNull(object)) {
             metricNullCheckRemoved.increment();
             return falseConstant;
         }
-        return isNull;
+        return isNu;
     }
 
     /**
@@ -515,6 +505,38 @@
     }
 
     /**
+     * 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.
@@ -558,6 +580,7 @@
 
         PiNode untrivialNull = nonTrivialNull(scrutinee);
         if (untrivialNull != null) {
+            metricNullInserted.increment();
             return untrivialNull;
         }
 
@@ -646,24 +669,6 @@
     }
 
     /**
-     * <p>
-     * If the argument is known null due to its stamp, there's no need to have an anchor for that
-     * fact and this method returns null.
-     * </p>
-     *
-     * <p>
-     * Otherwise, if an anchor is found it is returned, null otherwise.
-     * </p>
-     */
-    public GuardingNode nonTrivialNullAnchor(ValueNode object) {
-        assert FlowUtil.hasLegalObjectStamp(object);
-        if (StampTool.isObjectAlwaysNull(object)) {
-            return null;
-        }
-        return state.knownNull.get(GraphUtil.unproxify(object));
-    }
-
-    /**
      *
      * This method returns:
      * <ul>
@@ -680,7 +685,7 @@
      */
     public PiNode nonTrivialNull(ValueNode object) {
         assert FlowUtil.hasLegalObjectStamp(object);
-        GuardingNode anchor = nonTrivialNullAnchor(object);
+        GuardingNode anchor = state.nonTrivialNullAnchor(object);
         if (anchor == null) {
             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/Evidence.java	Mon May 12 21:29:29 2014 -0700
@@ -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);
+
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java	Mon May 12 21:29:29 2014 -0700
@@ -23,9 +23,7 @@
 package com.oracle.graal.phases.common.cfs;
 
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.IsNullNode;
 import com.oracle.graal.nodes.extended.GuardingNode;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.tiers.PhaseContext;
 
 /**
@@ -43,7 +41,7 @@
  */
 public abstract class FixedGuardReduction extends CheckCastReduction {
 
-    public FixedGuardReduction(FixedNode start, State initialState, PhaseContext context) {
+    public FixedGuardReduction(StartNode start, State initialState, PhaseContext context) {
         super(start, initialState, context);
     }
 
@@ -99,118 +97,33 @@
             return;
         }
 
-        /*
-         * Attempt to eliminate the current FixedGuardNode by using another GuardingNode already in
-         * scope and with equivalent condition.
-         */
+        final boolean isTrue = !f.isNegated();
+        final Evidence evidence = state.outcome(isTrue, f.condition());
 
-        GuardingNode existingGuard = f.isNegated() ? state.falseFacts.get(f.condition()) : state.trueFacts.get(f.condition());
-        if (existingGuard != null) {
-            // assert existingGuard instanceof FixedGuardNode;
-            metricFixedGuardNodeRemoved.increment();
-            f.replaceAtUsages(existingGuard.asNode());
-            graph.removeFixed(f);
+        // can't produce evidence, must be information gain
+        if (evidence == null) {
+            state.addFact(isTrue, f.condition(), f);
             return;
         }
 
-        final LogicNode cond = f.condition();
-        final boolean isTrue = !f.isNegated();
-
-        /*
-         * 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.
-         */
-
-        // TODO what about isDependencyTainted
-
-        if (cond instanceof IsNullNode) {
-            final IsNullNode isNullNode = (IsNullNode) cond;
-            if (isTrue) {
-                // grab an anchor attesting nullness
-                final GuardingNode replacement = reasoner.nonTrivialNullAnchor(isNullNode.object());
-                if (replacement != null) {
-                    removeFixedGuardNode(f, replacement);
-                    return;
-                }
-                if (state.isNonNull(isNullNode.object())) {
-                    markFixedGuardNodeAlwaysFails(f);
-                    return;
-                }
-                // can't produce evidence, fall-through to addFact
-            } else {
-                // grab an anchor attesting non-nullness
-                final Witness w = state.typeInfo(isNullNode.object());
-                if (w != null && w.isNonNull()) {
-                    removeFixedGuardNode(f, w.guard());
-                    return;
-                }
-                if (state.isNull(isNullNode.object())) {
-                    markFixedGuardNodeAlwaysFails(f);
-                    return;
-                }
-                // can't produce evidence, fall-through to addFact
-            }
-        } else if (cond instanceof InstanceOfNode) {
-            final InstanceOfNode iOf = (InstanceOfNode) cond;
-            final Witness w = state.typeInfo(iOf.object());
-            if (isTrue) {
-                // grab an anchor attesting instanceof
-                if (w != null) {
-                    if (w.isNonNull() && w.type() != null) {
-                        if (iOf.type().isAssignableFrom(w.type())) {
-                            removeFixedGuardNode(f, w.guard());
-                            return;
-                        }
-                        if (State.knownNotToConform(w.type(), iOf.type())) {
-                            markFixedGuardNodeAlwaysFails(f);
-                            return;
-                        }
-                    }
-                }
-                if (state.isNull(iOf.object())) {
-                    markFixedGuardNodeAlwaysFails(f);
-                    return;
-                }
-                // can't produce evidence, fall-through to addFact
-            } else {
-                // grab an anchor attesting not-instanceof
-                // (1 of 2) attempt determining nullness
-                final GuardingNode nullGuard = reasoner.nonTrivialNullAnchor(iOf.object());
-                if (nullGuard != null) {
-                    removeFixedGuardNode(f, nullGuard);
-                    return;
-                }
-                // (2 of 2) attempt determining known-not-to-conform
-                if (w != null && !w.cluelessAboutType()) {
-                    if (State.knownNotToConform(w.type(), iOf.type())) {
-                        removeFixedGuardNode(f, w.guard());
-                        return;
-                    }
-                }
-                // can't produce evidence, fall-through to addFact
-            }
-        } else if (isTrue && cond instanceof ShortCircuitOrNode) {
-            CastCheckExtractor cce = CastCheckExtractor.extract(cond);
-            if (cce != null && !State.isDependencyTainted(cce.subject, f)) {
-                // grab an anchor attesting check-cast
-                Witness w = state.typeInfo(cce.subject);
-                if (w != null && w.type() != null) {
-                    if (cce.type.isAssignableFrom(w.type())) {
-                        removeFixedGuardNode(f, w.guard());
-                        return;
-                    }
-                    if (State.knownNotToConform(w.type(), cce.type)) {
-                        markFixedGuardNodeAlwaysFails(f);
-                        return;
-                    }
-                }
-            }
-            // can't produce evidence, fall-through to addFact
+        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;
         }
 
-        state.addFact(isTrue, cond, f);
+        assert evidence.isNegative();
+        markFixedGuardNodeAlwaysFails(f);
+
     }
 
     /**
@@ -232,9 +145,7 @@
      * </p>
      */
     private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) {
-        if (replacement == null) {
-            return;
-        }
+        assert replacement != null;
         metricFixedGuardNodeRemoved.increment();
         old.replaceAtUsages(replacement.asNode());
         graph.removeFixed(old);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Mon May 12 21:29:29 2014 -0700
@@ -54,6 +54,14 @@
  * <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>
@@ -76,6 +84,13 @@
  * </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
@@ -83,7 +98,7 @@
  */
 public class FlowSensitiveReduction extends FixedGuardReduction {
 
-    public FlowSensitiveReduction(FixedNode start, State initialState, PhaseContext context) {
+    public FlowSensitiveReduction(StartNode start, State initialState, PhaseContext context) {
         super(start, initialState, context);
     }
 
@@ -150,6 +165,7 @@
         assert !isAliveWithoutUsages(trueConstant);
         assert !isAliveWithoutUsages(falseConstant);
         assert !isAliveWithoutUsages(nullConstant);
+        super.finished();
     }
 
     private static boolean isAliveWithoutUsages(FloatingNode node) {
@@ -217,13 +233,8 @@
                 // `begin` denotes the default case of the TypeSwitchNode
                 return;
             }
-            if (state.knownNotToConform(loadHub.object(), type)) {
-                postponedDeopts.addDeoptAfter(begin, UnreachedCode);
-                state.impossiblePath();
-                return;
-            }
             // it's unwarranted to assume loadHub.object() to be non-null
-            // it also seems unwarranted state.trackCC(loadHub.object(), type, begin);
+            state.trackCC(loadHub.object(), type, begin);
         }
     }
 
@@ -295,9 +306,16 @@
      *
      */
     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)) {
-            Node j = reasoner.deverbosify(i);
+            ValueNode j = (ValueNode) reasoner.deverbosify(i);
+            if (shouldDowncastReceiver) {
+                shouldDowncastReceiver = false;
+                j = reasoner.downcast(j);
+            }
             if (i != j) {
                 assert j != parent;
                 if (changed == null) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Mon May 12 21:29:29 2014 -0700
@@ -47,7 +47,7 @@
  */
 public abstract class GuardingPiReduction extends BaseReduction {
 
-    public GuardingPiReduction(FixedNode start, State initialState, PhaseContext context) {
+    public GuardingPiReduction(StartNode start, State initialState, PhaseContext context) {
         super(start, initialState, context);
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Mon May 12 21:29:29 2014 -0700
@@ -22,24 +22,22 @@
  */
 package com.oracle.graal.phases.common.cfs;
 
-import com.oracle.graal.api.meta.Kind;
-import com.oracle.graal.api.meta.ResolvedJavaType;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
+import 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.IsNullNode;
-import com.oracle.graal.nodes.calc.ObjectEqualsNode;
-import com.oracle.graal.nodes.extended.GuardedNode;
-import com.oracle.graal.nodes.extended.GuardingNode;
-import com.oracle.graal.nodes.java.InstanceOfNode;
-import com.oracle.graal.nodes.spi.ValueProxy;
-import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.nodes.type.StampTool;
-import com.oracle.graal.nodes.util.GraphUtil;
-import com.oracle.graal.phases.graph.MergeableState;
-
-import java.lang.reflect.Modifier;
-import java.util.*;
+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
@@ -50,10 +48,10 @@
  */
 public final class State extends MergeableState<State> implements Cloneable {
 
-    private static final DebugMetric metricTypeRegistered = Debug.metric("TypeRegistered");
-    private static final DebugMetric metricNullnessRegistered = Debug.metric("NullnessRegistered");
-    private static final DebugMetric metricObjectEqualsRegistered = Debug.metric("ObjectEqualsRegistered");
-    private static final DebugMetric metricImpossiblePathDetected = Debug.metric("ImpossiblePathDetected");
+    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>
@@ -99,46 +97,47 @@
 
     /**
      * <p>
-     * This map semantically tracks "facts" (ie, properties valid for the program-point the state
-     * refers to) as opposed to floating-guard-dependent properties. The
-     * {@link com.oracle.graal.nodes.extended.GuardingNode} being tracked comes handy at
-     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)}
-     * .
+     * This map tracks properties about reference-values, ie combinations of: definitely-null,
+     * known-to-be-non-null, seen-type.
      * </p>
      *
      * <p>
-     * On a related note, {@link #typeRefinements} also captures information the way
-     * {@link #trueFacts} and {@link #falseFacts} do, including "witnessing" guards. Why not just
-     * standardize on one of them, and drop the other? Because the {@link #typeRefinements} eagerly
-     * aggregates information for easier querying afterwards, e.g. when producing a "downcasted"
-     * value (which involves building a {@link com.oracle.graal.nodes.PiNode}, see
-     * {@link EquationalReasoner#downcast(com.oracle.graal.nodes.ValueNode) downcast()}
+     * 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 IdentityHashMap<ValueNode, Witness> typeRefinements;
+    private Map<ValueNode, Witness> typeRefinements;
 
-    IdentityHashMap<ValueNode, GuardingNode> knownNull;
-    IdentityHashMap<LogicNode, GuardingNode> trueFacts;
-    IdentityHashMap<LogicNode, GuardingNode> falseFacts;
+    Map<LogicNode, GuardingNode> trueFacts;
+    Map<LogicNode, GuardingNode> falseFacts;
 
     public State() {
-        this.typeRefinements = new IdentityHashMap<>();
-        this.knownNull = new IdentityHashMap<>();
-        this.trueFacts = new IdentityHashMap<>();
-        this.falseFacts = new IdentityHashMap<>();
+        this.typeRefinements = newNodeIdentityMap();
+        this.trueFacts = newNodeIdentityMap();
+        this.falseFacts = newNodeIdentityMap();
     }
 
     public State(State other) {
         this.isUnreachable = other.isUnreachable;
         this.versionNr = other.versionNr;
-        this.typeRefinements = new IdentityHashMap<>();
+        this.typeRefinements = newNodeIdentityMap();
         for (Map.Entry<ValueNode, Witness> entry : other.typeRefinements.entrySet()) {
             this.typeRefinements.put(entry.getKey(), new Witness(entry.getValue()));
         }
-        this.knownNull = new IdentityHashMap<>(other.knownNull);
-        this.trueFacts = new IdentityHashMap<>(other.trueFacts);
-        this.falseFacts = new IdentityHashMap<>(other.falseFacts);
+        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;
     }
 
     /**
@@ -155,8 +154,8 @@
         return result;
     }
 
-    private IdentityHashMap<ValueNode, Witness> mergeKnownTypes(MergeNode merge, ArrayList<State> withReachableStates) {
-        IdentityHashMap<ValueNode, Witness> newKnownTypes = new IdentityHashMap<>();
+    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();
@@ -179,31 +178,6 @@
         return newKnownTypes;
     }
 
-    private IdentityHashMap<ValueNode, GuardingNode> mergeKnownNull(MergeNode merge, ArrayList<State> withReachableStates) {
-        // newKnownNull starts empty
-        IdentityHashMap<ValueNode, GuardingNode> newKnownNull = new IdentityHashMap<>();
-        for (Map.Entry<ValueNode, GuardingNode> entry : knownNull.entrySet()) {
-            ValueNode key = entry.getKey();
-            GuardingNode newGN = entry.getValue();
-            boolean missing = false;
-
-            for (State other : withReachableStates) {
-                GuardingNode otherGuard = other.knownNull.get(key);
-                if (otherGuard == null) {
-                    missing = true;
-                    break;
-                }
-                if (otherGuard != newGN) {
-                    newGN = merge;
-                }
-            }
-            if (!missing) {
-                newKnownNull.put(key, newGN);
-            }
-        }
-        return newKnownNull;
-    }
-
     /**
      * <p>
      * This method handles phis, by adding to the resulting state any information that can be gained
@@ -221,7 +195,7 @@
      * when merging type-witnesses and known-null maps.
      * </p>
      */
-    private void mergePhis(MergeNode merge, List<State> withStates, IdentityHashMap<ValueNode, Witness> newKnownPhiTypes, IdentityHashMap<ValueNode, GuardingNode> newKnownNullPhis) {
+    private void mergePhis(MergeNode merge, List<State> withStates, Map<ValueNode, Witness> newKnownPhiTypes) {
 
         if (merge instanceof LoopBeginNode) {
             return;
@@ -244,20 +218,21 @@
                 ObjectStamp phiStamp = (ObjectStamp) phi.stamp();
                 ObjectStamp nonPollutedStamp = (ObjectStamp) StampTool.meet(reachingValues);
                 Witness w = new Witness(nonPollutedStamp, merge);
-                if (FlowUtil.isMorePrecise(w.type(), phiStamp.type())) {
+                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 regarding nullness
+                    // precision gain: non-null
                     newKnownPhiTypes.put(phi, w);
                     // confirm no precision loss regarding type
                     assert !FlowUtil.isMorePrecise(phiStamp.type(), w.type());
                 }
-                if (nonPollutedStamp.alwaysNull()) {
-                    newKnownNullPhis.put(phi, merge);
-                }
             }
         }
 
@@ -284,27 +259,27 @@
 
         if (isUnreachable) {
             typeRefinements.clear();
-            knownNull.clear();
             trueFacts.clear();
             falseFacts.clear();
             return true;
         }
 
         // may also get updated in a moment, during processing of phi nodes.
-        IdentityHashMap<ValueNode, Witness> newKnownTypes = mergeKnownTypes(merge, withReachableStates);
+        Map<ValueNode, Witness> newKnownTypes = mergeKnownTypes(merge, withReachableStates);
         // may also get updated in a moment, during processing of phi nodes.
-        IdentityHashMap<ValueNode, GuardingNode> newKnownNull = mergeKnownNull(merge, withReachableStates);
-        mergePhis(merge, withStates, newKnownTypes, newKnownNull);
+        mergePhis(merge, withStates, newKnownTypes);
         this.typeRefinements = newKnownTypes;
-        this.knownNull = newKnownNull;
 
         this.trueFacts = mergeTrueFacts(withReachableStates, merge);
         this.falseFacts = mergeFalseFacts(withReachableStates, merge);
+
+        assert repOK();
+
         return true;
     }
 
-    private IdentityHashMap<LogicNode, GuardingNode> mergeTrueFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
-        IdentityHashMap<LogicNode, GuardingNode> newTrueConditions = new IdentityHashMap<>();
+    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();
@@ -326,8 +301,8 @@
         return newTrueConditions;
     }
 
-    private IdentityHashMap<LogicNode, GuardingNode> mergeFalseFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
-        IdentityHashMap<LogicNode, GuardingNode> newFalseConditions = new IdentityHashMap<>();
+    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();
@@ -362,7 +337,12 @@
      */
     public boolean isNull(ValueNode object) {
         assert FlowUtil.hasLegalObjectStamp(object);
-        return StampTool.isObjectAlwaysNull(object) || knownNull.containsKey(GraphUtil.unproxify(object));
+        if (StampTool.isObjectAlwaysNull(object)) {
+            return true;
+        }
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+        Witness w = typeRefinements.get(scrutinee);
+        return (w != null) && w.isNull();
     }
 
     /**
@@ -393,7 +373,8 @@
     }
 
     /**
-     * @return true iff the argument is known to stand for an object conforming to the given type.
+     * @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);
@@ -415,14 +396,20 @@
     }
 
     /**
-     * @return true iff the argument is known to stand for an object that definitely does not
-     *         conform to the given type.
+     * @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 knownNotToConform(ValueNode object, ResolvedJavaType to) {
+    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);
@@ -437,6 +424,34 @@
         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
     /**
      *   \   |     |     |     |
@@ -526,6 +541,7 @@
         Witness w = getOrElseAddTypeInfo(object);
         if (w.trackNN(anchor)) {
             versionNr++;
+            assert repOK();
             return true;
         }
         return false;
@@ -558,6 +574,7 @@
         if (w.trackCC(observed, anchor)) {
             versionNr++;
             metricTypeRegistered.increment();
+            assert repOK();
             return true;
         }
         return false;
@@ -584,6 +601,7 @@
         if (w.trackIO(observed, anchor)) {
             versionNr++;
             metricTypeRegistered.increment();
+            assert repOK();
             return true;
         }
         return false;
@@ -600,7 +618,7 @@
      * </p>
      *
      */
-    private void addFactPrimordial(LogicNode condition, IdentityHashMap<LogicNode, GuardingNode> to, GuardingNode anchor) {
+    private void addFactPrimordial(LogicNode condition, Map<LogicNode, GuardingNode> to, GuardingNode anchor) {
         assert condition != null;
         if (!to.containsKey(condition)) {
             versionNr++;
@@ -665,6 +683,7 @@
         } else {
             addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
         }
+        assert repOK();
     }
 
     /**
@@ -675,7 +694,7 @@
     private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) {
         ValueNode object = instanceOf.object();
         if (isTrue) {
-            if (knownNotToConform(object, instanceOf.type())) {
+            if (knownNotToPassInstanceOf(object, instanceOf.type())) {
                 impossiblePath();
                 return;
             }
@@ -757,25 +776,27 @@
             return;
         }
         assert anchor instanceof FixedNode;
-        ValueNode original = GraphUtil.unproxify(value);
-        boolean wasNull = isNull(original);
-        boolean wasNonNull = isNonNull(original);
+        ValueNode scrutinee = GraphUtil.unproxify(value);
+        boolean wasNull = isNull(scrutinee);
+        boolean wasNonNull = isNonNull(scrutinee);
         if (isNull) {
             if (wasNonNull) {
                 impossiblePath();
             } else {
                 metricNullnessRegistered.increment();
                 versionNr++;
-                knownNull.put(original, anchor);
+                Witness w = getOrElseAddTypeInfo(scrutinee);
+                w.trackDN(anchor);
             }
         } else {
             if (wasNull) {
                 impossiblePath();
             } else {
                 metricNullnessRegistered.increment();
-                trackNN(original, anchor);
+                trackNN(scrutinee, anchor);
             }
         }
+        assert repOK();
     }
 
     /**
@@ -808,9 +829,187 @@
         versionNr = 0;
         isUnreachable = false;
         typeRefinements.clear();
-        knownNull.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;
+    }
+
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java	Mon May 12 21:29:29 2014 -0700
@@ -86,7 +86,8 @@
         CLUELESS,
         NN,
         CC,
-        IO
+        IO,
+        DN
     }
 
     private boolean atNonNull() {
@@ -101,6 +102,10 @@
         return level == LEVEL.IO;
     }
 
+    private boolean atDefinitelyNull() {
+        return level == LEVEL.DN;
+    }
+
     private void transition(LEVEL to, GuardingNode newAnchor) {
         this.level = to;
         this.gn = newAnchor;
@@ -122,37 +127,41 @@
     public Witness(ObjectStamp stamp, GuardingNode anchor) {
         assert stamp.isLegal();
         assert anchor != null;
-        boolean isNonIface = (stamp.type() != null && !stamp.type().isInterface());
-        if (stamp.nonNull()) {
-            if (isNonIface) {
-                seen = stamp.type();
-                transition(LEVEL.IO, anchor);
+        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 {
-                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();
+                if (isNonIface) {
+                    seen = stamp.type();
+                    transition(LEVEL.CC, anchor);
+                } else {
+                    seen = null;
+                    transition(LEVEL.CLUELESS, null);
+                    assert clueless();
+                }
             }
         }
         assert repOK();
     }
 
-    /**
-     * Type-witnesses aren't tracked for known-to-be-null. Therefore, although method
-     * {@link #isNonNull() isNonNull()} can be found in this class there's on purpose no companion
-     * <code>isNull()</code> .
-     */
     public boolean isNonNull() {
         return atNonNull() || atInstanceOf();
     }
 
+    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).
@@ -163,7 +172,7 @@
 
     public ObjectStamp asStamp() {
         boolean isKnownExact = (seen != null && seen.equals(seen.asExactType()));
-        return new ObjectStamp(seen, isKnownExact, isNonNull(), false);
+        return new ObjectStamp(seen, isKnownExact, isNonNull(), isNull());
     }
 
     private LEVEL level = LEVEL.CLUELESS;
@@ -219,15 +228,14 @@
             assert level == LEVEL.CLUELESS;
             return true;
         }
-        if (level == LEVEL.NN) {
+        if (atNonNull() || atDefinitelyNull()) {
             assert seen == null;
         }
         if (seen != null) {
             assert !seen.isInterface();
             assert !seen.isPrimitive();
         }
-        boolean gnOK = gn instanceof BeginNode || gn instanceof LoopExitNode || gn instanceof MergeNode || gn instanceof FixedGuardNode;
-        assert gnOK;
+        assert gn instanceof BeginNode || gn instanceof LoopExitNode || gn instanceof MergeNode || gn instanceof FixedGuardNode;
         return true;
     }
 
@@ -235,7 +243,7 @@
      * Helper method for readability in complex conditions.
      */
     public boolean clueless() {
-        return cluelessAboutType() && cluelessAboutNonNullness();
+        return cluelessAboutType() && cluelessAboutNullity();
     }
 
     /**
@@ -249,8 +257,8 @@
     /**
      * Helper method for readability in complex conditions.
      */
-    public boolean cluelessAboutNonNullness() {
-        return !atNonNull() && !atInstanceOf();
+    public boolean cluelessAboutNullity() {
+        return !atNonNull() && !atInstanceOf() && !atDefinitelyNull();
     }
 
     /**
@@ -276,6 +284,9 @@
      * @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;
@@ -294,6 +305,7 @@
      */
     public boolean trackNN(GuardingNode anchor) {
         assert repOK();
+        assert !isNull();
         try {
             if (atInstanceOf()) {
                 return false;
@@ -313,6 +325,29 @@
     }
 
     /**
+     * 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)
@@ -366,6 +401,7 @@
      */
     public boolean trackIO(ResolvedJavaType observed, GuardingNode anchor) {
         assert repOK();
+        assert !isNull();
         try {
             boolean gotMorePreciseType = refinesSeenType(observed);
             if (!atInstanceOf() || gotMorePreciseType) {
@@ -405,12 +441,62 @@
             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);
 
-        // preserve guarding node only if matches other, otherwise settle on `merge`
-        final GuardingNode resultGuard = guard() == that.guard() ? guard() : merge;
-
         /*
          * guarantee on (both conformance and non-nullness) required from each input in order for
          * the result to be able to offer such guarantee
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/ComputeInliningRelevance.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/ComputeInliningRelevance.java	Mon May 12 21:29:29 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.common.inlining;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 import java.util.function.*;
 
@@ -46,7 +48,7 @@
      * 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 IdentityHashMap<FixedNode, Double> nodeRelevances;
+    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.
@@ -69,10 +71,10 @@
             rootScope = new Scope(graph.start(), null);
         } else {
             if (nodeRelevances == null) {
-                nodeRelevances = new IdentityHashMap<>(EXPECTED_MIN_INVOKE_COUNT + graph.getNodeCount() / EXPECTED_INVOKE_RATIO);
+                nodeRelevances = newNodeIdentityMap(EXPECTED_MIN_INVOKE_COUNT + graph.getNodeCount() / EXPECTED_INVOKE_RATIO);
             }
             NodeWorkList workList = graph.createNodeWorkList();
-            IdentityHashMap<LoopBeginNode, Scope> loops = new IdentityHashMap<>(EXPECTED_LOOP_COUNT);
+            Map<LoopBeginNode, Scope> loops = newNodeIdentityMap(EXPECTED_LOOP_COUNT);
 
             loops.put(null, new Scope(graph.start(), null));
             for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) {
@@ -97,7 +99,7 @@
      * 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, IdentityHashMap<LoopBeginNode, Scope> loops) {
+    private Scope createLoopScope(LoopBeginNode loopBegin, Map<LoopBeginNode, Scope> loops) {
         Scope scope = loops.get(loopBegin);
         if (scope == null) {
             final Scope parent;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningIterator.java	Mon May 12 21:29:29 2014 -0700
@@ -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;
+
+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()}
+ */
+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;
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Mon May 12 21:29:29 2014 -0700
@@ -477,106 +477,13 @@
         }
     }
 
-    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);
+        private static final GraphInfo DummyGraphInfo = new GraphInfo(null, 1.0, 1.0);
 
         /**
          * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
@@ -601,10 +508,7 @@
 
         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));
+            graphQueue.push(new GraphInfo(graph, probability, relevance));
             assert graphQueue.size() <= maxGraphs;
         }
 
@@ -712,16 +616,6 @@
             }
             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 {
@@ -803,13 +697,19 @@
         private final ToDoubleFunction<FixedNode> probabilities;
         private final ComputeInliningRelevance computeInliningRelevance;
 
-        public GraphInfo(StructuredGraph graph, LinkedList<Invoke> invokes, double probability, double relevance) {
+        public GraphInfo(StructuredGraph graph, double probability, double relevance) {
             this.graph = graph;
-            this.remainingInvokes = invokes;
+            if (graph == null) {
+                this.remainingInvokes = new LinkedList<>();
+            } else {
+                LinkedList<Invoke> invokes = new InliningIterator(graph).apply();
+                assert invokes.size() == count(graph.getInvokes());
+                this.remainingInvokes = invokes;
+            }
             this.probability = probability;
             this.relevance = relevance;
 
-            if (graph != null && (graph.hasNode(InvokeNode.class) || graph.hasNode(InvokeWithExceptionNode.class))) {
+            if (graph != null && !remainingInvokes.isEmpty()) {
                 probabilities = new FixedNodeProbabilityCache();
                 computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
                 computeProbabilities();
@@ -819,6 +719,16 @@
             }
         }
 
+        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.
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon May 12 21:29:29 2014 -0700
@@ -26,6 +26,7 @@
 
 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.nodes.*;
 
@@ -40,6 +41,7 @@
 
     private final DebugTimer phaseTimer;
     private final DebugMetric phaseMetric;
+    private final DebugMemUseTracker phaseMemUseTracker;
 
     private static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
 
@@ -51,6 +53,7 @@
     protected BasePhase() {
         phaseTimer = Debug.timer("PhaseTime_%s", getClass());
         phaseMetric = Debug.metric("PhaseCount_%s", getClass());
+        phaseMemUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
     }
 
     protected BasePhase(String name) {
@@ -58,6 +61,7 @@
         this.name = name;
         phaseTimer = Debug.timer("PhaseTime_%s", getClass());
         phaseMetric = Debug.metric("PhaseCount_%s", getClass());
+        phaseMemUseTracker = Debug.memUseTracker("PhaseMemUse_%s", getClass());
     }
 
     protected CharSequence getDetailedName() {
@@ -69,7 +73,7 @@
     }
 
     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 = phaseTimer.start(); Scope s = Debug.scope(getClass(), this); Closeable c = phaseMemUseTracker.start()) {
             BasePhase.this.run(graph, context);
             phaseMetric.increment();
             if (dumpGraph && Debug.isDumpEnabled()) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Mon May 12 21:29:29 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.graph;
 
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
+
 import java.util.*;
 import java.util.function.*;
 
@@ -37,7 +39,7 @@
 
     private static final DebugMetric metricComputeNodeProbability = Debug.metric("ComputeNodeProbability");
 
-    private final IdentityHashMap<FixedNode, Double> cache = new IdentityHashMap<>();
+    private final Map<FixedNode, Double> cache = newIdentityMap();
 
     public double applyAsDouble(FixedNode node) {
         metricComputeNodeProbability.increment();
@@ -64,7 +66,7 @@
         double probability;
         if (current.predecessor() == null) {
             if (current instanceof MergeNode) {
-                probability = ((MergeNode) current).forwardEnds().stream().mapToDouble(end -> applyAsDouble(end)).sum();
+                probability = ((MergeNode) current).forwardEnds().stream().mapToDouble(this::applyAsDouble).sum();
                 if (current instanceof LoopBeginNode) {
                     probability *= ((LoopBeginNode) current).loopFrequency();
                 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Mon May 12 21:29:29 2014 -0700
@@ -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.*;
@@ -54,16 +56,16 @@
     }
 
     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();
         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());
             StateT exitState = blockEndStates.get(loopExit.getBeginNode());
@@ -77,12 +79,12 @@
         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;
@@ -103,14 +105,14 @@
                         } 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);
                             }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Mon May 12 21:29:29 2014 -0700
@@ -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,8 @@
 
     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 = newNodeIdentityMap(4);
+        public final Map<LoopExitNode, StateT> exitStates = newNodeIdentityMap(2);
     }
 
     public abstract static class NodeIteratorClosure<StateT> {
@@ -76,13 +78,14 @@
         return info;
     }
 
-    public static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState) {
-        return apply(closure, start, initialState, null);
+    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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java	Mon May 12 21:29:29 2014 -0700
@@ -0,0 +1,349 @@
+/*
+ * 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.QElem
+     */
+    private final Deque<QElem<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>the successor of a control-split node, in which case the pre-state of the successor in
+     * question is also stored in the item, see {@link #nextQueuedNode()}</li>
+     * </ul>
+     * </p>
+     */
+    private static class QElem<U> {
+        private final FixedNode node;
+        private final U preState;
+
+        private QElem(FixedNode node, U preState) {
+            this.node = node;
+            this.preState = preState;
+            assert repOK();
+        }
+
+        private boolean repOK() {
+            return (node instanceof MergeNode && preState == null) || (node instanceof BeginNode && preState != 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();
+    }
+
+    private void queueSuccessors(FixedNode x) {
+        for (Node node : x.successors()) {
+            if (node != null) {
+                nodeQueue.addFirst(new QElem<>((BeginNode) node, state));
+            }
+        }
+    }
+
+    /**
+     * 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;
+        }
+        QElem<T> elem = nodeQueue.removeFirst();
+        if (elem.node instanceof MergeNode) {
+            MergeNode merge = (MergeNode) elem.node;
+            state = pruneEntry(merge.forwardEndAt(0)).clone();
+            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 = (BeginNode) elem.node;
+            assert begin.predecessor() != null;
+            state = elem.preState.clone();
+            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 QElem<>(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);
+        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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon May 12 21:29:29 2014 -0700
@@ -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));
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/ArraySet.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/ArraySet.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Mon May 12 21:29:29 2014 -0700
@@ -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.*;
@@ -136,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>() {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Mon May 12 21:29:29 2014 -0700
@@ -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);
     }
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Mon May 12 21:29:29 2014 -0700
@@ -28,12 +28,18 @@
 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.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon May 12 21:29:29 2014 -0700
@@ -73,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) {
@@ -103,7 +103,7 @@
     /**
      * 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
@@ -151,7 +151,7 @@
 
     /**
      * 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}
@@ -186,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();
     }
 
     /**
@@ -240,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/SnippetTemplate.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon May 12 21:29:29 2014 -0700
@@ -24,9 +24,10 @@
 
 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 java.util.FormattableFlags.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -494,7 +495,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();
@@ -642,11 +643,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;
 
@@ -655,9 +651,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);
@@ -665,6 +662,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;
@@ -790,8 +792,8 @@
      *
      * @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];
@@ -1008,7 +1010,7 @@
         }
 
         @Override
-        public void replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
+        public boolean replaceLastLocationAccess(MemoryNode oldNode, MemoryNode newNode) {
             throw GraalInternalError.shouldNotReachHere();
         }
     }
@@ -1031,7 +1033,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());
@@ -1184,7 +1186,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());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalJUnitCore.java	Mon May 12 21:29:29 2014 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.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;
+        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 {
+                    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);
+        }
+        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	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 21:29:29 2014 -0700
@@ -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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTextListener.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 21:29:29 2014 -0700
@@ -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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/TimingDecorator.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Mon May 12 21:29:29 2014 -0700
@@ -42,8 +42,6 @@
 
     protected abstract int getNotifyIndex();
 
-    protected abstract int getCallTargetIndex();
-
     protected abstract int getFrameIndex();
 
     @SlowPath
@@ -86,15 +84,7 @@
 
     public abstract CallTarget getCallTarget();
 
-    public abstract CallTarget getTargetCallTarget();
-
-    public Node getCallNode() {
-        Object receiver = stackFrame.getLocal(getNotifyIndex());
-        if (receiver instanceof DirectCallNode || receiver instanceof IndirectCallNode) {
-            return (Node) receiver;
-        }
-        return null;
-    }
+    public abstract Node getCallNode();
 
     /**
      * This class represents a frame that is taken from the
@@ -111,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) {
@@ -124,11 +113,6 @@
         }
 
         @Override
-        protected int getCallTargetIndex() {
-            return CALL_TARGET_INDEX;
-        }
-
-        @Override
         protected int getFrameIndex() {
             return FRAME_INDEX;
         }
@@ -139,8 +123,12 @@
         }
 
         @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;
         }
     }
 
@@ -181,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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon May 12 21:29:29 2014 -0700
@@ -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.*;
@@ -54,7 +55,6 @@
 import com.oracle.truffle.api.*;
 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()));
         }
     }
 
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon May 12 21:29:29 2014 -0700
@@ -138,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/PartialEvaluator.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon May 12 21:29:29 2014 -0700
@@ -297,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.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Mon May 12 21:29:29 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.virtual.phases.ea;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.graph.util.CollectionsAccess.*;
 
 import java.util.*;
 
@@ -45,8 +46,8 @@
 
     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;
 
@@ -155,7 +156,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 +165,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 +173,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/PartialEscapeBlockState.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon May 12 21:29:29 2014 -0700
@@ -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,7 +35,6 @@
 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.virtual.*;
@@ -55,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
@@ -84,10 +84,6 @@
         this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, assumptions, this);
     }
 
-    public Map<Invoke, Double> getHints() {
-        return hints;
-    }
-
     /**
      * @return true if the node was deleted, false otherwise
      */
@@ -116,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);
                 }
@@ -278,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);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Mon May 12 21:29:29 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.graal.virtual.phases.ea;
 
 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.truffle.api/src/com/oracle/truffle/api/Truffle.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java	Mon May 12 21:29:29 2014 -0700
@@ -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/impl/DefaultCallTarget.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java	Mon May 12 21:29:29 2014 -0700
@@ -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/DefaultTruffleRuntime.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Mon May 12 21:29:29 2014 -0700
@@ -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();
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Mon May 12 20:17:25 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Mon May 12 21:29:29 2014 -0700
@@ -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/mx/JUnitWrapper.java	Mon May 12 20:17:25 2014 -0700
+++ b/mx/JUnitWrapper.java	Mon May 12 21:29:29 2014 -0700
@@ -27,8 +27,7 @@
  * linux [depending on the settings]: ~2097k)
  * see http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx
  */
-
-import org.junit.runner.*;
+import com.oracle.graal.test.*;
 import java.io.*;
 import java.util.*;
 
@@ -44,6 +43,10 @@
             System.exit(1);
         }
         ArrayList<String> tests = new ArrayList<String>(1000);
+        // add JUnit command line arguments
+        for (int i = 1; i < args.length; i++) {
+            tests.add(args[i]);
+        }
         BufferedReader br = null;
         try {
             br = new BufferedReader(new FileReader(args[0]));
@@ -72,6 +75,6 @@
         } else {
             System.out.printf("executing junit tests now... (%d test classes)\n", strargs.length);
         }
-        JUnitCore.main(strargs);
+        GraalJUnitCore.main(strargs);
     }
 }
--- a/mx/mx_graal.py	Mon May 12 20:17:25 2014 -0700
+++ b/mx/mx_graal.py	Mon May 12 21:29:29 2014 -0700
@@ -26,7 +26,7 @@
 #
 # ----------------------------------------------------------------------------------------------------
 
-import os, sys, shutil, zipfile, tarfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO, socket
+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
@@ -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)
 
@@ -904,7 +912,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)
@@ -939,6 +947,9 @@
     if 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')
         for c in classes:
@@ -946,7 +957,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):
     mxdir = dirname(__file__)
     name = 'JUnitWrapper'
     javaSource = join(mxdir, name + '.java')
@@ -955,10 +966,19 @@
     if testfile is None:
         (_, testfile) = tempfile.mkstemp(".testclasses", "graal")
         os.close(_)
+    corecp = mx.classpath(['com.oracle.graal.test'])
+
+    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')
+
 
     def harness(projectscp, vmArgs):
-        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:
@@ -968,12 +988,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)
@@ -981,8 +1001,11 @@
 _unittestHelpSuffix = """
     Unittest options:
 
-      --whitelist            run only testcases which are included
+      --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
 
     To avoid conflicts with VM options '--' can be used as delimiter.
 
@@ -1020,6 +1043,9 @@
           epilog=_unittestHelpSuffix,
         )
     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>')
 
     ut_args = []
     delimiter = False
@@ -1046,7 +1072,7 @@
         except IOError:
             mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
 
-    _unittest(args, ['@Test', '@Parameters'], whitelist=whitelist)
+    _unittest(args, ['@Test', '@Parameters'], whitelist=whitelist, verbose=parsed_args.verbose, enable_timing=parsed_args.enable_timing, regex=parsed_args.regex)
 
 def shortunittest(args):
     """alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}"""
@@ -1158,12 +1184,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(['--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler'])
+        unittest(['--enable-timing', '--verbose', '--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler'])
         tasks.append(t.stop())
 
     for vmbuild in ['fastdebug', 'product']:
@@ -1509,7 +1535,7 @@
                     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, excludedDependencies=[])
         d.make_archive()
         cmd = ['mvn', 'install:install-file', '-DgroupId=' + groupId, '-DartifactId=' + artifactId,
                '-Dversion=1.0-SNAPSHOT', '-Dpackaging=jar', '-Dfile=' + d.path]
@@ -1596,8 +1622,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:
@@ -1625,7 +1654,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:"):
@@ -1781,20 +1811,6 @@
     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', '@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', '@Parameters'], "truffle.jar:")
-
-
 def isGraalEnabled(vm):
     return vm != 'original' and not vm.endswith('nograal')
 
@@ -2024,8 +2040,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'])
--- a/mx/projects	Mon May 12 20:17:25 2014 -0700
+++ b/mx/projects	Mon May 12 21:29:29 2014 -0700
@@ -26,9 +26,11 @@
 
 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
@@ -44,12 +46,16 @@
 
 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.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
@@ -58,6 +64,7 @@
 
 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@sourcesPath=graal.src.zip
@@ -69,7 +76,25 @@
 com.oracle.graal.hotspot.sparc,\
 com.oracle.graal.hotspot,\
 com.oracle.graal.hotspot.hsail
-distribution@GRAAL@excludeLibs=FINDBUGS
+distribution@GRAAL@exclude=FINDBUGS
+
+distribution@TRUFFLE@path=truffle.jar
+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@sourcesPath=truffle-dsl-processor-sources.jar
+distribution@TRUFFLE-DSL-PROCESSOR@dependencies=\
+com.oracle.truffle.dsl.processor
+distribution@TRUFFLE-DSL-PROCESSOR@distDependency=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
@@ -253,7 +278,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
 
@@ -422,7 +447,7 @@
 # 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
+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
--- a/mxtool/mx.py	Mon May 12 20:17:25 2014 -0700
+++ b/mxtool/mx.py	Mon May 12 21:29:29 2014 -0700
@@ -62,7 +62,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, excludedDependencies, distDependency):
         self.suite = suite
         self.name = name
         self.path = path.replace('/', os.sep)
@@ -70,13 +70,14 @@
         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.excludedDependencies = excludedDependencies
+        self.distDependency = distDependency
 
     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):
@@ -124,6 +125,11 @@
                                 srcArc.zf.writestr(arcname, lp.read(arcname))
                 else:
                     p = dep
+
+                    if self.distDependency and p in _dists[self.distDependency].sorted_deps():
+                        logv("Excluding {0} from {1} because it's provided by the dependency {2}".format(p.name, self.path, self.distDependency))
+                        continue
+
                     # skip a  Java project if its Java compliance level is "higher" than the configured JDK
                     jdk = java(p.javaCompliance)
                     if not jdk:
@@ -748,8 +754,9 @@
             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)
+            exclDeps = pop_list(attrs, 'exclude')
+            distDep = attrs.pop('distDependency', None)
+            d = Distribution(self, name, path, sourcesPath, deps, exclDeps, distDep)
             d.__dict__.update(attrs)
             self.dists.append(d)
 
@@ -1300,8 +1307,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':
@@ -1340,8 +1360,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
@@ -1359,7 +1378,7 @@
         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)
         if callable(out):
             t = Thread(target=redirect, args=(p.stdout, out))
             t.daemon = True  # thread dies with the program
@@ -1382,7 +1401,7 @@
     except KeyboardInterrupt:
         abort(1)
     finally:
-        _currentSubprocess = (None, None)
+        _removeSubprocess(sub)
 
     if retcode and nonZeroIsFatal:
         if _opts.verbose:
@@ -1663,21 +1682,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):
     """
@@ -1692,12 +1710,14 @@
 
     # 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)
+    for p, args in _currentSubprocesses:
+        try:
+            if get_os() == 'windows':
+                p.terminate()
+            else:
+                _kill_process_group(p.pid, signal.SIGKILL)
+        except BaseException as e:
+            log('error while killing subprocess {} "{}": {}'.format(p.pid, ' '.join(args), e))
 
     raise SystemExit(codeOrMessage)
 
@@ -1798,7 +1818,7 @@
     return get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar'))
 
 class JavaCompileTask:
-    def __init__(self, args, proj, reason, javafilelist, jdk, outputDir, deps):
+    def __init__(self, args, proj, reason, javafilelist, jdk, outputDir, jdtJar, deps):
         self.proj = proj
         self.reason = reason
         self.javafilelist = javafilelist
@@ -1806,6 +1826,7 @@
         self.jdk = jdk
         self.outputDir = outputDir
         self.done = False
+        self.jdtJar = jdtJar
         self.args = args
 
     def __str__(self):
@@ -1840,20 +1861,8 @@
         cp = classpath(self.proj.name, includeSelf=True)
         toBeDeleted = [argfileName]
 
-        jdtJar = None
-        if not args.javac and args.jdt is not None:
-            if not args.jdt.endswith('.jar'):
-                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:
-                    # 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)
-
         try:
-            if not jdtJar:
+            if not self.jdtJar:
                 mainJava = java()
                 if not args.error_prone:
                     self.logCompilation('javac')
@@ -1878,7 +1887,7 @@
             else:
                 self.logCompilation('JDT')
 
-                jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
+                jdtVmArgs = ['-Xmx1g', '-jar', self.jdtJar]
 
                 jdtArgs = ['-' + compliance,
                          '-cp', cp, '-g', '-enableJavadoc',
@@ -1946,12 +1955,23 @@
     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='...')
 
     args = parser.parse_args(args)
 
+    jdtJar = None
+    if not args.javac and args.jdt is not None:
+        if not args.jdt.endswith('.jar'):
+            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:
+                # 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)
+
     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(',')]
@@ -2087,7 +2107,7 @@
             logv('[no Java sources for {0} - skipping]'.format(p.name))
             continue
 
-        task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, taskDeps)
+        task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, jdtJar, taskDeps)
 
         if args.parallelize:
             # Best to initialize class paths on main process
@@ -2113,6 +2133,7 @@
                 if t.proc.is_alive():
                     active.append(t)
                 else:
+                    _removeSubprocess(t.sub)
                     if t.proc.exitcode != 0:
                         return ([], joinTasks(tasks))
             return (active, [])
@@ -2126,10 +2147,18 @@
                     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, lambda x, y: remainingDepsDepth(x) - remainingDepsDepth(y))
+            return sorted(tasks, compareTasks)
 
         import multiprocessing
         cpus = multiprocessing.cpu_count()
@@ -2162,6 +2191,7 @@
                     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
 
@@ -2696,6 +2726,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:
@@ -2706,13 +2742,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))
--- a/src/cpu/sparc/vm/graalCodeInstaller_sparc.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/cpu/sparc/vm/graalCodeInstaller_sparc.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/src/cpu/x86/vm/graalCodeInstaller_x86.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/src/cpu/x86/vm/templateTable_x86_64.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/src/gpu/hsail/vm/gpu_hsail.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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"
@@ -243,6 +243,8 @@
         return _last_idx;
       }
     }
+    ShouldNotReachHere();
+    return -1;
   }
 
 public:
--- a/src/gpu/hsail/vm/gpu_hsail.hpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/gpu/hsail/vm/gpu_hsail.hpp	Mon May 12 21:29:29 2014 -0700
@@ -32,7 +32,7 @@
 class Hsail : public Gpu {
 
   public:
-  class HSAILKernelDeoptimization {
+  class HSAILKernelDeoptimization VALUE_OBJ_CLASS_SPEC {
     friend class VMStructs;
    private:
     // TODO: separate workitemid and actionAndReason out
@@ -40,14 +40,16 @@
     // for now, though we only ever have one hsail fram
     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
@@ -75,7 +77,7 @@
       _deopt_next_index = 0;
       _num_slots = numSlots;
       _bytesPerSaveArea = bytesPerSaveArea;
-      _deopt_span = sizeof(HSAILKernelDeoptimization) + bytesPerSaveArea;
+      _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)));
       }
--- a/src/gpu/hsail/vm/gpu_hsail_Frame.hpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/gpu/hsail/vm/gpu_hsail_Frame.hpp	Mon May 12 21:29:29 2014 -0700
@@ -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,14 +29,13 @@
 #include "code/debugInfo.hpp"
 #include "code/location.hpp"
 
-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 _num_stack_slots; 
-  jbyte  _save_area[0];     // save area size can vary per kernel compilation  
 
 public:
   // Accessors
@@ -20,29 +43,30 @@
   jint num_s_regs() {return _num_s_regs; }
   jint num_d_regs() {return _num_d_regs; }
   jint num_stack_slots() {return _num_stack_slots; }
+  jbyte * data_start() {return (jbyte *) this  + sizeof(*this); }
   jlong get_d_reg(int idx) {
     int ofst = num_s_regs() * 4 + idx * 8;
-    return(*(jlong *) (_save_area + ofst));
+    return(*(jlong *) (data_start() + ofst));
   }
   jint get_s_reg(int idx) {
     int ofst = idx * 4;
-    return(*(jint *) (_save_area + ofst));
+    return(*(jint *) (data_start() + ofst));
   }
   void put_d_reg(int idx, jlong val) {
     int ofst = num_s_regs() * 4 + idx * 8;
-    (*(jlong *) (_save_area + 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 *) (_save_area + ofst));
+    return(*(jint *) (data_start() + ofst));
   }
   jlong get_stackslot64(int stackOffset) {
     int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
-    return(*(jlong *) (_save_area + ofst));
+    return(*(jlong *) (data_start() + ofst));
   }
   void put_stackslot64(int stackOffset, jlong val) {
     int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
-    (*(jlong *) (_save_area + ofst)) = val;
+    (*(jlong *) (data_start() + ofst)) = val;
   }
 };
   
--- a/src/gpu/hsail/vm/vmStructs_hsail.hpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/gpu/hsail/vm/vmStructs_hsail.hpp	Mon May 12 21:29:29 2014 -0700
@@ -40,7 +40,6 @@
                                                                                                                                       \
   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)                                      \
--- a/src/gpu/ptx/vm/gpu_ptx.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/gpu/ptx/vm/gpu_ptx.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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/vmSymbols.hpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/classfile/vmSymbols.hpp	Mon May 12 21:29:29 2014 -0700
@@ -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")               \
@@ -360,27 +358,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,               "(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/nmethod.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/code/nmethod.cpp	Mon May 12 21:29:29 2014 -0700
@@ -1064,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);
--- a/src/share/vm/compiler/compileBroker.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/compiler/compileBroker.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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) {
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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;
   }
--- a/src/share/vm/graal/graalCompiler.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/graal/graalCompiler.cpp	Mon May 12 21:29:29 2014 -0700
@@ -25,178 +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() {
-  if (!should_perform_init()) {
+#ifdef COMPILERGRAAL
+  if (!UseCompiler || !should_perform_init()) {
     return;
   }
 
-  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);
+  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);
+    }
   }
 
-  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);
-  }
-  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 = UseGraalCompilationQueue && (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;
-}
-
+#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, (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;
   }
 }
 
@@ -205,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	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/graal/graalCompiler.hpp	Mon May 12 21:29:29 2014 -0700
@@ -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,6 +57,7 @@
   // Initialization
   virtual void initialize();
 
+#ifdef COMPILERGRAAL
   // Compilation entry point for methods
   virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
 
@@ -65,31 +66,8 @@
   // 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/graalRuntime.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/graal/graalRuntime.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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,32 @@
   }
 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 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
 
-// JVM_InitializeTruffleRuntime
-JVM_ENTRY(jobject, JVM_InitializeTruffleRuntime(JNIEnv *env, jclass graalclass))
-  return JNIHandles::make_local(VMToCompiler::truffleRuntime()());
+// private static String[] HotSpotOptions.getVMOptions(boolean[] timeCompilations)
+JVM_ENTRY(jobject, JVM_GetGraalOptions(JNIEnv *env, jclass c, jobject timeCompilations))
+  HandleMark hm;
+  int numOptions = Arguments::num_graal_args();
+  objArrayOop options = oopFactory::new_objArray(SystemDictionary::String_klass(),
+      numOptions, CHECK_NULL);
+  objArrayHandle optionsHandle(THREAD, options);
+  for (int i = 0; i < numOptions; i++) {
+    Handle option = java_lang_String::create_from_str(Arguments::graal_args_array()[i], CHECK_NULL);
+    optionsHandle->obj_at_put(i, option());
+  }
+  ((typeArrayOop) JNIHandles::resolve(timeCompilations))->bool_at_put(0, CITime || CITimeEach);
+  return JNIHandles::make_local(THREAD, optionsHandle());
 JVM_END
--- a/src/share/vm/graal/graalRuntime.hpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/graal/graalRuntime.hpp	Mon May 12 21:29:29 2014 -0700
@@ -28,8 +28,21 @@
 #include "memory/allocation.hpp"
 #include "runtime/deoptimization.hpp"
 
-class GraalRuntime: public AllStatic {
+class GraalRuntime: public CHeapObj<mtCompiler> {
+ private:
+
+  static address   _external_deopt_i2c_entry;
+
  public:
+
+  static void initialize_natives(JNIEnv *env, jclass c2vmClass);
+  static BufferBlob* initialize_buffer_blob();
+  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 +73,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	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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,135 +40,184 @@
   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));
+  return Handle(JNIHandles::resolve_non_null(_HotSpotGraalRuntime_instance));
 }
 
-Handle VMToCompiler::instance() {
-  if (JNIHandles::resolve(_vmToCompilerPermObject) == NULL) {
-    KlassHandle compilerKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotGraalRuntime());
-
+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(graalRuntime());
-    JavaCalls::call_virtual(&result, compilerKlass, vmSymbols::getVMToCompiler_name(), vmSymbols::getVMToCompiler_signature(), &args, Thread::current());
+    args.set_receiver(get_HotSpotGraalRuntime());
+    JavaCalls::call_virtual(&result, klass, getVMToCompiler, sig, &args, THREAD);
     check_pending_exception("Couldn't get VMToCompiler");
-    _vmToCompilerPermObject = JNIHandles::make_global((oop) result.get_jobject());
+    _VMToCompiler_instance = JNIHandles::make_global((oop) result.get_jobject());
   }
-  return Handle(JNIHandles::resolve_non_null(_vmToCompilerPermObject));
+  return Handle(JNIHandles::resolve_non_null(_VMToCompiler_instance));
 }
 
 void VMToCompiler::initOptions() {
-  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
   Thread* THREAD = Thread::current();
+  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotOptions", THREAD);
+  KlassHandle optionsKlass = loadClass(name);
   optionsKlass->initialize(THREAD);
   check_pending_exception("Error while calling initOptions");
 }
 
 jboolean VMToCompiler::setOption(Handle option) {
   assert(!option.is_null(), "");
-  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
-
   Thread* THREAD = Thread::current();
+  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotOptions", THREAD);
+  TempNewSymbol setOption = SymbolTable::new_symbol("setOption", THREAD);
+  TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;)Z", THREAD);
+  KlassHandle optionsKlass = loadClass(name);
   JavaValue result(T_BOOLEAN);
-  JavaCalls::call_static(&result, optionsKlass, vmSymbols::setOption_name(), vmSymbols::setOption_signature(), option, THREAD);
+  JavaCalls::call_static(&result, optionsKlass, setOption, sig, option, THREAD);
   check_pending_exception("Error while calling setOption");
   return result.get_jboolean();
 }
 
 void VMToCompiler::finalizeOptions(jboolean ciTime) {
-  KlassHandle optionsKlass = loadClass(vmSymbols::com_oracle_graal_hotspot_HotSpotOptions());
   Thread* THREAD = Thread::current();
+  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotOptions", THREAD);
+  TempNewSymbol finalizeOptions = SymbolTable::new_symbol("finalizeOptions", THREAD);
+  TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;)Z", THREAD);
+  KlassHandle optionsKlass = loadClass(name);
   JavaValue result(T_VOID);
   JavaCallArguments args;
   args.push_int(ciTime);
-  JavaCalls::call_static(&result, optionsKlass, vmSymbols::finalizeOptions_name(), vmSymbols::bool_void_signature(), &args, THREAD);
+  JavaCalls::call_static(&result, optionsKlass, finalizeOptions, vmSymbols::bool_void_signature(), &args, THREAD);
   check_pending_exception("Error while calling finalizeOptions");
 }
 
+void VMToCompiler::startRuntime() {
+  JavaThread* THREAD = JavaThread::current();
+  JavaValue result(T_VOID);
+  JavaCallArguments args;
+  TempNewSymbol startRuntime = SymbolTable::new_symbol("startRuntime", THREAD);
+  args.push_oop(VMToCompiler_instance());
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), startRuntime, vmSymbols::void_method_signature(), &args, THREAD);
+  check_pending_exception("Error while calling startRuntime");
+}
+
+#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;
+  TempNewSymbol startCompiler = SymbolTable::new_symbol("startCompiler", THREAD);
+  args.push_oop(VMToCompiler_instance());
+  args.push_int(bootstrap_enabled);
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), startCompiler, vmSymbols::bool_void_signature(), &args, THREAD);
+  check_pending_exception("Error while calling startCompiler");
+}
+
 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());
+  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, vmToCompilerKlass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, THREAD);
+  JavaCalls::call_interface(&result, VMToCompiler_klass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, THREAD);
   check_pending_exception("Error while calling compileMethod");
 }
 
 void VMToCompiler::shutdownCompiler() {
-  if (_graalRuntimePermObject != NULL) {
-    HandleMark hm;
+  JavaThread* THREAD = JavaThread::current();
+  HandleMark hm(THREAD);
+  TempNewSymbol shutdownCompiler = SymbolTable::new_symbol("shutdownCompiler", THREAD);
+  JavaValue result(T_VOID);
+  JavaCallArguments args;
+  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(instance());
-    JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::shutdownCompiler_name(), vmSymbols::void_method_signature(), &args, THREAD);
-    check_pending_exception("Error while calling shutdownCompiler");
+    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(_graalRuntimePermObject);
-    JNIHandles::destroy_global(_vmToCompilerPermObject);
-    //JNIHandles::destroy_global(_vmToCompilerPermKlass);
+    JNIHandles::destroy_global(_HotSpotGraalRuntime_instance);
+    JNIHandles::destroy_global(_VMToCompiler_instance);
 
-    _graalRuntimePermObject = NULL;
-    _vmToCompilerPermObject = NULL;
-    _vmToCompilerPermKlass = NULL;
+    _HotSpotGraalRuntime_instance = NULL;
+    _VMToCompiler_instance = NULL;
+    _VMToCompiler_klass = NULL;
   }
 }
 
-void VMToCompiler::startCompiler(jboolean bootstrap_enabled) {
+#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();
-  JavaValue result(T_VOID);
-  JavaCallArguments args;
-  args.push_oop(instance());
-  args.push_int(bootstrap_enabled);
-  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::bool_void_signature(), &args, THREAD);
-  check_pending_exception("Error while calling startCompiler");
-}
-
-void VMToCompiler::bootstrap() {
-  JavaThread* THREAD = JavaThread::current();
+  TempNewSymbol compileTheWorld = SymbolTable::new_symbol("compileTheWorld", THREAD);
   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");
-}
-
-void VMToCompiler::compileTheWorld() {
-  JavaThread* THREAD = JavaThread::current();
-  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(), compileTheWorld, vmSymbols::void_method_signature(), &args, THREAD);
   check_pending_exception("Error while calling compileTheWorld");
 }
+#endif
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Mon May 12 21:29:29 2014 -0700
@@ -35,20 +35,24 @@
 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();
+  // 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>();
@@ -60,20 +64,30 @@
   // public static void HotSpotOptions.finalizeOptions(boolean ciTime);
   static void finalizeOptions(jboolean ciTime);
 
+  // public abstract void startRuntime();
+  static void startRuntime();
+
+#ifdef COMPILERGRAAL
+  // public abstract void startCompiler(boolean bootstrapEnabled);
+  static void startCompiler(jboolean bootstrap_enabled);
+
+  // 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/prims/jni.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/prims/jni.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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,9 +5174,9 @@
     *vm = (JavaVM *)(&main_vm);
     *(JNIEnv**)penv = thread->jni_environment();
 
-#ifdef GRAAL
-    if (COMPILERGRAAL_PRESENT(UseGraalCompilationQueue) NOT_COMPILERGRAAL(true)) {
-      // GraalCompiler needs to have been created in compileBroker.cpp
+#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();
@@ -5210,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	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/prims/jvmtiTagMap.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/prims/nativeLookup.cpp	Mon May 12 21:29:29 2014 -0700
@@ -124,8 +124,10 @@
   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_CreateTruffleRuntime(JNIEnv *env, jclass c);
+  jobject JNICALL JVM_GetGraalOptions(JNIEnv *env, jclass hotspotOptionsClass, jobject timeCompilations);
 #endif
 }
 
@@ -138,8 +140,10 @@
   { 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_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_getVMOptions", NULL, FN_PTR(JVM_GetGraalOptions)             },
 #endif
 };
 
--- a/src/share/vm/runtime/deoptimization.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/runtime/deoptimization.cpp	Mon May 12 21:29:29 2014 -0700
@@ -88,7 +88,7 @@
 #endif
 
 #ifdef GRAAL
-#include "graal/graalCompiler.hpp"
+#include "graal/graalRuntime.hpp"
 #include "graal/graalJavaAccess.hpp"
 #endif
 
--- a/src/share/vm/runtime/java.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/runtime/java.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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"
@@ -462,10 +463,13 @@
   static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;
 
 #ifdef GRAAL
+#ifdef COMPILERGRAAL
   if (GraalCompiler::instance() != NULL) {
-    GraalCompiler::instance()->exit();
+    GraalCompiler::instance()->shutdown();
   }
 #endif
+  VMToCompiler::shutdownRuntime();
+#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/src/share/vm/runtime/javaCalls.cpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/runtime/javaCalls.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/runtime/mutex.cpp	Mon May 12 21:29:29 2014 -0700
@@ -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	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/runtime/mutexLocker.cpp	Mon May 12 21:29:29 2014 -0700
@@ -133,6 +133,10 @@
 Mutex*   JfrThreadGroups_lock         = NULL;
 #endif
 
+#ifdef GRAAL
+Monitor* GraalInitialization_lock     = NULL;
+#endif
+
 #define MAX_NUM_MUTEX 128
 static Monitor * _mutex_array[MAX_NUM_MUTEX];
 static int _num_mutex;
@@ -281,6 +285,9 @@
   def(JfrStacktrace_lock           , Mutex,   special,     true );
 #endif
 
+#ifdef GRAAL
+  def(GraalInitialization_lock     , Monitor, nonleaf+5,   false);
+#endif
 }
 
 GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/share/vm/runtime/mutexLocker.hpp	Mon May 12 20:17:25 2014 -0700
+++ b/src/share/vm/runtime/mutexLocker.hpp	Mon May 12 21:29:29 2014 -0700
@@ -146,6 +146,10 @@
 extern Mutex*   JfrThreadGroups_lock;            // protects JFR access to Thread Groups
 #endif
 
+#ifdef GRAAL
+extern Monitor* GraalInitialization_lock;        // ensures exactly 1 thread initializes Graal
+#endif
+
 // A MutexLocker provides mutual exclusion with respect to a given mutex
 // for the scope which contains the locker.  The lock is an OS lock, not
 // an object lock, and the two do not interoperate.  Do not use Mutex-based
--- a/test/whitelist_baseline.txt	Mon May 12 20:17:25 2014 -0700
+++ b/test/whitelist_baseline.txt	Mon May 12 21:29:29 2014 -0700
@@ -1,7 +1,7 @@
-# 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.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
@@ -17,3 +17,12 @@
 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
--- a/test/whitelist_shortunittest.txt	Mon May 12 20:17:25 2014 -0700
+++ b/test/whitelist_shortunittest.txt	Mon May 12 21:29:29 2014 -0700
@@ -1,1 +1,3 @@
 com.oracle.graal.jtt.bytecode.*
+com.oracle.graal.jtt.loop.*
+com.oracle.graal.jtt.except.*