changeset 15466:4b75c567aa62

Merge.
author Roland Schatz <roland.schatz@oracle.com>
date Fri, 02 May 2014 11:33:47 +0200
parents 8df78fe6d84c (diff) f52961f15275 (current diff)
children 4e3c2247daf4
files
diffstat 395 files changed, 13073 insertions(+), 4039 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri May 02 10:46:52 2014 +0200
+++ b/.hgignore	Fri May 02 11:33:47 2014 +0200
@@ -87,3 +87,4 @@
 agent/build/*
 agent/make/filelist
 agent/make/sa17.tar.gz
+export.json
--- a/CHANGELOG.md	Fri May 02 10:46:52 2014 +0200
+++ b/CHANGELOG.md	Fri May 02 11:33:47 2014 +0200
@@ -8,6 +8,7 @@
 * Added graal.version system property to Graal enabled VM builds.
 * Transitioned to JDK 8 as minimum JDK level for Graal.
 * Added support for stack introspection.
+* New MatchRule facility to convert multiple HIR nodes into specialized LIR
 * ...
 
 ### Truffle
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,4 +93,9 @@
      * Gets a description of the target architecture.
      */
     TargetDescription getTarget();
+
+    /**
+     * Create a new speculation log for the target runtime.
+     */
+    SpeculationLog createSpeculationLog();
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Fri May 02 11:33:47 2014 +0200
@@ -432,22 +432,20 @@
 
         private static final long serialVersionUID = 3612943150662354844L;
         public final Object id;
-        public final Mark[] references;
 
-        public Mark(int pcOffset, Object id, Mark[] references) {
+        public Mark(int pcOffset, Object id) {
             super(pcOffset);
             this.id = id;
-            this.references = references;
         }
 
         @Override
         public String toString() {
             if (id == null) {
-                return String.format("%d[<mark with %d references>]", pcOffset, references.length);
+                return String.format("%d[<mar>]", pcOffset);
             } else if (id instanceof Integer) {
-                return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, Integer.toHexString((Integer) id));
+                return String.format("%d[<mark with id %s>]", pcOffset, Integer.toHexString((Integer) id));
             } else {
-                return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, id.toString());
+                return String.format("%d[<mark with id %s>]", pcOffset, id.toString());
             }
         }
     }
@@ -635,10 +633,9 @@
      *
      * @param codePos the position in the code that is covered by the handler
      * @param markId the identifier for this mark
-     * @param references an array of other marks that this mark references
      */
-    public Mark recordMark(int codePos, Object markId, Mark[] references) {
-        Mark mark = new Mark(codePos, markId, references);
+    public Mark recordMark(int codePos, Object markId) {
+        Mark mark = new Mark(codePos, markId);
         marks.add(mark);
         return mark;
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,16 +33,16 @@
     /**
      * Keys.
      */
-    private Register[] registers;
+    private final Register[] registers;
 
     /**
      * Slot indexes relative to stack pointer.
      */
-    private int[] slots;
+    private final int[] slots;
 
     /**
      * Creates a map from registers to frame slots.
-     * 
+     *
      * @param registers the keys in the map
      * @param slots frame slot index for each register in {@code registers}
      */
@@ -55,6 +55,21 @@
     }
 
     /**
+     * Gets the frame slot index for a given register.
+     *
+     * @param register register to get the frame slot index for
+     * @return frame slot index
+     */
+    public int registerToSlot(Register register) {
+        for (int i = 0; i < registers.length; i++) {
+            if (register.equals(registers[i])) {
+                return slots[i];
+            }
+        }
+        throw new IllegalArgumentException(register + " not saved by this layout: " + this);
+    }
+
+    /**
      * Gets this layout information as a {@link Map} from registers to slots.
      */
     public Map<Register, Integer> registersToSlots(boolean sorted) {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Fri May 02 11:33:47 2014 +0200
@@ -27,7 +27,7 @@
 public interface StackIntrospection {
 
     /**
-     * Accesses the current stack, returning a collection of {@long InspectedFrame}s that can be
+     * Accesses the current stack, returning a collection of {@link InspectedFrame}s that can be
      * used to inspect the stack frames' contents.
      *
      * @param initialMethods if this is non-{@code null}, then the stack trace will start at these
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Fri May 02 11:33:47 2014 +0200
@@ -45,7 +45,7 @@
 
     /**
      * Initializes a new value of the specified kind.
-     * 
+     *
      * @param platformKind the kind
      */
     protected Value(PlatformKind platformKind) {
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri May 02 11:33:47 2014 +0200
@@ -79,6 +79,14 @@
         }
     }
 
+    public final void movptr(Register dst, AMD64Address src) {
+        movq(dst, src);
+    }
+
+    public final void movptr(AMD64Address dst, Register src) {
+        movq(dst, src);
+    }
+
     public final void movptr(AMD64Address dst, int src) {
         movslq(dst, src);
     }
@@ -277,7 +285,7 @@
     /**
      * Emit code to save a given set of callee save registers in the {@linkplain CalleeSaveLayout
      * CSA} within the frame.
-     * 
+     *
      * @param csl the description of the CSA
      * @param frameToCSA offset from the frame pointer to the CSA
      */
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Fri May 02 11:33:47 2014 +0200
@@ -556,6 +556,17 @@
     }
 
     /**
+     * Emits an atomic_exch_global instruction.
+     *
+     * @param result result operand that gets the original contents of the memory location
+     * @param address the memory location
+     * @param newValue the new value to write to the memory location
+     */
+    public void emitAtomicExch(Kind accessKind, AllocatableValue result, HSAILAddress address, Value newValue) {
+        emitString(String.format("atomic_exch_global_b%d   %s, %s, %s;", getArgSizeFromKind(accessKind), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(newValue)));
+    }
+
+    /**
      * Emits a comment. Useful for debugging purposes.
      *
      * @param comment
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java	Fri May 02 11:33:47 2014 +0200
@@ -30,11 +30,6 @@
 
 public class SPARCAddress extends AbstractAddress {
 
-    /**
-     * Stack bias for stack and frame pointer loads.
-     */
-    private static final int STACK_BIAS = 0x7ff;
-
     private final Register base;
     private final Register index;
     private final int displacement;
@@ -42,7 +37,7 @@
     /**
      * Creates an {@link SPARCAddress} with given base register, no scaling and a given
      * displacement.
-     * 
+     *
      * @param base the base register
      * @param displacement the displacement
      */
@@ -54,7 +49,7 @@
 
     /**
      * Creates an {@link SPARCAddress} with given base register, no scaling and a given index.
-     * 
+     *
      * @param base the base register
      * @param index the index register
      */
@@ -113,7 +108,7 @@
     /**
      * This method adds the stack-bias to the displacement if the base register is either
      * {@link SPARC#sp} or {@link SPARC#fp}.
-     * 
+     *
      * @return Optional additive displacement.
      */
     public int getDisplacement() {
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri May 02 11:33:47 2014 +0200
@@ -37,7 +37,7 @@
 
     /**
      * Constructs an assembler for the SPARC architecture.
-     * 
+     *
      * @param registerConfig the register configuration used to bind {@link Register#Frame} and
      *            {@link Register#CallerFrame} to physical registers. This value can be null if this
      *            assembler instance will not be used to assemble instructions using these logical
@@ -50,7 +50,7 @@
     // @formatter:off
     /**
      * Instruction format for sethi.
-     * 
+     *
      * | 00  |  rd    | op2 |               imm22                     |
      * |31 30|29    25|24 22|21                                      0|
      */
@@ -123,7 +123,7 @@
     // @formatter:off
     /**
      * Instruction format for branches.
-     * 
+     *
      * | 00  |a | cond | op2 |             disp22                      |
      * |31 30|29|28  25|24 22|21                                      0|
      */
@@ -142,7 +142,7 @@
     // @formatter:off
     /**
      * Instruction format for conditional branches.
-     * 
+     *
      * | 00  |a | cond | op2 |cc1|cc0|p |             disp19           |
      * |31 30|29|28  25|24 22|21 |20 |19|                             0|
      */
@@ -330,7 +330,7 @@
     // @formatter:off
     /**
      * Instruction format for calls.
-     * 
+     *
      * | 01  |                      disp30                             |
      * |31 30|29                                                      0|
      */
@@ -457,7 +457,7 @@
     // @formatter:off
     /**
      * Instruction format for Arithmetic, Logical, Moves, Tcc, Prefetch, and Misc.
-     * 
+     *
      * | 10  |   rd   |   op3   |   rs1   | i|     imm_asi   |   rs2   |
      * | 10  |   rd   |   op3   |   rs1   | i|          simm13         |
      * | 10  |   rd   |   op3   |   rs1   | i| x|            |   rs2   |
@@ -594,7 +594,7 @@
     // @formatter:off
     /**
      * Instruction format for Loads, Stores and Misc.
-     * 
+     *
      * | 11  |   rd   |   op3   |   rs1   | i|   imm_asi   |   rs2   |
      * | 11  |   rd   |   op3   |   rs1   | i|        simm13         |
      * |31 30|29    25|24     19|18     14|13|12          5|4       0|
@@ -749,7 +749,7 @@
     // @formatter:off
     /**
      * Instruction format for Movcc.
-     * 
+     *
      * | 10  |   rd   |   op3   |cc2|   cond  | i|cc1|cc0|      -      |   rs2   |
      * | 10  |   rd   |   op3   |cc2|   cond  | i|cc1|cc0|        simm11         |
      * |31 30|29    25|24     19| 18|17     14|13| 12| 11|10          5|4       0|
@@ -1007,7 +1007,7 @@
         Wrreg(0x30, "wrreg"),
         Saved(0x31, "saved"),
 
-        Fpop1(0x34, "fpop1"),
+        Fpop1(0b11_0100, "fpop1"),
         Fpop2(0x35, "fpop2"),
         Impdep1(0x36, "impdep1"),
         Impdep2(0x37, "impdep2"),
@@ -1036,14 +1036,14 @@
         Ldx(0b001011, "ldx"),
         Stx(0b001110, "stx"),
 
-        Ldf(0x20, "ldf"),
+        Ldf(0b100000, "ldf"),
         Ldfsr(0x21, "ldfsr"),
         Ldaf(0x22, "ldaf"),
-        Lddf(0x23, "lddf"),
-        Stf(0x24, "stf"),
+        Lddf(0b100011, "lddf"),
+        Stf(0b100100, "stf"),
         Stfsr(0x25, "stfsr"),
         Staf(0x26, "staf"),
-        Stdf(0x27, "stdf");
+        Stdf(0b100111, "stdf");
 
         // @formatter:on
 
@@ -1092,9 +1092,9 @@
     public enum Opfs {
         // @formatter:off
 
-        Fmovs(0x01, "fmovs"),
-        Fmovd(0x02, "fmovd"),
-        Fmovq(0x03, "fmovq"),
+        Fmovs(0b0_0000_0001, "fmovs"),
+        Fmovd(0b0_0000_0010, "fmovd"),
+        Fmovq(0b0_0000_0011, "fmovq"),
         Fnegs(0x05, "fnegs"),
         Fnegd(0x06, "fnegd"),
         Fnegq(0x07, "fnegq"),
@@ -2376,6 +2376,20 @@
         }
     }
 
+    public static class Fmovs extends Fmt3p {
+
+        public Fmovs(Register src, Register dst) {
+            super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovs, g0, src, dst);
+        }
+    }
+
+    public static class Fmovd extends Fmt3p {
+
+        public Fmovd(Register src, Register dst) {
+            super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovd, g0, src, dst);
+        }
+    }
+
     public static class Fmuls extends Fmt3p {
 
         public Fmuls(Register src1, Register src2, Register dst) {
@@ -3174,6 +3188,20 @@
         }
     }
 
+    public static class Stdf extends Fmt11 {
+
+        public Stdf(Register dst, SPARCAddress src) {
+            super(Op3s.Stdf, src, dst);
+        }
+    }
+
+    public static class Stf extends Fmt11 {
+
+        public Stf(Register dst, SPARCAddress src) {
+            super(Op3s.Stf, src, dst);
+        }
+    }
+
     public static class Sth extends Fmt11 {
 
         public Sth(Register dst, SPARCAddress addr) {
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Fri May 02 11:33:47 2014 +0200
@@ -50,7 +50,7 @@
 
 public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, BaselineFrameStateBuilder> implements BytecodeParserTool {
     private Backend backend;
-    protected LIRGenerator gen;
+    protected LIRGeneratorTool gen;
     private LIRGenerationResult lirGenRes;
     private BytecodeLIRBuilder lirBuilder;
     @SuppressWarnings("unused") private BciBlock[] loopHeaders;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -263,6 +263,25 @@
         }
     }
 
+    public void emitCompareBranchMemory(Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        boolean mirrored = emitCompareMemory(cmpKind, left, right, state);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        switch (left.getKind().getStackKind()) {
+            case Int:
+            case Long:
+            case Object:
+                append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+                break;
+            case Float:
+            case Double:
+                append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("" + left.getKind());
+        }
+    }
+
     @Override
     public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) {
         append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability));
@@ -343,6 +362,26 @@
         }
     }
 
+    /**
+     * This method emits the compare against memory instruction, and may reorder the operands. It
+     * returns true if it did so.
+     *
+     * @param b the right operand of the comparison
+     * @return true if the left and right operands were switched, false otherwise
+     */
+    private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) {
+        boolean mirrored;
+        if (LIRValueUtil.isVariable(a)) {
+            Variable left = load(a);
+            emitCompareRegMemoryOp(cmpKind, left, b, state);
+            mirrored = false;
+        } else {
+            emitCompareMemoryConOp(cmpKind, b, a, state);
+            mirrored = true;
+        }
+        return mirrored;
+    }
+
     protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Value value, LIRFrameState state) {
         assert kind.getStackKind() == value.getKind().getStackKind();
         switch (kind) {
@@ -761,6 +800,28 @@
         }
     }
 
+    public Variable emitRol(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitShift(IROL, a, b);
+            case Long:
+                return emitShift(LROL, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public Variable emitRor(Value a, Value b) {
+        switch (a.getKind().getStackKind()) {
+            case Int:
+                return emitShift(IROR, a, b);
+            case Long:
+                return emitShift(LROR, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     private AllocatableValue emitConvert2RegOp(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) {
         Variable result = newVariable(kind);
         append(new Unary2RegOp(op, result, input));
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,495 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.compiler.amd64;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
-import static com.oracle.graal.nodes.ConstantNode.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public class AMD64MemoryPeephole implements MemoryArithmeticLIRLowerer {
-    protected final AMD64NodeLIRBuilder gen;
-    protected List<ValueNode> deferredNodes;
-
-    protected AMD64MemoryPeephole(AMD64NodeLIRBuilder gen) {
-        this.gen = gen;
-    }
-
-    public Value setResult(ValueNode x, Value operand) {
-        return gen.setResult(x, operand);
-    }
-
-    @Override
-    public boolean memoryPeephole(Access access, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred) {
-        this.deferredNodes = deferred;
-        boolean result = operation.generate(this, access);
-        if (result) {
-            Debug.log("merge %s %s with %1s %s %s", access, access.asNode().stamp(), operation, result, access.asNode().graph().method());
-        } else {
-            Debug.log("can't merge %s %s with %1s", access, access.asNode().stamp(), operation);
-        }
-        this.deferredNodes = null;
-        return result;
-    }
-
-    protected LIRFrameState getState(Access access) {
-        if (access instanceof DeoptimizingNode) {
-            return gen.state((DeoptimizingNode) access);
-        }
-        return null;
-    }
-
-    protected Kind getMemoryKind(Access access) {
-        return (Kind) gen.getLIRGenerator().getPlatformKind(access.asNode().stamp());
-    }
-
-    protected AMD64AddressValue makeAddress(Access access) {
-        return (AMD64AddressValue) access.accessLocation().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(access.object()));
-    }
-
-    protected Value emitBinaryMemory(AMD64Arithmetic op, boolean commutative, ValueNode x, ValueNode y, Access access) {
-        ValueNode other = x;
-        if (uncast(other) == access) {
-            if (commutative) {
-                other = y;
-            } else {
-                return null;
-            }
-        }
-        ensureEvaluated(other);
-        return gen.getLIRGenerator().emitBinaryMemory(op, getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(other)), makeAddress(access), getState(access));
-    }
-
-    /**
-     * Constants with multiple users need to be evaluated in the right location so that later users
-     * can pick up the operand. Make sure that happens when it needs to.
-     */
-    protected void ensureEvaluated(ValueNode node) {
-        evaluateDeferred(node);
-        evaluateDeferred();
-    }
-
-    protected void evaluateDeferred(ValueNode node) {
-        // Ensure the other input value has a generated value.
-        if (ConstantNodeRecordsUsages) {
-            if (!gen.hasOperand(node)) {
-                assert node instanceof ConstantNode : node;
-                ((ConstantNode) node).generate(gen);
-            }
-        }
-    }
-
-    protected void evaluateDeferred() {
-        if (deferredNodes != null) {
-            for (ValueNode node : deferredNodes) {
-                evaluateDeferred(node);
-            }
-        }
-    }
-
-    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
-        AMD64AddressValue address = makeAddress(access);
-        LIRFrameState state = getState(access);
-        evaluateDeferred();
-        return gen.getLIRGenerator().emitConvert2MemoryOp(kind, op, address, state);
-    }
-
-    @Override
-    public Value emitAddMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IADD, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LADD, true, x, y, access);
-            case Float:
-                return emitBinaryMemory(FADD, true, x, y, access);
-            case Double:
-                return emitBinaryMemory(DADD, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitSubMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(ISUB, false, x, y, access);
-            case Long:
-                return emitBinaryMemory(LSUB, false, x, y, access);
-            case Float:
-                return emitBinaryMemory(FSUB, false, x, y, access);
-            case Double:
-                return emitBinaryMemory(DSUB, false, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitMulMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IMUL, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LMUL, true, x, y, access);
-            case Float:
-                return emitBinaryMemory(FMUL, true, x, y, access);
-            case Double:
-                return emitBinaryMemory(DMUL, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitDivMemory(ValueNode x, ValueNode y, Access access) {
-        return null;
-    }
-
-    @Override
-    public Value emitRemMemory(ValueNode x, ValueNode y, Access access) {
-        return null;
-    }
-
-    @Override
-    public Value emitAndMemory(ValueNode x, ValueNode y, Access access) {
-        Kind kind = getMemoryKind(access);
-        switch (kind) {
-            case Int:
-                return emitBinaryMemory(IAND, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LAND, true, x, y, access);
-            case Short: {
-                ValueNode other = selectOtherInput(x, y, access);
-                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
-                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
-                    // Convert to unsigned load
-                    ensureEvaluated(other);
-                    return emitZeroExtendMemory(16, 32, access);
-                }
-                return null;
-            }
-            case Byte: {
-                if (OptFoldMemory.getValue()) {
-                    return null;
-                }
-                ValueNode other = selectOtherInput(x, y, access);
-                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
-                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
-                    // Convert to unsigned load
-                    ensureEvaluated(other);
-                    return emitConvert2MemoryOp(Kind.Int, MOV_B2UI, access);
-                }
-                return null;
-            }
-
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitOrMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IOR, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LOR, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitXorMemory(ValueNode x, ValueNode y, Access access) {
-        switch (getMemoryKind(access)) {
-            case Int:
-                return emitBinaryMemory(IXOR, true, x, y, access);
-            case Long:
-                return emitBinaryMemory(LXOR, true, x, y, access);
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Value emitReinterpretMemory(Stamp stamp, Access access) {
-        PlatformKind to = gen.getLIRGenerator().getPlatformKind(stamp);
-        Kind from = getMemoryKind(access);
-        assert to != from : "should have been eliminated";
-
-        /*
-         * Conversions between integer to floating point types require moves between CPU and FPU
-         * registers.
-         */
-        switch ((Kind) to) {
-            case Int:
-                switch (from) {
-                    case Float:
-                        return emitConvert2MemoryOp(to, MOV_F2I, access);
-                }
-                break;
-            case Long:
-                switch (from) {
-                    case Double:
-                        return emitConvert2MemoryOp(to, MOV_D2L, access);
-                }
-                break;
-            case Float:
-                switch (from) {
-                    case Int:
-                        return emitConvert2MemoryOp(to, MOV_I2F, access);
-                }
-                break;
-            case Double:
-                switch (from) {
-                    case Long:
-                        return emitConvert2MemoryOp(to, MOV_L2D, access);
-                }
-                break;
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
-
-    @Override
-    public Value emitFloatConvertMemory(FloatConvert op, Access access) {
-        switch (op) {
-            case D2F:
-                return emitConvert2MemoryOp(Kind.Float, D2F, access);
-            case D2I:
-                return emitConvert2MemoryOp(Kind.Int, D2I, access);
-            case D2L:
-                return emitConvert2MemoryOp(Kind.Long, D2L, access);
-            case F2D:
-                return emitConvert2MemoryOp(Kind.Double, F2D, access);
-            case F2I:
-                return emitConvert2MemoryOp(Kind.Int, F2I, access);
-            case F2L:
-                return emitConvert2MemoryOp(Kind.Long, F2L, access);
-            case I2D:
-                return emitConvert2MemoryOp(Kind.Double, I2D, access);
-            case I2F:
-                return emitConvert2MemoryOp(Kind.Float, I2F, access);
-            case L2D:
-                return emitConvert2MemoryOp(Kind.Double, L2D, access);
-            case L2F:
-                return emitConvert2MemoryOp(Kind.Float, L2F, access);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public Value emitSignExtendMemory(Access access, int fromBits, int toBits) {
-        assert fromBits <= toBits && toBits <= 64;
-        if (fromBits == toBits) {
-            return null;
-        } else if (toBits > 32) {
-            // sign extend to 64 bits
-            switch (fromBits) {
-                case 8:
-                    return emitConvert2MemoryOp(Kind.Long, B2L, access);
-                case 16:
-                    return emitConvert2MemoryOp(Kind.Long, S2L, access);
-                case 32:
-                    return emitConvert2MemoryOp(Kind.Long, I2L, access);
-                default:
-                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        } else {
-
-            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
-            switch (fromBits) {
-                case 8:
-                    return emitConvert2MemoryOp(Kind.Int, B2I, access);
-                case 16:
-                    return emitConvert2MemoryOp(Kind.Int, S2I, access);
-                case 32:
-                    return null;
-                default:
-                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        }
-    }
-
-    @Override
-    public Value emitNarrowMemory(int resultBits, Access access) {
-        // TODO
-        return null;
-    }
-
-    @Override
-    public Value emitZeroExtendMemory(int fromBits, int toBits, Access access) {
-        assert fromBits != toBits;
-        Kind memoryKind = getMemoryKind(access);
-        if (memoryKind.getBitCount() != fromBits && !memoryKind.isUnsigned()) {
-            // The memory being read from is signed and smaller than the result size so
-            // this is a sign extension to inputBits followed by a zero extension to resultBits
-            // which can't be expressed in a memory operation.
-            return null;
-        }
-        if (memoryKind == Kind.Short) {
-            memoryKind = Kind.Char;
-        }
-        evaluateDeferred();
-        return gen.getLIRGenerator().emitZeroExtendMemory(memoryKind, toBits, makeAddress(access), getState(access));
-    }
-
-    public boolean emitIfMemory(IfNode x, Access access) {
-        return emitBranchMemory(x.condition(), access, gen.getLIRBlock(x.trueSuccessor()), gen.getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
-    }
-
-    private boolean emitBranchMemory(LogicNode node, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        if (node instanceof IsNullNode) {
-            // can't do anything interesting.
-            return false;
-        } else if (node instanceof CompareNode) {
-            CompareNode compare = (CompareNode) node;
-            return emitCompareBranchMemory(compare, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else if (node instanceof LogicConstantNode) {
-            return false;
-        } else if (node instanceof IntegerTestNode) {
-            return emitIntegerTestBranchMemory((IntegerTestNode) node, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-        } else {
-            throw GraalInternalError.unimplemented(node.toString());
-        }
-    }
-
-    public boolean emitCompareBranchMemory(CompareNode compare, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        return emitCompareBranchMemory(compare.x(), compare.y(), access, compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    public boolean emitIntegerTestBranchMemory(IntegerTestNode test, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
-        return emitIntegerTestBranchMemory(test.x(), test.y(), access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
-    }
-
-    private boolean emitIntegerTestBranchMemory(ValueNode left, ValueNode right, Access access, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
-        ValueNode other = selectOtherInput(left, right, access);
-        Kind kind = getMemoryKind(access);
-        if (other.isConstant()) {
-            if (kind != kind.getStackKind()) {
-                return false;
-            }
-            Constant constant = other.asConstant();
-            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return false;
-            }
-            ensureEvaluated(other);
-            gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
-        } else {
-            evaluateDeferred();
-            gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), gen.operand(other), getState(access)));
-        }
-
-        gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
-        return true;
-    }
-
-    /**
-     * @return the input which is not equal to access, accounting for possible UnsafeCastNodes.
-     */
-    protected ValueNode selectOtherInput(ValueNode left, ValueNode right, Access access) {
-        assert uncast(left) == access || uncast(right) == access;
-        return uncast(left) == access ? right : left;
-    }
-
-    protected ValueNode uncast(ValueNode value) {
-        if (value instanceof UnsafeCastNode) {
-            UnsafeCastNode cast = (UnsafeCastNode) value;
-            return cast.getOriginalNode();
-        }
-        return value;
-    }
-
-    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
-                    double trueLabelProbability) {
-        ValueNode other = selectOtherInput(left, right, access);
-        Kind kind = getMemoryKind(access);
-        boolean mirrored = false;
-
-        if (other.isConstant()) {
-            Constant constant = other.asConstant();
-            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return false;
-            }
-            if (kind.isNumericFloat()) {
-                Debug.log("Skipping constant compares for float kinds");
-                return false;
-            }
-            if (kind == Kind.Object) {
-                if (!constant.isNull()) {
-                    Debug.log("Skipping constant compares for Object kinds");
-                    return false;
-                }
-            }
-            ensureEvaluated(other);
-            gen.getLIRGenerator().emitCompareMemoryConOp(kind, makeAddress(access), constant, getState(access));
-            mirrored = uncast(right) == access;
-        } else {
-            if (kind == Kind.Object) {
-                // Can't compare against objects since they require encode/decode
-                Debug.log("Skipping compares for Object kinds");
-                return false;
-            }
-
-            evaluateDeferred();
-            gen.getLIRGenerator().emitCompareRegMemoryOp(kind, gen.operand(other), makeAddress(access), getState(access));
-            mirrored = uncast(left) == access;
-        }
-
-        Condition finalCondition = mirrored ? cond.mirror() : cond;
-        switch (kind.getStackKind()) {
-            case Long:
-            case Int:
-            case Object:
-                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            case Float:
-            case Double:
-                gen.append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            default:
-                throw GraalInternalError.shouldNotReachHere("" + kind.getStackKind());
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -23,34 +23,31 @@
 
 package com.oracle.graal.compiler.amd64;
 
+import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
+
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.extended.*;
 
 public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
 
-    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         super(graph, gen);
     }
 
-    protected MemoryArithmeticLIRLowerer memoryPeephole;
-
-    @Override
-    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
-        if (memoryPeephole == null) {
-            // Use the generic one
-            memoryPeephole = new AMD64MemoryPeephole(this);
-        }
-        return memoryPeephole;
-    }
-
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
         AllocatableValue targetAddress = AMD64.rax.asValue();
@@ -91,6 +88,422 @@
         return false;
     }
 
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected Kind getMemoryKind(Access access) {
+        return (Kind) gen.getPlatformKind(access.asNode().stamp());
+    }
+
+    protected AMD64AddressValue makeAddress(Access access) {
+        return (AMD64AddressValue) access.accessLocation().generateAddress(this, gen, operand(access.object()));
+    }
+
+    protected ValueNode uncast(ValueNode value) {
+        if (value instanceof UnsafeCastNode) {
+            UnsafeCastNode cast = (UnsafeCastNode) value;
+            return cast.getOriginalNode();
+        }
+        return value;
+    }
+
+    protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
+        Condition cond = compare.condition();
+        Kind kind = getMemoryKind(access);
+
+        if (value.isConstant()) {
+            Constant constant = value.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            if (kind.isNumericFloat()) {
+                Debug.log("Skipping constant compares for float kinds");
+                return null;
+            }
+            if (kind == Kind.Object) {
+                if (!constant.isNull()) {
+                    Debug.log("Skipping constant compares for Object kinds");
+                    return null;
+                }
+            }
+        } else {
+            if (kind == Kind.Object) {
+                // Can't compare against objects since they require encode/decode
+                Debug.log("Skipping compares for Object kinds");
+                return null;
+            }
+        }
+
+        PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp());
+        if (cmpKind instanceof Kind) {
+            // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
+            // that's not true. It might be mirrored again the actual compare is emitted but that's
+            // ok.
+            Condition finalCondition = uncast(compare.x()) == access ? cond.mirror() : cond;
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+                    LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+                    boolean unorderedIsTrue = compare.unorderedIsTrue();
+                    double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+                    Value other;
+                    if (value.isConstant()) {
+                        other = value.asConstant();
+                    } else {
+                        other = operand(value);
+                    }
+
+                    getLIRGeneratorTool().emitCompareBranchMemory((Kind) cmpKind, other, makeAddress(access), getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel,
+                                    trueLabelProbability);
+                    return null;
+                }
+            };
+        }
+        return null;
+
+    }
+
+    private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
+        LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
+        double trueLabelProbability = x.probability(x.trueSuccessor());
+        Kind kind = getMemoryKind(access);
+        if (value.isConstant()) {
+            if (kind != kind.getStackKind()) {
+                return null;
+            }
+            Constant constant = value.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            return builder -> {
+                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        } else {
+            return builder -> {
+                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        }
+    }
+
+    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
+        AMD64AddressValue address = makeAddress(access);
+        LIRFrameState state = getState(access);
+        return getLIRGeneratorTool().emitConvert2MemoryOp(kind, op, address, state);
+    }
+
+    private Value emitFloatConvertMemory(FloatConvertNode op, Access access) {
+        switch (op.getOp()) {
+            case D2F:
+                return emitConvert2MemoryOp(Kind.Float, D2F, access);
+            case D2I:
+                return emitConvert2MemoryOp(Kind.Int, D2I, access);
+            case D2L:
+                return emitConvert2MemoryOp(Kind.Long, D2L, access);
+            case F2D:
+                return emitConvert2MemoryOp(Kind.Double, F2D, access);
+            case F2I:
+                return emitConvert2MemoryOp(Kind.Int, F2I, access);
+            case F2L:
+                return emitConvert2MemoryOp(Kind.Long, F2L, access);
+            case I2D:
+                return emitConvert2MemoryOp(Kind.Double, I2D, access);
+            case I2F:
+                return emitConvert2MemoryOp(Kind.Float, I2F, access);
+            case L2D:
+                return emitConvert2MemoryOp(Kind.Double, L2D, access);
+            case L2F:
+                return emitConvert2MemoryOp(Kind.Float, L2F, access);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        Kind kind = null;
+        AMD64Arithmetic op = null;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            kind = Kind.Long;
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    op = B2L;
+                    break;
+                case 16:
+                    op = S2L;
+                    break;
+                case 32:
+                    op = I2L;
+                    break;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+            kind = Kind.Int;
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    op = B2I;
+                    break;
+                case 16:
+                    op = S2I;
+                    break;
+                case 32:
+                    return null;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+        if (kind != null && op != null) {
+            Kind localKind = kind;
+            AMD64Arithmetic localOp = op;
+            return new ComplexMatchResult() {
+                public Value evaluate(NodeLIRBuilder builder) {
+                    return emitConvert2MemoryOp(localKind, localOp, access);
+                }
+            };
+        }
+        return null;
+    }
+
+    private Value emitReinterpretMemory(PlatformKind to, Access access) {
+        Kind from = getMemoryKind(access);
+        assert to != from : "should have been eliminated";
+
+        /*
+         * Conversions between integer to floating point types require moves between CPU and FPU
+         * registers.
+         */
+        switch ((Kind) to) {
+            case Int:
+                switch (from) {
+                    case Float:
+                        return emitConvert2MemoryOp(to, MOV_F2I, access);
+                }
+                break;
+            case Long:
+                switch (from) {
+                    case Double:
+                        return emitConvert2MemoryOp(to, MOV_D2L, access);
+                }
+                break;
+            case Float:
+                switch (from) {
+                    case Int:
+                        return emitConvert2MemoryOp(to, MOV_I2F, access);
+                }
+                break;
+            case Double:
+                switch (from) {
+                    case Long:
+                        return emitConvert2MemoryOp(to, MOV_L2D, access);
+                }
+                break;
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    private AMD64Arithmetic getOp(ValueNode operation, Access access) {
+        Kind memoryKind = getMemoryKind(access);
+        if (operation.getClass() == IntegerAddNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IADD;
+                case Long:
+                    return LADD;
+            }
+        } else if (operation.getClass() == FloatAddNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FADD;
+                case Double:
+                    return DADD;
+            }
+        } else if (operation.getClass() == AndNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IAND;
+                case Long:
+                    return LAND;
+            }
+        } else if (operation.getClass() == OrNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IOR;
+                case Long:
+                    return LOR;
+            }
+        } else if (operation.getClass() == XorNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IXOR;
+                case Long:
+                    return LXOR;
+            }
+        } else if (operation.getClass() == IntegerSubNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return ISUB;
+                case Long:
+                    return LSUB;
+            }
+        } else if (operation.getClass() == FloatSubNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FSUB;
+                case Double:
+                    return DSUB;
+            }
+        } else if (operation.getClass() == IntegerMulNode.class) {
+            switch (memoryKind) {
+                case Int:
+                    return IMUL;
+                case Long:
+                    return LMUL;
+            }
+        } else if (operation.getClass() == FloatMulNode.class) {
+            switch (memoryKind) {
+                case Float:
+                    return FMUL;
+                case Double:
+                    return DMUL;
+            }
+        }
+        return null;
+    }
+
+    @MatchRule("(If (IntegerTest Read=access value))")
+    @MatchRule("(If (IntegerTest FloatingRead=access value))")
+    public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
+        return emitIntegerTestBranchMemory(root, value, access);
+    }
+
+    @MatchRule("(If (IntegerEquals=compare value Read=access))")
+    @MatchRule("(If (IntegerLessThan=compare value Read=access))")
+    @MatchRule("(If (IntegerBelowThan=compare value Read=access))")
+    @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerBelowThan=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatEquals=compare value Read=access))")
+    @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatLessThan=compare value Read=access))")
+    @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
+    public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+        return emitCompareBranchMemory(root, compare, value, access);
+    }
+
+    @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
+    public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
+        if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(lshift.x()), operand(lshift.y()));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
+    public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
+        if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))")
+    public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
+        if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    @MatchRule("(IntegerAdd value Read=access)")
+    @MatchRule("(IntegerSub value Read=access)")
+    @MatchRule("(IntegerMul value Read=access)")
+    @MatchRule("(FloatAdd value Read=access)")
+    @MatchRule("(FloatSub value Read=access)")
+    @MatchRule("(FloatMul value Read=access)")
+    @MatchRule("(Or value Read=access)")
+    @MatchRule("(Xor value Read=access)")
+    @MatchRule("(And value Read=access)")
+    @MatchRule("(IntegerAdd value FloatingRead=access)")
+    @MatchRule("(IntegerSub value FloatingRead=access)")
+    @MatchRule("(IntegerMul value FloatingRead=access)")
+    @MatchRule("(FloatAdd value FloatingRead=access)")
+    @MatchRule("(FloatSub value FloatingRead=access)")
+    @MatchRule("(FloatMul value FloatingRead=access)")
+    @MatchRule("(Or value FloatingRead=access)")
+    @MatchRule("(Xor value FloatingRead=access)")
+    @MatchRule("(And value FloatingRead=access)")
+    public ComplexMatchResult binaryRead(BinaryNode root, ValueNode value, Access access) {
+        AMD64Arithmetic op = getOp(root, access);
+        if (op != null) {
+            return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access));
+        }
+        return null;
+    }
+
+    @MatchRule("(Write Narrow=narrow value)")
+    public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
+        return builder -> {
+            PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp());
+            Value address = root.location().generateAddress(builder, getLIRGeneratorTool(), operand(root.object()));
+            Value v = operand(narrow.getInput());
+            getLIRGeneratorTool().emitStore(writeKind, address, v, state(root));
+            return null;
+        };
+    }
+
+    @MatchRule("(SignExtend Read=access)")
+    @MatchRule("(SignExtend FloatingRead=access)")
+    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
+        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        Kind memoryKind = getMemoryKind(access);
+        if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) {
+            /*
+             * The memory being read from is signed and smaller than the result size so this is a
+             * sign extension to inputBits followed by a zero extension to resultBits which can't be
+             * expressed in a memory operation.
+             */
+            return null;
+        }
+        return builder -> getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), makeAddress(access), getState(access));
+    }
+
+    @MatchRule("(FloatConvert Read=access)")
+    @MatchRule("(FloatConvert FloatingRead=access)")
+    public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
+        return builder -> emitFloatConvertMemory(root, access);
+
+    }
+
+    @MatchRule("(Reinterpret Read=access)")
+    @MatchRule("(Reinterpret FloatingRead=access)")
+    public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
+        return builder -> {
+            PlatformKind kind = getLIRGeneratorTool().getPlatformKind(root.stamp());
+            return emitReinterpretMemory(kind, access);
+        };
+
+    }
+
     @Override
     public void visitBreakpointNode(BreakpointNode node) {
         JavaType[] sig = new JavaType[node.arguments().size()];
@@ -108,7 +521,7 @@
     }
 
     @Override
-    public AMD64LIRGenerator getLIRGenerator() {
+    public AMD64LIRGenerator getLIRGeneratorTool() {
         return (AMD64LIRGenerator) gen;
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Fri May 02 11:33:47 2014 +0200
@@ -187,6 +187,8 @@
 
     // Code generator settings
     @Option(help = "")
+    public static final OptionValue<Boolean> FlowSensitiveReduction = new OptionValue<>(false);
+    @Option(help = "")
     public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> UseProfilingInformation = new OptionValue<>(true);
@@ -272,7 +274,9 @@
     @Option(help = "")
     public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true);
     @Option(help = "Allow backend to emit arithmetic and compares directly against memory.")
-    public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(true);
+    public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(false);
+    @Option(help = "Allow backend to match complex expressions.")
+    public static final OptionValue<Boolean> MatchExpressions = new OptionValue<>(true);
 
 
     /**
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Fri May 02 11:33:47 2014 +0200
@@ -29,12 +29,11 @@
 import com.oracle.graal.compiler.common.spi.*;
 
 /**
- * Describes the possible values of a {@link ValueNode} that produces an int or long result.
+ * Describes the possible values of a node that produces an int or long result.
  *
  * The description consists of (inclusive) lower and upper bounds and up (may be set) and down
  * (always set) bit-masks.
  */
-@SuppressWarnings("javadoc")
 public class IntegerStamp extends PrimitiveStamp {
 
     private final long lowerBound;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Fri May 02 11:33:47 2014 +0200
@@ -23,9 +23,8 @@
 package com.oracle.graal.compiler.common.type;
 
 /**
- * Describes the possible values of a {@link ValueNode} that produces a primitive value as result.
+ * Type describing primitive values.
  */
-@SuppressWarnings("javadoc")
 public abstract class PrimitiveStamp extends Stamp {
 
     private final int bits;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Fri May 02 11:33:47 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.compiler.common.spi.*;
 
 /**
- * A stamp is the basis for a type system over the nodes in a graph.
+ * A stamp is the basis for a type system.
  */
 public abstract class Stamp {
 
@@ -57,13 +57,12 @@
     public abstract PlatformKind getPlatformKind(PlatformKindTool tool);
 
     /**
-     * Returns the union of this stamp and the given stamp. Typically used to create stamps for
-     * {@link ValuePhiNode}s.
+     * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi
+     * nodes.
      *
      * @param other The stamp that will enlarge this stamp.
      * @return The union of this stamp and the given stamp.
      */
-    @SuppressWarnings("javadoc")
     public abstract Stamp meet(Stamp other);
 
     /**
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java	Fri May 02 11:33:47 2014 +0200
@@ -27,13 +27,10 @@
 
 import org.junit.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.compiler.hsail.test.infra.*;
 
 /**
- * Tests {@link AtomicInteger#getAndAdd(int)} which indirectly tests
- * {@link Unsafe#compareAndSwapInt(Object, long, int, int)}.
+ * Tests {@link AtomicInteger#getAndAdd(int)} which tests HSAIL atomic_add codegen.
  */
 public class AtomicIntGetAndAddTest extends GraalKernelTester {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndSetTest.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests {@link AtomicInteger#getAndSet(int)} which tests HSAIL atomic_exch codegen.
+ */
+public class AtomicIntGetAndSetTest extends GraalKernelTester {
+
+    static final int NUM = 1000;
+    @Result public int[] outArray = new int[NUM];
+    AtomicInteger atomicInt = new AtomicInteger(Integer.MAX_VALUE);
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+        }
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchMethodKernel(NUM);
+        // to complete the circle, replace the initial get value with that of the last executor
+        for (int i = 0; i < NUM; i++) {
+            if (outArray[i] == Integer.MAX_VALUE) {
+                outArray[i] = atomicInt.get();
+            }
+        }
+
+        // note: the actual order of entries in outArray is not predictable
+        // thus we sort before we compare results
+        Arrays.sort(outArray);
+    }
+
+    public void run(int gid) {
+        outArray[gid] = atomicInt.getAndSet(gid);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java	Fri May 02 11:33:47 2014 +0200
@@ -27,13 +27,10 @@
 
 import org.junit.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.compiler.hsail.test.infra.*;
 
 /**
- * Tests {@link AtomicLong#getAndAdd(long)} which indirectly tests
- * {@link Unsafe#compareAndSwapLong(Object, long, long, long)}.
+ * Tests {@link AtomicLong#getAndAdd(long)} which tests HSAIL atomic_add codegen.
  */
 public class AtomicLongGetAndAddTest extends GraalKernelTester {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndSetTest.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests {@link AtomicLong#getAndSet(long)} which tests HSAIL atomic_exch codegen.
+ */
+public class AtomicLongGetAndSetTest extends GraalKernelTester {
+
+    static final int NUM = 1000;
+    @Result public long[] outArray = new long[NUM];
+    AtomicLong atomicLong = new AtomicLong(Long.MAX_VALUE);
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            outArray[i] = -i;
+        }
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+
+        dispatchMethodKernel(NUM);
+        // to complete the circle, replace the initial get value with that of the last executor
+        for (int i = 0; i < NUM; i++) {
+            if (outArray[i] == Long.MAX_VALUE) {
+                outArray[i] = atomicLong.get();
+            }
+        }
+
+        // note: the actual order of entries in outArray is not predictable
+        // thus we sort before we compare results
+        Arrays.sort(outArray);
+    }
+
+    public void run(int gid) {
+        outArray[gid] = atomicLong.getAndSet(gid);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicReferenceGetAndSetTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicReferenceGetAndSetTest.java	Fri May 02 11:33:47 2014 +0200
@@ -96,7 +96,6 @@
     }
 
     @Test
-    @Ignore
     public void test() {
         testGeneratedHsail();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java	Fri May 02 11:33:47 2014 +0200
@@ -118,9 +118,8 @@
         dispatchMethodKernel(size, out, in);
     }
 
-    // Marked to only run on hardware until simulator spill bug is fixed.
-    @Ignore
     @Test
+    @Ignore("until stack slots are supported in deopt")
     public void test() {
         testGeneratedHsail();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java	Fri May 02 11:33:47 2014 +0200
@@ -87,9 +87,8 @@
         dispatchMethodKernel(size, out, in);
     }
 
-    // Marked to only run on hardware until simulator spill bug is fixed.
-    @Ignore
     @Test
+    @Ignore("until stack slots are supported in deopt")
     public void test() {
         testGeneratedHsail();
     }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Fri May 02 11:33:47 2014 +0200
@@ -25,11 +25,11 @@
 
 import static com.oracle.graal.debug.Debug.*;
 
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
 import com.oracle.graal.debug.*;
 
-import org.junit.Test;
-
 /**
  * Tests creating a String and calling .equals() on it.
  */
@@ -64,14 +64,16 @@
     }
 
     // NYI emitForeignCall charAlignedDisjointArraycopy
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsail();
         }
     }
 
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void testUsingLambdaMethod() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java	Fri May 02 11:33:47 2014 +0200
@@ -26,12 +26,12 @@
 import static com.oracle.graal.debug.Debug.*;
 import static com.oracle.graal.debug.DelegatingDebugConfig.Feature.*;
 
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import com.oracle.graal.debug.*;
+import java.util.*;
 
-import org.junit.Test;
+import org.junit.*;
 
-import java.util.Arrays;
+import com.oracle.graal.compiler.hsail.test.infra.*;
+import com.oracle.graal.debug.*;
 
 /**
  * Tests non-escaping object creation and calling a method on it.
@@ -78,14 +78,16 @@
     }
 
     // NYI emitForeignCall floatArraycopy
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void test() {
         try (DebugConfigScope s = disableIntercept()) {
             testGeneratedHsail();
         }
     }
 
-    @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+    @Ignore
+    @Test
     public void testUsingLambdaMethod() {
         try (DebugConfigScope dcs = setConfig(new DelegatingDebugConfig().disable(INTERCEPT))) {
             testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -37,7 +37,7 @@
  */
 public abstract class HSAILNodeLIRBuilder extends NodeLIRBuilder {
 
-    public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -56,7 +56,7 @@
         }
     }
 
-    public PTXNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public PTXNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -27,7 +27,9 @@
 import static com.oracle.graal.lir.sparc.SPARCArithmetic.*;
 import static com.oracle.graal.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.sparc.SPARCCompare.*;
+import static com.oracle.graal.lir.sparc.SPARCControlFlow.*;
 import static com.oracle.graal.lir.sparc.SPARCMathIntrinsicOp.IntrinsicOpcode.*;
+import static com.oracle.graal.lir.sparc.SPARCMove.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -40,25 +42,6 @@
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryCommutative;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegConst;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegReg;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Op1Stack;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Op2Stack;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.RemOp;
-import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op;
-import com.oracle.graal.lir.sparc.SPARCCompare.CompareOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.BranchOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.FloatCondMoveOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
-import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
-import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -129,7 +112,7 @@
 
     @Override
     public void emitData(AllocatableValue dst, byte[] data) {
-        throw GraalInternalError.unimplemented();
+        append(new LoadDataAddressOp(dst, data));
     }
 
     @Override
@@ -156,7 +139,7 @@
                 indexRegister = Value.ILLEGAL;
             } else {
                 if (scale != 1) {
-                    Value longIndex = emitSignExtend(index, 32, 64);
+                    Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64);
                     if (CodeUtil.isPowerOf2(scale)) {
                         indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale)));
                     } else {
@@ -184,16 +167,20 @@
         // If we don't have an index register we can use a displacement, otherwise load the
         // displacement into a register and add it to the base.
         if (indexRegister.equals(Value.ILLEGAL)) {
-            // TODO What if displacement if too big?
             displacementInt = (int) finalDisp;
+            assert SPARCAssembler.isSimm13(displacementInt) : displacementInt;
         } else {
             displacementInt = 0;
             if (baseRegister.equals(Value.ILLEGAL)) {
                 baseRegister = load(Constant.forLong(finalDisp));
             } else {
-                Variable longBaseRegister = newVariable(Kind.Long);
-                emitMove(longBaseRegister, baseRegister);  // FIXME get rid of this move
-                baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp));
+                if (finalDisp == 0) {
+                    // Nothing to do. Just use the base register.
+                } else {
+                    Variable longBaseRegister = newVariable(Kind.Long);
+                    emitMove(longBaseRegister, baseRegister);
+                    baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp));
+                }
             }
         }
 
@@ -282,15 +269,16 @@
         Condition finalCondition = mirrored ? cond.mirror() : cond;
 
         Variable result = newVariable(trueValue.getKind());
-        switch (left.getKind().getStackKind()) {
+        Kind kind = left.getKind().getStackKind();
+        switch (kind) {
             case Int:
             case Long:
             case Object:
-                append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
+                append(new CondMoveOp(kind, result, finalCondition, load(trueValue), loadNonConst(falseValue)));
                 break;
             case Float:
             case Double:
-                append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
+                append(new FloatCondMoveOp(kind, result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere("" + left.getKind());
@@ -345,7 +333,8 @@
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
         emitIntegerTest(left, right);
         Variable result = newVariable(trueValue.getKind());
-        append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
+        Kind kind = left.getKind().getStackKind();
+        append(new CondMoveOp(kind, result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
         return result;
     }
 
@@ -811,22 +800,23 @@
             return inputVal;
         } else if (toBits > 32) {
             // sign extend to 64 bits
-            if (fromBits == 32) {
-                return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
-            } else if (fromBits < 32) {
-                // TODO implement direct x2L sign extension conversions
-                Value intVal = emitSignExtend(inputVal, fromBits, 32);
-                return emitSignExtend(intVal, 32, toBits);
-            } else {
-                throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            switch (fromBits) {
+                case 8:
+                    return emitConvert2Op(Kind.Long, B2L, asAllocatable(inputVal));
+                case 16:
+                    return emitConvert2Op(Kind.Long, S2L, asAllocatable(inputVal));
+                case 32:
+                    return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal));
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
         } else {
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(Kind.Int, I2B, asAllocatable(inputVal));
+                    return emitConvert2Op(Kind.Int, B2I, asAllocatable(inputVal));
                 case 16:
-                    return emitConvert2Op(Kind.Int, I2S, asAllocatable(inputVal));
+                    return emitConvert2Op(Kind.Int, S2I, asAllocatable(inputVal));
                 case 32:
                     return inputVal;
                 default:
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -37,7 +37,7 @@
  */
 public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder {
 
-    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri May 02 11:33:47 2014 +0200
@@ -52,7 +52,7 @@
  */
 public class CheckGraalInvariants extends GraalTest {
 
-    @LongTest
+    @Test
     public void test() {
         RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
         Providers providers = rt.getHostBackend().getProviders();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri May 02 11:33:47 2014 +0200
@@ -22,23 +22,16 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.nodes.ConstantNode.*;
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static org.junit.Assert.*;
-
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
 /**
- * Collection of tests for {@link ConditionalEliminationPhase} including those that triggered bugs
- * in this phase.
+ * Collection of tests for {@link com.oracle.graal.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest extends GraalCompilerTest {
 
@@ -88,174 +81,6 @@
         } while (true);
     }
 
-    /**
-     * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast
-     * caused an enclosing instanceof (for the same object and target type) to be incorrectly
-     * eliminated.
-     */
-    @Test
-    public void testReanchoringIssue() {
-        Entry end = new Entry("end");
-        EntryWithNext e1 = new EntryWithNext("e1", end);
-        EntryWithNext e2 = new EntryWithNext("e2", e1);
-
-        test("search", e2, "e3", new Entry("e4"));
-    }
-
-    @SuppressWarnings("unused")
-    public static int testNullnessSnippet(Object a, Object b) {
-        if (a == null) {
-            if (a == b) {
-                if (b == null) {
-                    return 1;
-                } else {
-                    return -2;
-                }
-            } else {
-                if (b == null) {
-                    return -3;
-                } else {
-                    return 4;
-                }
-            }
-        } else {
-            if (a == b) {
-                if (b == null) {
-                    return -5;
-                } else {
-                    return 6;
-                }
-            } else {
-                if (b == null) {
-                    return 7;
-                } else {
-                    return 8;
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testNullness() {
-        test("testNullnessSnippet", null, null);
-        test("testNullnessSnippet", null, new Object());
-        test("testNullnessSnippet", new Object(), null);
-        test("testNullnessSnippet", new Object(), new Object());
-
-        StructuredGraph graph = parse("testNullnessSnippet");
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public static int testDisjunctionSnippet(Object a) {
-        try {
-            if (a instanceof Integer) {
-                if (a == null) {
-                    return -1;
-                } else {
-                    return 2;
-                }
-            } else {
-                return 3;
-            }
-        } finally {
-            field = null;
-        }
-    }
-
-    @Test
-    public void testDisjunction() {
-        StructuredGraph graph = parse("testDisjunctionSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        IfNode ifNode = (IfNode) graph.start().next();
-        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition();
-        IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0)));
-        InstanceOfNode y = instanceOf;
-        ShortCircuitOrNode disjunction = graph.unique(new ShortCircuitOrNode(x, false, y, false, NOT_FREQUENT_PROBABILITY));
-        LogicNegationNode negation = graph.unique(new LogicNegationNode(disjunction));
-        ifNode.setCondition(negation);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : getConstantNodes(graph)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
-                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
-            }
-        }
-    }
-
-    public static int testInvokeSnippet(Number n) {
-        if (n instanceof Integer) {
-            return n.intValue();
-        } else {
-            return 1;
-        }
-    }
-
-    @Test
-    public void testInvoke() {
-        test("testInvokeSnippet", new Integer(16));
-        StructuredGraph graph = parse("testInvokeSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-
-        InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
-        assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
-    }
-
-    public static void testTypeMergingSnippet(Object o, boolean b) {
-        if (b) {
-            if (!(o instanceof Double)) {
-                return;
-            }
-        } else {
-            if (!(o instanceof Integer)) {
-                return;
-            }
-        }
-
-        /*
-         * For this test the conditional elimination has to correctly merge the type information it
-         * has about o, so that it can remove the check on Number.
-         */
-        if (!(o instanceof Number)) {
-            field = o;
-        }
-    }
-
-    @Test
-    public void testTypeMerging() {
-        StructuredGraph graph = parse("testTypeMergingSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-
-        assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
-    }
-
-    public static String testInstanceOfCheckCastSnippet(Object e) {
-        if (e instanceof Entry) {
-            return ((Entry) e).name;
-        }
-        return null;
-    }
-
-    @Test
-    public void testInstanceOfCheckCast() {
-        StructuredGraph graph = parse("testInstanceOfCheckCastSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-
-        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
-    }
-
     public static int testRedundantComparesSnippet(int[] array) {
         if (array == null) {
             return 0;
@@ -272,39 +97,17 @@
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
         new FloatingReadPhase().apply(graph);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
         canonicalizer.apply(graph, context);
 
         assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
     }
 
-    public static int testDuplicateNullChecksSnippet(Object a) {
-        if (a == null) {
-            return 2;
-        }
-        try {
-            return ((Integer) a).intValue();
-        } catch (ClassCastException e) {
-            return 0;
+    public static String testInstanceOfCheckCastSnippet(Object e) {
+        if (e instanceof Entry) {
+            return ((Entry) e).name;
         }
-    }
-
-    @Test
-    @Ignore
-    public void testDuplicateNullChecks() {
-        // This tests whether explicit null checks properly eliminate later null guards. Currently
-        // it's failing.
-        StructuredGraph graph = parse("testDuplicateNullChecksSnippet");
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        PhaseContext context = new PhaseContext(getProviders(), null);
-
-        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
-        canonicalizer.apply(graph, context);
-        new FloatingReadPhase().apply(graph);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        canonicalizer.apply(graph, context);
-
-        assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+        return null;
     }
 
     @Test
@@ -317,9 +120,10 @@
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context);
         canonicalizer.apply(graph, context);
 
         assertEquals(0, graph.getNodes().filter(GuardNode.class).count());
     }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugConfig;
+import com.oracle.graal.debug.DebugConfigScope;
+import com.oracle.graal.debug.internal.DebugScope;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Tests whether {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} actually
+ * performs some graph rewritings that it's supposed to perform.
+ */
+public class FlowSenReduTest extends GraalCompilerTest {
+
+    /*
+     * A previous instanceof makes redundant a follow-up checkcast.
+     */
+    public Object redundantCheckCastSnippet(Number o) {
+        Integer z = null;
+        if (o instanceof Integer) {
+            z = (Integer) o; // this CheckCastNode will be removed
+        }
+        return z;
+    }
+
+    static final Integer i7 = new Integer(7);
+
+    @Test
+    public void redundantCheckCastTest() {
+        assertEquals(i7, redundantCheckCastSnippet(i7));
+        StructuredGraph result = afterFlowSensitiveReduce("redundantCheckCastSnippet");
+        nodeCountEquals(result, CheckCastNode.class, 0);
+        nodeCountEquals(result, InstanceOfNode.class, 1);
+    }
+
+    @SuppressWarnings("unused")
+    public boolean redundantInstanceOfSnippet01(Object o) {
+        if (o != null) {
+            Integer x = (Integer) o;
+            return (o instanceof Number); // this InstanceOfNode will be removed
+        }
+        return false;
+    }
+
+    @Test
+    public void redundantInstanceOfTest01() {
+        String snippet = "redundantInstanceOfSnippet01";
+        assertEquals(true, redundantInstanceOfSnippet01(i7));
+        nodeCountEquals(afterFlowSensitiveReduce(snippet), InstanceOfNode.class, 1);
+    }
+
+    /*
+     * The combination of (previous) non-null-check and checkcast make redundant an instanceof.
+     */
+    @SuppressWarnings("unused")
+    public Object redundantInstanceOfSnippet02(Object o) {
+        Integer x = (Integer) o;
+        if (o != null) {
+            if (o instanceof Number) { // this InstanceOfNode will be removed
+                return o;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void redundantInstanceOfTest02() {
+        String snippet = "redundantInstanceOfSnippet02";
+        assertEquals(i7, redundantInstanceOfSnippet02(i7));
+        int ioAfter = getNodes(afterFlowSensitiveReduce(snippet), InstanceOfNode.class).size();
+        assertEquals(ioAfter, 1);
+    }
+
+    /*
+     * Once an exact-type has been inferred (due to instanceof final-class) a callsite is
+     * devirtualized.
+     */
+    public int devirtualizationSnippet(Object x, Object y) {
+        boolean c = x instanceof Integer;
+        if (c && x == y) {
+            Number z = (Number) y; // this CheckCastNode will be removed
+            return z.intValue(); // devirtualized into InvokeSpecial on Integer.intValue()
+        }
+        return 0;
+    }
+
+    @Test
+    public void devirtualizationTest() {
+        String snippet = "devirtualizationSnippet";
+        assertEquals(i7, devirtualizationSnippet(i7, i7));
+        nodeCountEquals(afterFlowSensitiveReduce(snippet), CheckCastNode.class, 0);
+
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+
+        List<InvokeNode> invokeNodes = getNodes(afterFlowSensitiveReduce(snippet), InvokeNode.class);
+        assertEquals(1, invokeNodes.size());
+
+        MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
+        assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+        assertEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString());
+    }
+
+    /*
+     * At the return statement, the returned value has been inferred to have type j.l.Number. The
+     * instanceof is deemed to always evaluate to false. The interplay with tail-duplication is also
+     * taken into account (resulting in two return statements, each with "false" as input).
+     */
+    @SuppressWarnings("unused")
+    public boolean t5Snippet(Object o, boolean b) {
+        Number z;
+        if (b) {
+            z = (Number) o; // tail duplication of return stmt, which becomes "return false"
+        } else {
+            z = (Integer) o; // tail duplication of return stmt, which becomes "return false"
+        }
+        return o instanceof String; // unreachable
+    }
+
+    @Test
+    public void t5a() {
+        String snippet = "t5Snippet";
+        assertEquals(false, t5Snippet(null, true));
+        StructuredGraph resultGraph = canonicalize(afterFlowSensitiveReduce(snippet));
+        nodeCountEquals(resultGraph, ReturnNode.class, 2);
+
+        List<ReturnNode> returnNodes = getNodes(resultGraph, ReturnNode.class);
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ConstantNode c1 = (ConstantNode) iter.next().result();
+        ConstantNode c2 = (ConstantNode) iter.next().result();
+
+        assertEquals(c1, c2);
+        assertEquals(0, c1.getValue().asInt());
+    }
+
+    @Test
+    public void t5b() {
+        String snippet = "t5Snippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        nodeCountEquals(graph, InstanceOfNode.class, 2);
+    }
+
+    public boolean t6Snippet(Object x, Object y) {
+        if (!(x instanceof String)) {
+            return false;
+        }
+        if (!(y instanceof Number)) {
+            return false;
+        }
+        return x == y; // two known-not-to-conform reference values can't be ==
+    }
+
+    // TODO: two known-not-to-conform reference values can't be ==
+    // but baseCaseObjectEqualsNode doesn't check that as of now.
+    public void t6() {
+        String snippet = "t6Snippet";
+        // visualize(snippet);
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        nodeCountEquals(graph, ObjectEqualsNode.class, 0);
+    }
+
+    /*
+     * A previous instanceof check causes a follow-up instanceof to be deemed unsatisfiable,
+     * resulting in constant-substitution at that usage.
+     */
+    public Object t7Snippet(Object o) {
+        if (o instanceof Number) {
+            if (o instanceof String) { // condition amounts to false
+                return o; // made unreachable
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void t7() {
+        String snippet = "t7Snippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        graph = dce(canonicalize(graph));
+        // TODO how to simplify IfNode(false)
+        assertEquals(1, getNodes(graph, InstanceOfNode.class).size());
+
+        List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class);
+        assertEquals(2, returnNodes.size());
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ConstantNode c1 = (ConstantNode) iter.next().result();
+        ConstantNode c2 = (ConstantNode) iter.next().result();
+
+        assertEquals(c1, c2);
+        Assert.assertTrue(c1.getValue().isNull());
+    }
+
+    /*
+     * During FlowSensitiveReduction, an unreachable branch doesn't contribute to the merged state.
+     * The resulting ("non-polluted") more precise inferred type after the merge allows
+     * devirtualizing a callsite.
+     */
+    public int devirtualizationSnippet02(Number o) {
+        if (o instanceof Integer) {
+            Number z = o;
+            if (o instanceof Long) {
+                z = o;
+            }
+            /*
+             * devirtualized into InvokeSpecial on Integer.intValue() ie the inferred-type is not
+             * polluted with values from the unreachable branch.
+             */
+            return z.intValue();
+        }
+        return 0;
+    }
+
+    @Test
+    public void devirtualizationTest02() {
+        String snippet = "devirtualizationSnippet02";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+
+        assertEquals(1, getNodes(graph, InvokeNode.class).size());
+
+        List<InvokeNode> invokeNodes = getNodes(graph, InvokeNode.class);
+        assertEquals(1, invokeNodes.size());
+
+        MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget();
+        assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind());
+        assertEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString());
+    }
+
+    /*
+     * TODO ClassCastException known to fail --- either Deopt or throw ObjectGetClassNode The latter
+     * might lead to direct jump to EH if present.
+     */
+    @SuppressWarnings("unused")
+    public int t9Snippet(Object o) {
+        try {
+            if (o instanceof Number) {
+                String s = (String) o;
+                /*
+                 * make a long story short: replace the above with throw new ClassCastException (ok,
+                 * actual type of o unknown).
+                 */
+                return 1;
+            }
+        } catch (ClassCastException e) {
+            return 2;
+        }
+        return 3;
+    }
+
+    /*
+     * "Partial evaluation" via canonicalization of an expression (in the last return statement) one
+     * of whose leaf sub-expressions was determined to be constant.
+     */
+    @SuppressWarnings("unused")
+    public Object partialEvalSnippet01(Object o, boolean b) {
+        if (o == null) {
+            return o; // turned into "return null;"
+        } else {
+            Number z;
+            if (b) {
+                z = (Number) o;
+            } else {
+                z = (Integer) o;
+            }
+            return o instanceof String ? this : null; // turned into "return null;"
+        }
+    }
+
+    @Test
+    public void partialEvalTest01() {
+        String snippet = "partialEvalSnippet01";
+
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        canonicalize(graph);
+        dce(graph);
+
+        List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class);
+        assertEquals(2, returnNodes.size());
+        Iterator<ReturnNode> iter = returnNodes.iterator();
+
+        ValueNode c1 = GraphUtil.unproxify(iter.next().result());
+        ValueNode c2 = GraphUtil.unproxify(iter.next().result());
+        assert !iter.hasNext();
+
+        Assert.assertTrue(c1.isNullConstant());
+        Assert.assertTrue(c2.isNullConstant());
+    }
+
+    public static class C {
+        public int f;
+    }
+
+    /*
+     * A previous (assumed successful) instanceof check is reused later on to remove a checkcast.
+     */
+    public void deduplicateInstanceOfSnippet(Object o) {
+        ((C) o).f = ((C) o).f; // boils down to a single instanceof test
+    }
+
+    @Test
+    public void deduplicateInstanceOfTest() {
+        String snippet = "deduplicateInstanceOfSnippet";
+        StructuredGraph graph = afterFlowSensitiveReduce(snippet);
+        List<InstanceOfNode> ioNodes = getNodes(graph, InstanceOfNode.class);
+        assertEquals(1, ioNodes.size());
+
+    }
+
+    // ---------------------------------------------
+    // ----------------- UTILITIES -----------------
+    // ---------------------------------------------
+
+    private PhaseContext getPhaseContext() {
+        return new PhaseContext(getProviders(), null);
+    }
+
+    private static StructuredGraph dce(StructuredGraph graph) {
+        new DeadCodeEliminationPhase().apply(graph);
+        return graph;
+    }
+
+    private StructuredGraph canonicalize(StructuredGraph graph) {
+        new CanonicalizerPhase(true).apply(graph, getPhaseContext());
+        return graph;
+    }
+
+    private StructuredGraph flowSensitiveReduce(StructuredGraph graph) {
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, getPhaseContext());
+        return graph;
+    }
+
+    public static <N extends Node> List<N> getNodes(StructuredGraph graph, Class<N> nodeClass) {
+        return graph.getNodes().filter(nodeClass).snapshot();
+    }
+
+    public <N extends Node> void nodeCountEquals(StructuredGraph graph, Class<N> nodeClass, int expected) {
+        assertEquals(expected, getNodes(graph, nodeClass).size());
+    }
+
+    public StructuredGraph afterFlowSensitiveReduce(String snippet) {
+        StructuredGraph before = canonicalize(parse(snippet));
+        // visualize(before, snippet + "-before");
+        StructuredGraph result = flowSensitiveReduce(before);
+        // visualize(result, snippet + "-after");
+        return result;
+    }
+
+    public StructuredGraph visualize(StructuredGraph graph, String title) {
+        DebugConfig debugConfig = DebugScope.getConfig();
+        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+        try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+            Debug.dump(graph, title);
+
+            return graph;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import static com.oracle.graal.nodes.ConstantNode.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
+import static org.junit.Assert.*;
+
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+
+/**
+ * Collection of tests for {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase}
+ * including those that triggered bugs in this phase.
+ */
+public class FlowSensitiveReductionTest extends GraalCompilerTest {
+
+    public static Object field;
+
+    static class Entry {
+
+        final String name;
+
+        public Entry(String name) {
+            this.name = name;
+        }
+    }
+
+    static class EntryWithNext extends Entry {
+
+        public EntryWithNext(String name, Entry next) {
+            super(name);
+            this.next = next;
+        }
+
+        final Entry next;
+    }
+
+    public static Entry search(Entry start, String name, Entry alternative) {
+        Entry current = start;
+        do {
+            while (current instanceof EntryWithNext) {
+                if (name != null && current.name == name) {
+                    current = null;
+                } else {
+                    Entry next = ((EntryWithNext) current).next;
+                    current = next;
+                }
+            }
+
+            if (current != null) {
+                if (current.name.equals(name)) {
+                    return current;
+                }
+            }
+            if (current == alternative) {
+                return null;
+            }
+            current = alternative;
+
+        } while (true);
+    }
+
+    /**
+     * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast
+     * caused an enclosing instanceof (for the same object and target type) to be incorrectly
+     * eliminated.
+     */
+    @Test
+    public void testReanchoringIssue() {
+        Entry end = new Entry("end");
+        EntryWithNext e1 = new EntryWithNext("e1", end);
+        EntryWithNext e2 = new EntryWithNext("e2", e1);
+
+        test("search", e2, "e3", new Entry("e4"));
+    }
+
+    @SuppressWarnings("unused")
+    public static int testNullnessSnippet(Object a, Object b) {
+        if (a == null) {
+            if (a == b) {
+                if (b == null) {
+                    return 1;
+                } else {
+                    return -2;
+                }
+            } else {
+                if (b == null) {
+                    return -3;
+                } else {
+                    return 4;
+                }
+            }
+        } else {
+            if (a == b) {
+                if (b == null) {
+                    return -5;
+                } else {
+                    return 6;
+                }
+            } else {
+                if (b == null) {
+                    return 7;
+                } else {
+                    return 8;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testNullness() {
+        test("testNullnessSnippet", null, null);
+        test("testNullnessSnippet", null, new Object());
+        test("testNullnessSnippet", new Object(), null);
+        test("testNullnessSnippet", new Object(), new Object());
+
+        StructuredGraph graph = parse("testNullnessSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, context);
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static int testDisjunctionSnippet(Object a) {
+        try {
+            if (a instanceof Integer) {
+                if (a == null) {
+                    return -1;
+                } else {
+                    return 2;
+                }
+            } else {
+                return 3;
+            }
+        } finally {
+            field = null;
+        }
+    }
+
+    @Test
+    public void testDisjunction() {
+        StructuredGraph graph = parse("testDisjunctionSnippet");
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        IfNode ifNode = (IfNode) graph.start().next();
+        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition();
+        IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0)));
+        InstanceOfNode y = instanceOf;
+        ShortCircuitOrNode disjunction = graph.unique(new ShortCircuitOrNode(x, false, y, false, NOT_FREQUENT_PROBABILITY));
+        LogicNegationNode negation = graph.unique(new LogicNegationNode(disjunction));
+        ifNode.setCondition(negation);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), null));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
+                assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
+            }
+        }
+    }
+
+    public static int testInvokeSnippet(Number n) {
+        if (n instanceof Integer) {
+            return n.intValue();
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testInvoke() {
+        test("testInvokeSnippet", new Integer(16));
+        StructuredGraph graph = parse("testInvokeSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+
+        InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first();
+        assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
+    }
+
+    public static void testTypeMergingSnippet(Object o, boolean b) {
+        if (b) {
+            if (!(o instanceof Double)) {
+                return;
+            }
+        } else {
+            if (!(o instanceof Integer)) {
+                return;
+            }
+        }
+
+        /*
+         * For this test the conditional elimination has to correctly merge the type information it
+         * has about o, so that it can remove the check on Number.
+         */
+        if (!(o instanceof Number)) {
+            field = o;
+        }
+    }
+
+    @Test
+    public void testTypeMerging() {
+        StructuredGraph graph = parse("testTypeMergingSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+
+        assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
+    }
+
+    public static String testInstanceOfCheckCastSnippet(Object e) {
+        if (e instanceof Entry) {
+            return ((Entry) e).name;
+        }
+        return null;
+    }
+
+    @Test
+    public void testInstanceOfCheckCast() {
+        StructuredGraph graph = parse("testInstanceOfCheckCastSnippet");
+        PhaseContext context = new PhaseContext(getProviders(), null);
+        new CanonicalizerPhase(true).apply(graph, context);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+
+        assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count());
+    }
+
+    public static int testDuplicateNullChecksSnippet(Object a) {
+        if (a == null) {
+            return 2;
+        }
+        try {
+            return ((Integer) a).intValue();
+        } catch (ClassCastException e) {
+            return 0;
+        }
+    }
+
+    @Test
+    @Ignore
+    public void testDuplicateNullChecks() {
+        // This tests whether explicit null checks properly eliminate later null guards. Currently
+        // it's failing.
+        StructuredGraph graph = parse("testDuplicateNullChecksSnippet");
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        PhaseContext context = new PhaseContext(getProviders(), null);
+
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        new FloatingReadPhase().apply(graph);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Fri May 02 11:33:47 2014 +0200
@@ -39,7 +39,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 /**
  * Test that infopoints in {@link CompilationResult}s have correctly assigned reasons.
@@ -72,7 +71,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void lineInfopoints() {
         final Method method = getMethod("testMethod");
         final StructuredGraph graph = parseDebug(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Fri May 02 11:33:47 2014 +0200
@@ -53,7 +53,7 @@
  * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the
  * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the
  * right thing.
- * 
+ *
  * The scheduling shouldn't depend on FrameStates, which is tested by this class.
  */
 public class MemoryScheduleTest extends GraphScheduleTest {
@@ -247,7 +247,7 @@
     @Test
     public void testLoop5() {
         SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertEquals(10, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -266,7 +266,7 @@
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
         assertEquals(1, graph.getNodes(ReturnNode.class).count());
         ReturnNode ret = graph.getNodes(ReturnNode.class).first();
-        assertTrue(ret.result() instanceof FloatingReadNode);
+        assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode);
         assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -585,7 +585,7 @@
     private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final MemoryScheduling memsched, final SchedulingStrategy schedulingStrategy) {
         final StructuredGraph graph = parse(snippet);
         try (Scope d = Debug.scope("FloatingReadTest", graph)) {
-            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS)) {
+            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
                 Assumptions assumptions = new Assumptions(false);
                 HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Fri May 02 11:33:47 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.test;
 
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -167,8 +168,9 @@
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        PhaseContext context = new PhaseContext(getProviders(), assumptions);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, context);
         StructuredGraph referenceGraph = parse(referenceSnippet);
         assertEquals(referenceGraph, graph);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Fri May 02 11:33:47 2014 +0200
@@ -24,6 +24,7 @@
 
 import java.io.*;
 
+import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -184,7 +185,12 @@
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         Assumptions assumptions = new Assumptions(false);
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        /*
+         * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase,
+         * tail-duplication gets activated thus resulting in a graph with more nodes than the
+         * reference graph.
+         */
+        new ConditionalEliminationPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
         // a second canonicalizer is needed to process nested MaterializeNodes
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
@@ -239,7 +245,7 @@
         StructuredGraph graph = parse(snippet);
         Assumptions assumptions = new Assumptions(false);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
-        new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
+        new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
         Debug.dump(graph, "Graph " + snippet);
         Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri May 02 11:33:47 2014 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant
@@ -51,7 +50,7 @@
         return f1 + " " + arg1 + " " + arg2 + " " + arg3;
     }
 
-    @LongTest
+    @Test
     public void test1() {
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
@@ -74,7 +73,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test3() {
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
@@ -88,7 +87,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test4() {
         Method method = getMethod("testMethodVirtual");
         final StructuredGraph graph = parse(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Fri May 02 11:33:47 2014 +0200
@@ -38,7 +38,6 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.test.*;
 
 public class InliningTest extends GraalCompilerTest {
 
@@ -73,7 +72,7 @@
         assertInlined(getGraph("invokeMethodOnFieldSnippet", false));
     }
 
-    @LongTest
+    @Test
     public void testStaticBindableInliningIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true)));
@@ -82,7 +81,7 @@
     }
 
     @Ignore("would need read elimination/EA before inlining")
-    @LongTest
+    @Test
     public void testDependentStaticBindableInliningIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFieldSnippet", true)));
@@ -180,7 +179,7 @@
         assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false));
     }
 
-    @LongTest
+    @Test
     public void testClassHierarchyAnalysisIP() {
         assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true)));
         assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true)));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/META-INF/services/javax.annotation.processing.Processor	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,1 @@
+com.oracle.graal.compiler.match.MatchProcessor
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 02 11:33:47 2014 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.alloc.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -45,6 +44,7 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
@@ -208,7 +208,7 @@
         }
     }
 
-    private static void emitBlock(NodeLIRBuilder nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
+    private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) {
         if (lirGenRes.getLIR().getLIRforBlock(b) == null) {
             for (Block pred : b.getPredecessors()) {
                 if (!b.isLoopHeader() || !pred.isLoopEnd()) {
@@ -246,8 +246,8 @@
         try (Scope ds = Debug.scope("BackEnd", lir)) {
             FrameMap frameMap = backend.newFrameMap(registerConfig);
             LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMap, stub);
-            LIRGenerator lirGen = backend.newLIRGenerator(cc, lirGenRes);
-            NodeLIRBuilder nodeLirGen = backend.newNodeLIRGenerator(graph, lirGen);
+            LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes);
+            NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
 
             try (Scope s = Debug.scope("LIRGen", lirGen)) {
                 for (Block b : linearScanOrder) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri May 02 11:33:47 2014 +0200
@@ -70,6 +70,8 @@
             return enabled;
         }
     };
+    @Option(help = "Enable more verbose log output when available")
+    public static final OptionValue<Boolean> LogVerbose = new OptionValue<>(false);
     // @formatter:on
 
     public static boolean areDebugScopePatternsEnabled() {
@@ -150,7 +152,7 @@
 
     /**
      * Extracts a {@link JavaMethod} from an opaque debug context.
-     * 
+     *
      * @return the {@link JavaMethod} represented by {@code context} or null
      */
     public static JavaMethod asJavaMethod(Object context) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -27,10 +27,10 @@
 import com.oracle.graal.lir.gen.*;
 
 public class BytecodeLIRBuilder {
-    protected final LIRGenerator gen;
+    protected final LIRGeneratorTool gen;
     protected final BytecodeParserTool parser;
 
-    public BytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         this.gen = gen;
         this.parser = parser;
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -116,20 +116,33 @@
     }
 
     protected BytecodeFrame computeFrameForState(FrameState state) {
-        int numLocals = state.localsSize();
-        int numStack = state.stackSize();
-        int numLocks = state.locksSize();
+        try {
+            assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI;
+            assert state.bci != BytecodeFrame.UNKNOWN_BCI;
+            assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0;
+            assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0;
+            assert !(state.method().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) ||
+                            state.locksSize() > 0;
+            assert state.verify();
+
+            int numLocals = state.localsSize();
+            int numStack = state.stackSize();
+            int numLocks = state.locksSize();
 
-        Value[] values = new Value[numLocals + numStack + numLocks];
-        computeLocals(state, numLocals, values);
-        computeStack(state, numLocals, numStack, values);
-        computeLocks(state, values);
+            Value[] values = new Value[numLocals + numStack + numLocks];
+            computeLocals(state, numLocals, values);
+            computeStack(state, numLocals, numStack, values);
+            computeLocks(state, values);
 
-        BytecodeFrame caller = null;
-        if (state.outerFrameState() != null) {
-            caller = computeFrameForState(state.outerFrameState());
+            BytecodeFrame caller = null;
+            if (state.outerFrameState() != null) {
+                caller = computeFrameForState(state.outerFrameState());
+            }
+            return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
+        } catch (GraalInternalError e) {
+            throw e.addContext("FrameState: ", state);
         }
-        return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
     }
 
     protected void computeLocals(FrameState state, int numLocals, Value[] values) {
@@ -168,39 +181,43 @@
     private static final DebugMetric STATE_CONSTANTS = Debug.metric("StateConstants");
 
     protected Value toValue(ValueNode value) {
-        if (value instanceof VirtualObjectNode) {
-            VirtualObjectNode obj = (VirtualObjectNode) value;
-            EscapeObjectState state = objectStates.get(obj);
-            if (state == null && obj.entryCount() > 0) {
-                // null states occur for objects with 0 fields
-                throw new GraalInternalError("no mapping found for virtual object %s", obj);
-            }
-            if (state instanceof MaterializedObjectState) {
-                return toValue(((MaterializedObjectState) state).materializedValue());
-            } else {
-                assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
-                VirtualObject vobject = virtualObjects.get(value);
-                if (vobject == null) {
-                    vobject = VirtualObject.get(obj.type(), null, virtualObjects.size());
-                    virtualObjects.put(obj, vobject);
+        try {
+            if (value instanceof VirtualObjectNode) {
+                VirtualObjectNode obj = (VirtualObjectNode) value;
+                EscapeObjectState state = objectStates.get(obj);
+                if (state == null && obj.entryCount() > 0) {
+                    // null states occur for objects with 0 fields
+                    throw new GraalInternalError("no mapping found for virtual object %s", obj);
                 }
-                STATE_VIRTUAL_OBJECTS.increment();
-                return vobject;
-            }
-        } else if (value instanceof ConstantNode) {
-            STATE_CONSTANTS.increment();
-            return ((ConstantNode) value).getValue();
+                if (state instanceof MaterializedObjectState) {
+                    return toValue(((MaterializedObjectState) state).materializedValue());
+                } else {
+                    assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
+                    VirtualObject vobject = virtualObjects.get(value);
+                    if (vobject == null) {
+                        vobject = VirtualObject.get(obj.type(), null, virtualObjects.size());
+                        virtualObjects.put(obj, vobject);
+                    }
+                    STATE_VIRTUAL_OBJECTS.increment();
+                    return vobject;
+                }
+            } else if (value instanceof ConstantNode) {
+                STATE_CONSTANTS.increment();
+                return ((ConstantNode) value).getValue();
 
-        } else if (value != null) {
-            STATE_VARIABLES.increment();
-            Value operand = nodeOperands.get(value);
-            assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value;
-            return operand;
+            } else if (value != null) {
+                STATE_VARIABLES.increment();
+                Value operand = nodeOperands.get(value);
+                assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value;
+                return operand;
 
-        } else {
-            // return a dummy value because real value not needed
-            STATE_ILLEGALS.increment();
-            return Value.ILLEGAL;
+            } else {
+                // return a dummy value because real value not needed
+                STATE_ILLEGALS.increment();
+                return Value.ILLEGAL;
+            }
+        } catch (GraalInternalError e) {
+            throw e.addContext("toValue: ", value);
         }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.gen;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
 
@@ -35,14 +36,15 @@
 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.target.*;
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.gen.LIRGenerator.*;
+import com.oracle.graal.lir.gen.LIRGenerator.LoadConstant;
+import com.oracle.graal.lir.gen.LIRGenerator.Options;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
@@ -58,15 +60,18 @@
     private final NodeMap<Value> nodeOperands;
     private final DebugInfoBuilder debugInfoBuilder;
 
-    protected final LIRGenerator gen;
+    protected final LIRGeneratorTool gen;
 
     private ValueNode currentInstruction;
     private ValueNode lastInstructionPrinted; // Debugging only
 
-    public NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    private Map<Class<? extends ValueNode>, List<MatchStatement>> matchRules;
+
+    public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         this.gen = gen;
         this.nodeOperands = graph.createNodeMap();
         this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
+        matchRules = MatchRuleRegistry.lookup(getClass());
     }
 
     @SuppressWarnings("hiding")
@@ -153,13 +158,25 @@
     @Override
     public Value setResult(ValueNode x, Value operand) {
         assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable());
-        assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice";
         assert operand != null && isLegal(operand) : "operand must be legal";
         assert !(x instanceof VirtualObjectNode);
         nodeOperands.set(x, operand);
         return operand;
     }
 
+    /**
+     * Used by the {@link MatchStatement} machinery to override the generation LIR for some
+     * ValueNodes.
+     */
+    public void setMatchResult(ValueNode x, Value operand) {
+        assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue;
+        assert operand instanceof ComplexMatchValue || x.usages().count() == 1 : "interior matches must be single user";
+        assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice";
+        assert !(x instanceof VirtualObjectNode);
+        nodeOperands.set(x, operand);
+    }
+
     public LabelRef getLIRBlock(FixedNode b) {
         assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph;
         Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b);
@@ -171,7 +188,7 @@
     }
 
     public final void append(LIRInstruction op) {
-        if (gen.printIRWithLIR && !TTY.isSuppressed()) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
             if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
                 lastInstructionPrinted = currentInstruction;
                 InstructionPrinter ip = new InstructionPrinter(TTY.out());
@@ -192,34 +209,44 @@
         }
 
         List<ScheduledNode> nodes = blockMap.get(block);
-        int instructionsFolded = 0;
+
+        if (MatchExpressions.getValue()) {
+            // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
+            // of instructions
+            matchComplexExpressions(nodes);
+        }
+
         for (int i = 0; i < nodes.size(); i++) {
             Node instr = nodes.get(i);
-            if (gen.traceLevel >= 3) {
+            if (Options.TraceLIRGeneratorLevel.getValue() >= 3) {
                 TTY.println("LIRGen for " + instr);
             }
-            if (instructionsFolded > 0) {
-                instructionsFolded--;
-                continue;
-            }
             if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
                 // Loading of constants is done lazily by operand()
 
             } else if (instr instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) instr;
-                if (!hasOperand(valueNode)) {
+                Value operand = getOperand(valueNode);
+                if (operand == null) {
                     if (!peephole(valueNode)) {
-                        instructionsFolded = maybeFoldMemory(nodes, i, valueNode);
-                        if (instructionsFolded == 0) {
-                            try {
-                                doRoot((ValueNode) instr);
-                            } catch (GraalInternalError e) {
-                                throw GraalGraphInternalError.transformAndAddContext(e, instr);
-                            } catch (Throwable e) {
-                                throw new GraalGraphInternalError(e).addContext(instr);
-                            }
+                        try {
+                            doRoot((ValueNode) instr);
+                        } catch (GraalInternalError e) {
+                            throw GraalGraphInternalError.transformAndAddContext(e, instr);
+                        } catch (Throwable e) {
+                            throw new GraalGraphInternalError(e).addContext(instr);
                         }
                     }
+                } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) {
+                    // Doesn't need to be evaluated
+                    Debug.log("interior match for %s", valueNode);
+                } else if (operand instanceof ComplexMatchValue) {
+                    Debug.log("complex match for %s", valueNode);
+                    ComplexMatchValue match = (ComplexMatchValue) operand;
+                    operand = match.evaluate(this);
+                    if (operand != null) {
+                        setResult(valueNode, operand);
+                    }
                 } else {
                     // There can be cases in which the result of an instruction is already set
                     // before by other instructions.
@@ -244,156 +271,35 @@
         gen.doBlockEnd(block);
     }
 
-    private static final DebugMetric MemoryFoldSuccess = Debug.metric("MemoryFoldSuccess");
-    private static final DebugMetric MemoryFoldFailed = Debug.metric("MemoryFoldFailed");
-    private static final DebugMetric MemoryFoldFailedNonAdjacent = Debug.metric("MemoryFoldedFailedNonAdjacent");
-    private static final DebugMetric MemoryFoldFailedDifferentBlock = Debug.metric("MemoryFoldedFailedDifferentBlock");
-
-    /**
-     * Subclass can provide helper to fold memory operations into other operations.
-     */
-    public MemoryArithmeticLIRLowerer getMemoryLowerer() {
-        return null;
-    }
-
-    private static final Object LOG_OUTPUT_LOCK = new Object();
-
-    /**
-     * Try to find a sequence of Nodes which can be passed to the backend to look for optimized
-     * instruction sequences using memory. Currently this basically is a read with a single
-     * arithmetic user followed by an possible if use. This should generalized to more generic
-     * pattern matching so that it can be more flexibly used.
-     */
-    private int maybeFoldMemory(List<ScheduledNode> nodes, int i, ValueNode access) {
-        MemoryArithmeticLIRLowerer lowerer = getMemoryLowerer();
-        if (lowerer != null && GraalOptions.OptFoldMemory.getValue() && (access instanceof ReadNode || access instanceof FloatingReadNode) && access.usages().count() == 1 && i + 1 < nodes.size()) {
-            try (Scope s = Debug.scope("MaybeFoldMemory", access)) {
-                // This is all bit hacky since it's happening on the linearized schedule. This needs
-                // to be revisited at some point.
-
-                // Uncast the memory operation.
-                Node use = access.usages().first();
-                if (use instanceof UnsafeCastNode && use.usages().count() == 1) {
-                    use = use.usages().first();
-                }
-
-                // Find a memory lowerable usage of this operation
-                if (use instanceof MemoryArithmeticLIRLowerable) {
-                    ValueNode operation = (ValueNode) use;
-                    if (!nodes.contains(operation)) {
-                        Debug.log("node %1s in different block from %1s", access, operation);
-                        MemoryFoldFailedDifferentBlock.increment();
-                        return 0;
+    protected void matchComplexExpressions(List<ScheduledNode> nodes) {
+        if (matchRules != null) {
+            try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                // Match the nodes in backwards order to encourage longer matches.
+                for (int index = nodes.size() - 1; index >= 0; index--) {
+                    ScheduledNode snode = nodes.get(index);
+                    if (!(snode instanceof ValueNode)) {
+                        continue;
                     }
-                    ValueNode firstOperation = operation;
-                    if (operation instanceof LogicNode) {
-                        if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) {
-                            ValueNode ifNode = (ValueNode) operation.usages().first();
-                            if (!nodes.contains(ifNode)) {
-                                MemoryFoldFailedDifferentBlock.increment();
-                                Debug.log("if node %1s in different block from %1s", ifNode, operation);
-                                try (Indent indent = Debug.logAndIndent("checking operations")) {
-                                    int start = nodes.indexOf(access);
-                                    int end = nodes.indexOf(operation);
-                                    for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
-                                        Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
-                                    }
-                                }
-                                return 0;
-                            } else {
-                                operation = ifNode;
-                            }
-                        }
-                    }
-                    if (Debug.isLogEnabled()) {
-                        synchronized (LOG_OUTPUT_LOCK) {  // Hack to ensure the output is grouped.
-                            try (Indent indent = Debug.logAndIndent("checking operations")) {
-                                int start = nodes.indexOf(access);
-                                int end = nodes.indexOf(operation);
-                                for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
-                                    Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
-                                }
+                    ValueNode node = (ValueNode) snode;
+                    // See if this node is the root of any MatchStatements
+                    List<MatchStatement> statements = matchRules.get(node.getClass());
+                    if (statements != null) {
+                        for (MatchStatement statement : statements) {
+                            if (statement.generate(this, index, node, nodes)) {
+                                // Found a match so skip to the next
+                                break;
                             }
                         }
                     }
-                    // Possible lowerable operation in the same block. Check out the dependencies.
-                    int opIndex = nodes.indexOf(operation);
-                    int current = i + 1;
-                    ArrayList<ValueNode> deferred = null;
-                    for (; current < opIndex; current++) {
-                        ScheduledNode node = nodes.get(current);
-                        if (node != firstOperation) {
-                            if (node instanceof LocationNode || node instanceof VirtualObjectNode) {
-                                // nothing to do
-                                continue;
-                            } else if (node instanceof ConstantNode) {
-                                if (deferred == null) {
-                                    deferred = new ArrayList<>(2);
-                                }
-                                // These nodes are collected and the backend is expended to
-                                // evaluate them before generating the lowered form. This
-                                // basically works around unfriendly scheduling of values which
-                                // are defined in a block but not used there.
-                                deferred.add((ValueNode) node);
-                                continue;
-                            } else if (node instanceof UnsafeCastNode) {
-                                UnsafeCastNode cast = (UnsafeCastNode) node;
-                                if (cast.getOriginalNode() == access) {
-                                    continue;
-                                }
-                            }
-
-                            // Unexpected inline node
-                            // Debug.log("unexpected node %1s", node);
-                            break;
-                        }
-                    }
-
-                    if (current == opIndex) {
-                        if (lowerer.memoryPeephole((Access) access, (MemoryArithmeticLIRLowerable) operation, deferred)) {
-                            MemoryFoldSuccess.increment();
-                            // if this operation had multiple access inputs, then previous attempts
-                            // would be marked as failures which is wrong. Try to adjust the
-                            // counters to account for this.
-                            for (Node input : operation.inputs()) {
-                                if (input == access) {
-                                    continue;
-                                }
-                                if (input instanceof Access && nodes.contains(input)) {
-                                    MemoryFoldFailedNonAdjacent.add(-1);
-                                }
-                            }
-                            if (deferred != null) {
-                                // Ensure deferred nodes were evaluated
-                                for (ValueNode node : deferred) {
-                                    assert hasOperand(node);
-                                }
-                            }
-                            return opIndex - i;
-                        } else {
-                            // This isn't true failure, it just means there wasn't match for the
-                            // pattern. Usually that means it's just not supported by the backend.
-                            MemoryFoldFailed.increment();
-                            return 0;
-                        }
-                    } else {
-                        MemoryFoldFailedNonAdjacent.increment();
-                    }
-                } else if (!(use instanceof Access) && !(use instanceof PhiNode) && use.usages().count() == 1) {
-                    // memory usage which isn't considered lowerable. Mostly these are
-                    // uninteresting but it might be worth looking at to ensure that interesting
-                    // nodes are being properly handled.
-                    // Debug.log("usage isn't lowerable %1s", access.usages().first());
                 }
             }
         }
-        return 0;
     }
 
     protected abstract boolean peephole(ValueNode valueNode);
 
     private void doRoot(ValueNode instr) {
-        if (gen.traceLevel >= 2) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 2) {
             TTY.println("Emitting LIR for instruction " + instr);
         }
         currentInstruction = instr;
@@ -407,11 +313,7 @@
         if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) {
             Debug.log("This node has invalid type, we are emitting dead code(?): %s", node);
         }
-        if (node instanceof LIRGenLowerable) {
-            ((LIRGenLowerable) node).generate(this);
-        } else if (node instanceof LIRGenResLowerable) {
-            ((LIRGenResLowerable) node).generate(this, gen.getResult());
-        } else if (node instanceof LIRLowerable) {
+        if (node instanceof LIRLowerable) {
             ((LIRLowerable) node).generate(this);
         } else if (node instanceof ArithmeticLIRLowerable) {
             ((ArithmeticLIRLowerable) node).generate(this, gen);
@@ -460,7 +362,7 @@
     }
 
     private void moveToPhi(MergeNode merge, AbstractEndNode pred) {
-        if (gen.traceLevel >= 1) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
             TTY.println("MOVE TO PHI from " + pred + " to " + merge);
         }
         PhiResolver resolver = new PhiResolver(gen);
@@ -725,11 +627,7 @@
     }
 
     @Override
-    public LIRGenerator getLIRGeneratorTool() {
-        return gen;
-    }
-
-    public LIRGenerator getLIRGenerator() {
+    public LIRGeneratorTool getLIRGeneratorTool() {
         return gen;
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri May 02 11:33:47 2014 +0200
@@ -34,18 +34,18 @@
 
 /**
  * Converts {@link ValuePhiNode} instructions into moves.
- * 
+ *
  * Resolves cycles:
- * 
+ *
  * <pre>
- * 
+ *
  *  r1 := r2  becomes  temp := r1
  *  r2 := r1           r1 := r2
  *                     r2 := temp
  * </pre>
- * 
+ *
  * and orders moves:
- * 
+ *
  * <pre>
  *  r2 := r3  becomes  r1 := r2
  *  r1 := r2           r2 := r3
@@ -104,7 +104,7 @@
         }
     }
 
-    private final LIRGenerator gen;
+    private final LIRGeneratorTool gen;
 
     /**
      * The operand loop header phi for the operand currently being process in {@link #dispose()}.
@@ -121,7 +121,7 @@
      */
     private final HashMap<Value, PhiResolverNode> operandToNodeMap = new HashMap<>();
 
-    public PhiResolver(LIRGenerator gen) {
+    public PhiResolver(LIRGeneratorTool gen) {
         this.gen = gen;
         temp = ILLEGAL;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * A closure that can be evaluated to produce the LIR for some complex match. Using a closure allows
+ * normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes evaluated at
+ * the proper time.
+ */
+public interface ComplexMatchResult {
+    Value evaluate(NodeLIRBuilder gen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * A wrapper value for the lazy evaluation of a complex match. There's an intermediate class for the
+ * closure because Value is serializable which is a hassle for the little inner classes which
+ * usually occur here.
+ */
+public class ComplexMatchValue extends Value {
+    private static final long serialVersionUID = -4734670273590368770L;
+
+    /**
+     * This is the Value of a node which was matched as part of a complex match. The value isn't
+     * actually useable but this marks it as having been evaluated.
+     */
+    @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) {
+
+        @Override
+        public String toString() {
+            return "INTERIOR_MATCH";
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            // This class is a singleton
+            return other != null && getClass() == other.getClass();
+        }
+    };
+
+    final ComplexMatchResult result;
+
+    public ComplexMatchValue(ComplexMatchResult result) {
+        super(Kind.Illegal);
+        this.result = result;
+    }
+
+    public Value evaluate(NodeLIRBuilder builder) {
+        return result.evaluate(builder);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.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();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.virtual.*;
+
+/**
+ * Container for state captured during a match.
+ */
+public class MatchContext {
+
+    private final ValueNode root;
+
+    private final List<ScheduledNode> nodes;
+
+    private final MatchStatement rule;
+
+    private Map<String, NamedNode> namedNodes;
+
+    private ArrayList<ValueNode> consumed;
+
+    private int startIndex;
+
+    private int endIndex;
+
+    private final NodeLIRBuilder builder;
+
+    private static class NamedNode {
+        final Class<? extends ValueNode> type;
+        final ValueNode value;
+
+        NamedNode(Class<? extends ValueNode> type, ValueNode value) {
+            this.type = type;
+            this.value = value;
+        }
+    }
+
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List<ScheduledNode> nodes) {
+        this.builder = builder;
+        this.rule = rule;
+        this.root = node;
+        this.nodes = nodes;
+        assert index == nodes.indexOf(node);
+        // The root should be the last index since all the inputs must be scheduled before it.
+        startIndex = endIndex = index;
+    }
+
+    public ValueNode getRoot() {
+        return root;
+    }
+
+    public Result captureNamedValue(String name, Class<? extends ValueNode> type, ValueNode value) {
+        if (namedNodes == null) {
+            namedNodes = new HashMap<>(2);
+        }
+        NamedNode current = namedNodes.get(name);
+        if (current == null) {
+            current = new NamedNode(type, value);
+            namedNodes.put(name, current);
+            return Result.OK;
+        } else {
+            if (current.value != value || current.type != type) {
+                return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern());
+            }
+            return Result.OK;
+        }
+    }
+
+    public Result validate() {
+        // Ensure that there's no unsafe work in between these operations.
+        for (int i = startIndex; i <= endIndex; i++) {
+            ScheduledNode node = nodes.get(i);
+            if (node instanceof 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.
+                continue;
+            } else if (consumed == null || !consumed.contains(node) && node != root) {
+                if (LogVerbose.getValue()) {
+                    Debug.log("unexpected node %s", node);
+                    for (int j = startIndex; j <= endIndex; j++) {
+                        ScheduledNode theNode = nodes.get(j);
+                        Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode);
+                    }
+                }
+                return Result.NOT_SAFE(node, rule.getPattern());
+            }
+        }
+        return Result.OK;
+    }
+
+    /**
+     * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result.
+     * During final LIR generation it will be evaluated to produce the actual LIR value.
+     *
+     * @param result
+     */
+    public void setResult(ComplexMatchResult result) {
+        ComplexMatchValue value = new ComplexMatchValue(result);
+        Debug.log("matched %s %s", rule.getName(), rule.getPattern());
+        Debug.log("with nodes %s", rule.formatMatch(root));
+        if (consumed != null) {
+            for (ValueNode node : consumed) {
+                // All the interior nodes should be skipped during the normal doRoot calls in
+                // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
+                // closure which will be evaluated to produce the final LIR.
+                builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH);
+            }
+        }
+        builder.setMatchResult(root, value);
+    }
+
+    /**
+     * Mark a node as consumed by the match. Consumed nodes will never be evaluated.
+     *
+     * @return Result.OK if the node can be safely consumed.
+     */
+    public Result consume(ValueNode node) {
+        assert node.usages().count() <= 1 : "should have already been checked";
+
+        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);
+        }
+        consumed.add(node);
+        return Result.OK;
+    }
+
+    /**
+     * Return the named node. It's an error if the
+     *
+     * @param name the name of a node in the match rule
+     * @return the matched node
+     * @throws GraalInternalError is the named node doesn't exist.
+     */
+    public ValueNode namedNode(String name) {
+        if (namedNodes != null) {
+            NamedNode value = namedNodes.get(name);
+            if (value != null) {
+                return value.value;
+            }
+        }
+        throw new GraalInternalError("missing node %s", name);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : "");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.compiler.gen.*;
+
+/**
+ * Code generator for complex match patterns.
+ */
+public interface MatchGenerator {
+    /**
+     * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be
+     *          evaluated during LIR generation to produce the final LIR value.
+     */
+    ComplexMatchResult match(NodeLIRBuilder gen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A simple recursive pattern matcher for a DAG of nodes.
+ */
+
+public class MatchPattern {
+
+    enum MatchResultCode {
+        OK,
+        WRONG_CLASS,
+        NAMED_VALUE_MISMATCH,
+        TOO_MANY_USERS,
+        NOT_IN_BLOCK,
+        NOT_SAFE,
+        ALREADY_USED,
+    }
+
+    /**
+     * A descriptive result for match failures. This can be helpful for debugging why a match
+     * doesn't work as expected.
+     */
+    static class Result {
+        final MatchResultCode code;
+
+        final ScheduledNode node;
+
+        final MatchPattern matcher;
+
+        Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) {
+            this.code = result;
+            this.node = node;
+            this.matcher = matcher;
+        }
+
+        private static final DebugMetric MatchResult_WRONG_CLASS = Debug.metric("MatchResult_WRONG_CLASS");
+        private static final DebugMetric MatchResult_NAMED_VALUE_MISMATCH = Debug.metric("MatchResult_NAMED_VALUE_MISMATCH");
+        private static final DebugMetric MatchResult_TOO_MANY_USERS = Debug.metric("MatchResult_TOO_MANY_USERS");
+        private static final DebugMetric MatchResult_NOT_IN_BLOCK = Debug.metric("MatchResult_NOT_IN_BLOCK");
+        private static final DebugMetric MatchResult_NOT_SAFE = Debug.metric("MatchResult_NOT_SAFE");
+        private static final DebugMetric MatchResult_ALREADY_USED = Debug.metric("MatchResult_ALREADY_USED");
+
+        static final Result OK = new Result(MatchResultCode.OK, null, null);
+
+        static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) {
+            MatchResult_WRONG_CLASS.increment();
+            return new Result(MatchResultCode.WRONG_CLASS, node, matcher);
+        }
+
+        static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) {
+            MatchResult_NAMED_VALUE_MISMATCH.increment();
+            return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher);
+        }
+
+        static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) {
+            MatchResult_TOO_MANY_USERS.increment();
+            return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher);
+        }
+
+        static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) {
+            MatchResult_NOT_IN_BLOCK.increment();
+            return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher);
+        }
+
+        static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) {
+            MatchResult_NOT_SAFE.increment();
+            return new Result(MatchResultCode.NOT_SAFE, node, matcher);
+        }
+
+        static Result ALREADY_USED(ValueNode node, MatchPattern matcher) {
+            MatchResult_ALREADY_USED.increment();
+            return new Result(MatchResultCode.ALREADY_USED, node, matcher);
+        }
+
+        @Override
+        public String toString() {
+            if (code == MatchResultCode.OK) {
+                return "OK";
+            }
+            return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
+        }
+    }
+
+    /**
+     * The expected type of the node. It must match exactly.
+     */
+    private final Class<? extends ValueNode> nodeClass;
+    /**
+     * An optional name for this node. A name can occur multiple times in a match and that name must
+     * always refer to the same node of the match will fail.
+     */
+    private final String name;
+    /**
+     * An optional pattern for the first input.
+     */
+    private final MatchPattern first;
+    /**
+     * An optional pattern for the second input.
+     */
+    private final MatchPattern second;
+    /**
+     * Helper class to visit the inputs.
+     */
+    private final MatchNodeAdapter adapter;
+    /**
+     * Can there only be one user of the node. Constant nodes can be matched even if there are other
+     * users.
+     */
+    private final boolean singleUser;
+
+    public MatchPattern(String name, boolean singleUser) {
+        this(null, name, null, null, null, singleUser);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) {
+        this(nodeClass, name, null, null, null, singleUser);
+    }
+
+    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) {
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.first = first;
+        this.second = second;
+        this.adapter = adapter;
+    }
+
+    Class<? extends ValueNode> nodeClass() {
+        return nodeClass;
+    }
+
+    private Result matchType(ValueNode node) {
+        if (nodeClass != null && node.getClass() != nodeClass) {
+            return Result.WRONG_CLASS(node, this);
+        }
+        return Result.OK;
+    }
+
+    /**
+     * Match any named nodes and ensure that the consumed nodes can be safely merged.
+     *
+     * @param node
+     * @param context
+     * @return Result.OK is the pattern can be safely matched.
+     */
+    Result matchUsage(ValueNode node, MatchContext context) {
+        Result result = matchUsage(node, context, true);
+        if (result == Result.OK) {
+            result = context.validate();
+        }
+        return result;
+    }
+
+    private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
+        }
+        if (singleUser && !atRoot) {
+            result = context.consume(node);
+            if (result != Result.OK) {
+                return result;
+            }
+        }
+
+        if (name != null) {
+            result = context.captureNamedValue(name, nodeClass, node);
+        }
+
+        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);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Recursively match the shape of the tree without worry about named values. Most matches fail
+     * at this point so it's performed first.
+     *
+     * @param node
+     * @param statement
+     * @return Result.OK if the shape of the pattern matches.
+     */
+    public Result matchShape(ValueNode node, MatchStatement statement) {
+        return matchShape(node, statement, true);
+    }
+
+    private Result matchShape(ValueNode node, MatchStatement statement, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
+        }
+
+        if (singleUser && !atRoot) {
+            if (node.usages().count() > 1) {
+                return Result.TOO_MANY_USERS(node, statement.getPattern());
+            }
+        }
+
+        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);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * For a node starting at root, produce a String showing the inputs that matched against this
+     * rule. It's assumed that a match has already succeeded against this rule, otherwise the
+     * printing may produce exceptions.
+     */
+    public String formatMatch(ValueNode root) {
+        String result = String.format("%s", root);
+        if (first == null && second == null) {
+            return result;
+        } else {
+            return "(" + result + (first != null ? " " + first.formatMatch(adapter.getFirstInput(root)) : "") + (second != null ? " " + second.formatMatch(adapter.getSecondInput(root)) : "") + ")";
+        }
+    }
+
+    @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;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,772 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.lang.model.util.*;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
+ * generated for each top level class containing at least one such field. These service objects can
+ * be retrieved as follows:
+ *
+ * <pre>
+ *     ServiceLoader<MatchStatementSet> sl = ServiceLoader.loadInstalled(MatchStatementSet.class);
+ *     for (MatchStatementSet rules : sl) {
+ *         ...
+ *     }
+ * </pre>
+ */
+@SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode"})
+public class MatchProcessor extends AbstractProcessor {
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private final Set<Element> processedMatchRule = new HashSet<>();
+    private final Set<Element> processedMatchableNode = new HashSet<>();
+
+    private static class RuleParseError extends RuntimeException {
+        private static final long serialVersionUID = 6456128283609257490L;
+
+        RuleParseError(String format, Object... args) {
+            super(String.format(format, args));
+        }
+    }
+
+    private class RuleParser {
+        private ArrayList<TypeDescriptor> capturedTypes = new ArrayList<>();
+
+        private ArrayList<String> capturedNames = new ArrayList<>();
+
+        private final String[] tokens;
+
+        private int current;
+
+        private MatchDescriptor matchDescriptor;
+
+        private final Set<Element> originatingElements = new HashSet<>();
+
+        RuleParser(String rule) {
+            Matcher m = tokenizer.matcher(rule);
+            List<String> list = new ArrayList<>();
+            int end = 0;
+            while (m.lookingAt()) {
+                list.add(m.group(1));
+                end = m.end();
+                m.region(m.end(), m.regionEnd());
+            }
+            if (end != m.regionEnd()) {
+                throw new RuleParseError("Unnexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
+            }
+            tokens = list.toArray(new String[0]);
+
+            matchDescriptor = parseExpression();
+            if (!done()) {
+                throw new RuleParseError("didn't consume all tokens");
+            }
+            capturedNames.add(0, "root");
+            capturedTypes.add(0, matchDescriptor.nodeType);
+        }
+
+        String next() {
+            return tokens[current++];
+        }
+
+        String peek(String name) {
+            if (current >= tokens.length) {
+                if (name == null) {
+                    throw new RuleParseError("Out of tokens");
+                }
+                throw new RuleParseError("Out of tokens looking for %s", name);
+            }
+            return tokens[current];
+        }
+
+        boolean done() {
+            return current == tokens.length;
+        }
+
+        private MatchDescriptor parseExpression() {
+            if (peek("(").equals("(")) {
+                next();
+                MatchDescriptor descriptor = parseType(true);
+                for (int n = 0; n < descriptor.nodeType.inputs; n++) {
+                    if (peek("(").equals("(")) {
+                        descriptor.inputs[n] = parseExpression();
+                    } else {
+                        descriptor.inputs[n] = parseType(false);
+                    }
+                }
+                for (int n = 0; n < descriptor.nodeType.inputs; n++) {
+                    if (descriptor.inputs[n] == null) {
+                        throw new RuleParseError("not enough inputs for " + descriptor.name);
+                    }
+                }
+                if (peek(")").equals(")")) {
+                    next();
+                    return descriptor;
+                }
+            }
+            throw new RuleParseError("Extra tokens following match pattern: " + peek(null));
+        }
+
+        private MatchDescriptor parseType(boolean forExpression) {
+            TypeDescriptor type = null;
+            String name = null;
+            if (Character.isUpperCase(peek("node type or name").charAt(0))) {
+                String token = next();
+                type = knownTypes.get(token);
+                if (type == null) {
+                    throw new RuleParseError("Unknown node type: " + token);
+                }
+                if (peek("=").equals("=")) {
+                    next();
+                    name = next();
+                }
+                originatingElements.addAll(type.originatingElements);
+            } else if (Character.isLowerCase(peek("name").charAt(0))) {
+                name = next();
+                type = valueType;
+            } else {
+                throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null));
+            }
+            if (name != null) {
+                if (!capturedNames.contains(name)) {
+                    capturedNames.add(name);
+                    capturedTypes.add(type);
+                } else {
+                    int index = capturedNames.indexOf(name);
+                    if (capturedTypes.get(index) != type) {
+                        throw new RuleParseError("Captured node \"%s\" has differing types", name);
+                    }
+                }
+            }
+            return new MatchDescriptor(type, name, forExpression);
+        }
+
+        List<String> generateVariants() {
+            return matchDescriptor.generateVariants();
+        }
+
+        /**
+         *
+         * @return the list of node types which are captured by name
+         */
+        public ArrayList<TypeDescriptor> capturedTypes() {
+            return capturedTypes;
+        }
+
+        public ArrayList<String> capturedNames() {
+            return capturedNames;
+        }
+    }
+
+    static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+
+    static class TypeDescriptor {
+        final TypeMirror mirror;
+
+        /**
+         * The name uses in match expressions to refer to this type.
+         */
+        final String shortName;
+        /**
+         * The {@link ValueNode} class represented by this type.
+         */
+        final String nodeClass;
+
+        /**
+         * The {@link ValueNode} class represented by this type.
+         */
+        final String nodePackage;
+
+        /**
+         * Expected number of matchable inputs. Should be less <= 2 at the moment.
+         */
+        final int inputs;
+
+        /**
+         * An adapter class to read the proper matchable inputs of the class.
+         */
+        final String adapter;
+
+        /**
+         * Should swapped variants of this match be generated. The user of the match is expected to
+         * compensate for any ordering differences in compare which are commutative but require
+         * reinterpreting the condition in that case.
+         */
+        final boolean commutative;
+
+        /**
+         * Can multiple users of this node subsume it. Constants can be swallowed into a match even
+         * if there are multiple users.
+         */
+        final boolean cloneable;
+
+        final Set<Element> originatingElements = new HashSet<>();
+
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
+            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;
+        }
+    }
+
+    /**
+     * The types which are know for purpose of parsing MatchRule expressions.
+     */
+    Map<String, TypeDescriptor> knownTypes = new HashMap<>();
+
+    /**
+     * The set of packages which must be imported to refer to the known classes.
+     */
+    List<String> requiredPackages = new ArrayList<>();
+
+    /**
+     * The automatically generated wrapper class for 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);
+        descriptor.originatingElements.add(element);
+        knownTypes.put(shortName, descriptor);
+        if (!requiredPackages.contains(descriptor.nodePackage)) {
+            requiredPackages.add(descriptor.nodePackage);
+        }
+    }
+
+    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();
+        }
+        throw new GraalInternalError("can't find package for %s", type);
+    }
+
+    class MatchDescriptor {
+        TypeDescriptor nodeType;
+        String name;
+        MatchDescriptor[] inputs;
+
+        MatchDescriptor(TypeDescriptor nodeType, String name, boolean forExpression) {
+            this.nodeType = nodeType;
+            this.name = name;
+            if (forExpression) {
+                this.inputs = new MatchDescriptor[nodeType.inputs];
+            } else {
+                this.inputs = new MatchDescriptor[0];
+            }
+        }
+
+        /**
+         * Recursively generate all the variants of this rule pattern. Currently that just means to
+         * swap the inputs for commutative rules, producing all possible permutations.
+         *
+         * @return a list of Strings which will construct pattern matchers for this rule.
+         */
+        List<String> generateVariants() {
+            String prefix = formatPrefix();
+            String suffix = formatSuffix();
+            ArrayList<String> variants = new ArrayList<>();
+            if (inputs.length == 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);
+                }
+            } else {
+                variants.add(prefix + suffix);
+            }
+            return variants;
+        }
+
+        private String formatPrefix() {
+            if (nodeType == valueType) {
+                return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null");
+            } else {
+                return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null");
+            }
+        }
+
+        private String formatSuffix() {
+            if (nodeType != null) {
+                if (inputs.length != nodeType.inputs) {
+                    return ", true)";
+                } else {
+                    if (nodeType.adapter != null) {
+                        return ", " + nodeType.adapter + "," + !nodeType.cloneable + ")";
+                    }
+                    if (nodeType.cloneable) {
+                        return ", false)";
+                    }
+                }
+            }
+            return ")";
+        }
+
+    }
+
+    /**
+     * Strip the package off a class name leaving the full class name including any outer classes.
+     */
+    static String fullClassName(Element element) {
+        assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE : element;
+        String pkg = findPackage(element);
+        return ((TypeElement) element).getQualifiedName().toString().substring(pkg.length() + 1);
+    }
+
+    private void createFiles(MatchRuleDescriptor info) {
+        String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
+        Name topDeclaringClass = info.topDeclaringType.getSimpleName();
+
+        String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
+        Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
+
+        Types typeUtils = processingEnv.getTypeUtils();
+        Filer filer = processingEnv.getFiler();
+        try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) {
+
+            out.println("// CheckStyle: stop header check");
+            out.println("// GENERATED CONTENT - DO NOT EDIT");
+            out.println("// Source: " + topDeclaringClass + ".java");
+            out.println("package " + pkg + ";");
+            out.println("");
+            out.println("import java.util.*;");
+            out.println("import java.lang.reflect.*;");
+            out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
+            out.println("import " + GraalInternalError.class.getName() + ";");
+            out.println("import " + NodeLIRBuilder.class.getName() + ";");
+            for (String p : requiredPackages) {
+                out.println("import " + p + ".*;");
+            }
+            out.println("");
+            out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+
+            // Generate declarations for the reflective invocation of the code generation methods.
+            for (MethodInvokerItem invoker : invokers.values()) {
+                StringBuilder args = new StringBuilder();
+                StringBuilder types = new StringBuilder();
+                int count = invoker.fields.size();
+                for (VariableElement arg : invoker.fields) {
+                    args.append('"');
+                    args.append(arg.getSimpleName());
+                    args.append('"');
+                    types.append(fullClassName(typeUtils.asElement(arg.asType())));
+                    types.append(".class");
+                    if (count-- > 1) {
+                        args.append(", ");
+                        types.append(", ");
+                    }
+                }
+                out.printf("        private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
+                out.printf("        private static final 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.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(");
+
+            int i = 0;
+            for (MatchRuleItem matchRule : info.matchRules) {
+                String comma = i == info.matchRules.size() - 1 ? "" : ",";
+                out.printf("        %s%s\n", matchRule.ruleBuilder(), comma);
+                i++;
+            }
+            out.println("    ));");
+            out.println("    // CheckStyle: resume line length check");
+            out.println();
+
+            out.println("    public Class<? extends NodeLIRBuilder> forClass() {");
+            out.println("        return " + topDeclaringClass + ".class;");
+            out.println("    }");
+            out.println();
+            out.println("    @Override");
+            out.println("    public List<" + desc + "> statements() {");
+            out.println("        return statements;");
+            out.println("    }");
+            out.println("}");
+        }
+
+        try {
+            createProviderFile(pkg, matchStatementClassName, originatingElements);
+        } catch (IOException e) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType);
+        }
+    }
+
+    private void createProviderFile(String pkg, String providerClassName, Element... originatingElements) throws IOException {
+        String filename = "META-INF/providers/" + pkg + "." + providerClassName;
+        FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements);
+        PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
+        writer.println(MatchStatementSet.class.getName());
+        writer.close();
+    }
+
+    protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+        try {
+            // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle
+            JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements);
+            return new PrintWriter(sourceFile.openWriter()) {
+
+                @Override
+                public void println() {
+                    print("\n");
+                }
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Used to generate the MatchStatement constructor invocation.
+     */
+    static class MatchRuleItem {
+        private final String matchPattern;
+        private final MethodInvokerItem invoker;
+
+        public MatchRuleItem(String matchPattern, MethodInvokerItem invoker) {
+            this.matchPattern = matchPattern;
+            this.invoker = invoker;
+        }
+
+        /**
+         * @return a string which will construct the MatchStatement instance to match this pattern.
+         */
+        public String ruleBuilder() {
+            return String.format("new MatchStatement(\"%s\", %s, %s, %s)", invoker.name, matchPattern, invoker.reflectiveMethodName(), invoker.argumentsListName());
+        }
+    }
+
+    /**
+     * Used to generate the declarations needed for reflective invocation of the code generation
+     * method.
+     */
+    static class MethodInvokerItem {
+        final String name;
+        final String nodeLIRBuilderClass;
+        final String methodName;
+        final List<? extends VariableElement> fields;
+
+        MethodInvokerItem(String name, String nodeLIRBuilderClass, String methodName, List<? extends VariableElement> fields) {
+            this.name = name;
+            this.nodeLIRBuilderClass = nodeLIRBuilderClass;
+            this.methodName = methodName;
+            this.fields = fields;
+        }
+
+        String reflectiveMethodName() {
+            return methodName + "_invoke";
+        }
+
+        String argumentsListName() {
+            return methodName + "_arguments";
+        }
+    }
+
+    static class MatchRuleDescriptor {
+
+        final TypeElement topDeclaringType;
+        final List<MatchRuleItem> matchRules = new ArrayList<>();
+        private final Set<Element> originatingElements = new HashSet<>();
+
+        public MatchRuleDescriptor(TypeElement topDeclaringType) {
+            this.topDeclaringType = topDeclaringType;
+        }
+    }
+
+    private static TypeElement topDeclaringType(Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) {
+            assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE;
+            return (TypeElement) element;
+        }
+        return topDeclaringType(enclosing);
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+
+        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);
+
+            // 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);
+                }
+            }
+
+            // 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);
+            }
+            for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
+                processMatchRule(map, element);
+            }
+
+            for (MatchRuleDescriptor info : map.values()) {
+                createFiles(info);
+            }
+
+        } catch (Throwable t) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)));
+        }
+
+        return true;
+    }
+
+    /**
+     * Build up the type table to be used during parsing of the MatchRule.
+     */
+    private void processMatchableNode(Element element) {
+        if (!processedMatchableNode.contains(element)) {
+            try {
+                processedMatchableNode.add(element);
+                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);
+                }
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
+            }
+        }
+    }
+
+    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 processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element) {
+        if (!processedMatchRule.contains(element)) {
+            try {
+                processedMatchRule.add(element);
+
+                // The annotation element type should ensure this is true.
+                assert element instanceof ExecutableElement;
+
+                TypeElement topDeclaringType = topDeclaringType(element);
+                MatchRuleDescriptor info = map.get(topDeclaringType);
+                if (info == null) {
+                    info = new MatchRuleDescriptor(topDeclaringType);
+                    map.put(topDeclaringType, info);
+                }
+                for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
+                    // System.err.println(matchRule);
+                    processMethodMatchRule((ExecutableElement) element, info, matchRule);
+                }
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
+            }
+        }
+    }
+
+    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule) {
+        Types typeUtils = processingEnv.getTypeUtils();
+
+        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
+            String msg = String.format("MatchRule method %s must be public", method.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+            return;
+        }
+        if (method.getModifiers().contains(Modifier.STATIC)) {
+            String msg = String.format("MatchRule method %s must be non-static", method.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+            return;
+        }
+
+        try {
+            TypeMirror returnType = method.getReturnType();
+            if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) {
+                String msg = String.format("MatchRule method return type must be %s", ComplexMatchResult.class.getName());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                return;
+            }
+
+            String rule = matchRule.value();
+            RuleParser parser = new RuleParser(rule);
+            ArrayList<TypeDescriptor> expectedTypes = parser.capturedTypes();
+            ArrayList<String> expectedNames = parser.capturedNames();
+            List<? extends VariableElement> actualParameters = method.getParameters();
+            if (expectedTypes.size() + 1 < actualParameters.size()) {
+                String msg = String.format("Too many arguments for match method %s %s", expectedTypes.size() + 1, actualParameters.size());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                return;
+            }
+
+            // Walk through the parameters to the method and see if they exist in the match rule.
+            // The order doesn't matter but only names mentioned in the rule can be used and they
+            // must be assignment compatible.
+            for (VariableElement parameter : actualParameters) {
+                String name = parameter.getSimpleName().toString();
+                int nameIndex = expectedNames.indexOf(name);
+                if (nameIndex == -1) {
+                    String msg = String.format("Argument \"%s\" isn't captured in the match rule", name);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                    return;
+                }
+                TypeMirror type = parameter.asType();
+                if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) {
+                    String msg = String.format("Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                    return;
+                }
+            }
+
+            MethodInvokerItem invoker = invokers.get(method);
+            if (invoker == null) {
+                invoker = new MethodInvokerItem(method.getSimpleName().toString(), topDeclaringType(method).getSimpleName().toString(), method.getSimpleName().toString(), actualParameters);
+                invokers.put(method, invoker);
+            }
+
+            Element enclosing = method.getEnclosingElement();
+            String declaringClass = "";
+            String separator = "";
+            Set<Element> originatingElementsList = info.originatingElements;
+            originatingElementsList.add(method);
+            while (enclosing != null) {
+                if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                    if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
+                        String msg = String.format("MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                        processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                        return;
+                    }
+                    originatingElementsList.add(enclosing);
+                    declaringClass = enclosing.getSimpleName() + separator + declaringClass;
+                    separator = ".";
+                } else {
+                    assert enclosing.getKind() == ElementKind.PACKAGE;
+                }
+                enclosing = enclosing.getEnclosingElement();
+            }
+
+            originatingElementsList.addAll(parser.originatingElements);
+
+            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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+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.
+ *
+ * <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 ] )
+ * </pre>
+ *
+ * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user.
+ * All matched nodes must be in the same block.
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Repeatable(value = MatchRules.class)
+public @interface MatchRule {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.nodes.*;
+
+public class MatchRuleRegistry {
+
+    private static final HashMap<Class<? extends NodeLIRBuilder>, Map<Class<? extends ValueNode>, List<MatchStatement>>> registry = new HashMap<>();
+
+    /**
+     * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass.
+     *
+     * @param theClass
+     * @return the set of {@link MatchStatement}s applicable to theClass.
+     */
+    public synchronized static Map<Class<? extends ValueNode>, List<MatchStatement>> lookup(Class<? extends NodeLIRBuilder> theClass) {
+        Map<Class<? extends ValueNode>, List<MatchStatement>> result = registry.get(theClass);
+
+        if (result == null) {
+            HashMap<Class<? extends NodeLIRBuilder>, List<MatchStatement>> localRules = new HashMap<>();
+            ServiceLoader<MatchStatementSet> sl = ServiceLoader.loadInstalled(MatchStatementSet.class);
+            for (MatchStatementSet rules : sl) {
+                localRules.put(rules.forClass(), rules.statements());
+            }
+
+            // Walk the class hierarchy collecting lists and merge them together. The subclass
+            // rules are first which gives them preference over earlier rules.
+            Map<Class<? extends ValueNode>, List<MatchStatement>> rules = new HashMap<>();
+            Class<?> currentClass = theClass;
+            do {
+                List<MatchStatement> statements = localRules.get(currentClass);
+                if (statements != null) {
+                    for (MatchStatement statement : statements) {
+                        Class<? extends ValueNode> nodeClass = statement.getPattern().nodeClass();
+                        List<MatchStatement> current = rules.get(nodeClass);
+                        if (current == null) {
+                            current = new ArrayList<>();
+                            rules.put(nodeClass, current);
+                        }
+                        current.add(statement);
+                    }
+                }
+                currentClass = currentClass.getSuperclass();
+            } while (currentClass != NodeLIRBuilder.class);
+            registry.put(theClass, rules);
+            assert registry.get(theClass) == rules;
+            result = rules;
+
+            if (LogVerbose.getValue()) {
+                try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                    Debug.log("Match rules for %s", theClass.getSimpleName());
+                    for (Entry<Class<? extends ValueNode>, List<MatchStatement>> entry : result.entrySet()) {
+                        Debug.log("  For node class: %s", entry.getKey());
+                        for (MatchStatement statement : entry.getValue()) {
+                            Debug.log("    %s", statement.getPattern());
+                        }
+                    }
+                }
+            }
+        }
+
+        if (result.size() == 0) {
+            return null;
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchRule}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface MatchRules {
+    MatchRule[] value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.MatchResultCode;
+import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.*;
+
+/**
+ * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace
+ * one or more {@link ValueNode}s with a single {@link Value}.
+ */
+
+public class MatchStatement {
+    private static final DebugMetric MatchStatementSuccess = Debug.metric("MatchStatementSuccess");
+
+    /**
+     * A printable name for this statement. Usually it's just the name of the method doing the
+     * emission.
+     */
+    private final String name;
+
+    /**
+     * The actual match pattern.
+     */
+    private final MatchPattern pattern;
+
+    /**
+     * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission.
+     */
+    private Method generatorMethod;
+
+    /**
+     * The name of arguments in the order they are expected to be passed to the generator method.
+     */
+    private String[] arguments;
+
+    public MatchStatement(String name, MatchPattern pattern, Method generator, String[] arguments) {
+        this.name = name;
+        this.pattern = pattern;
+        this.generatorMethod = generator;
+        this.arguments = arguments;
+    }
+
+    /**
+     * Attempt to match the current statement against a Node.
+     *
+     * @param builder the current builder instance.
+     * @param node the node to be matched
+     * @param nodes the nodes in the current block
+     * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
+     *         evaluated by the NodeLIRBuilder.
+     */
+    public boolean generate(NodeLIRBuilder builder, int index, ValueNode node, List<ScheduledNode> nodes) {
+        assert index == nodes.indexOf(node);
+        // Check that the basic shape matches
+        Result result = pattern.matchShape(node, this);
+        if (result != Result.OK) {
+            return false;
+        }
+        // Now ensure that the other safety constraints are matched.
+        MatchContext context = new MatchContext(builder, this, index, node, nodes);
+        result = pattern.matchUsage(node, context);
+        if (result == Result.OK) {
+            try {
+                // Invoke the generator method and set the result if it's non null.
+                ComplexMatchResult value = (ComplexMatchResult) generatorMethod.invoke(builder, buildArgList(context));
+                if (value != null) {
+                    context.setResult(value);
+                    MatchStatementSuccess.increment();
+                    return true;
+                }
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+                throw new GraalInternalError(e);
+            }
+        } else {
+            if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) {
+                Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param context
+     * @return the ValueNodes captured by the match rule in the order expected by the
+     *         generatorMethod
+     */
+    private Object[] buildArgList(MatchContext context) {
+        Object[] result = new Object[arguments.length];
+        for (int i = 0; i < arguments.length; i++) {
+            if ("root".equals(arguments[i])) {
+                result[i] = context.getRoot();
+            } else {
+                result[i] = context.namedNode(arguments[i]);
+                if (result[i] == null) {
+                    throw new GraalGraphInternalError("Can't find named node %s", arguments[i]);
+                }
+            }
+        }
+        return result;
+    }
+
+    public String formatMatch(ValueNode root) {
+        return pattern.formatMatch(root);
+    }
+
+    public MatchPattern getPattern() {
+        return pattern;
+    }
+
+    public String getName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.gen.*;
+
+public interface MatchStatementSet {
+    /**
+     * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement}
+     *         instances.
+     */
+    public Class<? extends NodeLIRBuilder> forClass();
+
+    /**
+     * @return the {@link MatchStatement}s available with this {@link NodeLIRBuilder} subclass.
+     */
+    public List<MatchStatement> statements();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * Describes the properties of a node for use when building a {@link MatchPattern}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Repeatable(value = MatchableNodes.class)
+public @interface MatchableNode {
+
+    /**
+     * The {@link ValueNode} subclass this annotation describes. These annotations might work better
+     * if they were directly on the node being described but that may complicate the annotation
+     * processing.
+     */
+    Class<? extends ValueNode> nodeClass();
+
+    /**
+     * The number of matchable inputs, which may be less than the real number of inputs.
+     */
+    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;
+
+    /**
+     * Can a pattern be matched with the operands swapped. This will cause swapped versions of
+     * patterns to be automatically generated.
+     */
+    boolean commutative() default false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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 {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.match;
+
+import java.lang.annotation.*;
+
+/**
+ * The repeatable representation of {@link MatchableNode}. Should never be used directly.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MatchableNodes {
+    MatchableNode[] value() default {};
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri May 02 11:33:47 2014 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
@@ -57,9 +58,14 @@
                 appendPhase(new InliningPhase(canonicalizer));
                 appendPhase(new DeadCodeEliminationPhase());
 
-                if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+                boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+                if (reduceOrEliminate && OptCanonicalizer.getValue()) {
                     appendPhase(canonicalizer);
-                    appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+                    if (FlowSensitiveReduction.getValue()) {
+                        appendPhase(new IterativeFlowSensitiveReductionPhase(canonicalizer));
+                    } else {
+                        appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+                    }
                 }
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri May 02 11:33:47 2014 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 
@@ -72,17 +73,17 @@
      */
     public abstract FrameMap newFrameMap(RegisterConfig registerConfig);
 
-    public abstract LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
+    public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
 
     public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub);
 
-    public abstract NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen);
+    public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
 
     /**
      * @param gen the LIRGenerator the BytecodeLIRBuilder should use
      * @param parser the bytecode parser the BytecodeLIRBuilder should use
      */
-    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         throw GraalInternalError.unimplemented("Baseline compilation is not available for this Backend!");
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.target;
-
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerator} and {@link LIRInstruction}.
- */
-public interface LIRGenLowerable {
-
-    void generate(NodeLIRBuilder generator);
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.target;
-
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to
- * {@link LIRGenerationResult} and {@link LIRInstruction}.
- */
-public interface LIRGenResLowerable {
-
-    void generate(NodeLIRBuilderTool generator, LIRGenerationResult genRes);
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri May 02 11:33:47 2014 +0200
@@ -184,7 +184,6 @@
 
     class NodeUsageIterator implements Iterator<Node> {
 
-        private final int expectedModCount = usageModCount();
         int index = -1;
         Node current;
 
@@ -207,12 +206,10 @@
         }
 
         public boolean hasNext() {
-            assert expectedModCount == usageModCount();
             return current != null;
         }
 
         public Node next() {
-            assert expectedModCount == usageModCount();
             Node result = current;
             if (result == null) {
                 throw new NoSuchElementException();
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java	Fri May 02 11:33:47 2014 +0200
@@ -35,7 +35,7 @@
 
     public AMD64DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, target, linkage);
-        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14});
+        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14});
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri May 02 11:33:47 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri May 02 11:33:47 2014 +0200
@@ -48,6 +48,7 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
 /**
  * HotSpot AMD64 specific backend.
@@ -71,7 +72,7 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new AMD64HotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
@@ -81,12 +82,12 @@
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new AMD64HotSpotNodeLIRBuilder(graph, lirGen);
     }
 
     @Override
-    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         return new AMD64HotSpotBytecodeLIRBuilder(gen, parser);
 
     }
@@ -311,7 +312,7 @@
             MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
             AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
-            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null);
+            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -33,7 +33,7 @@
 
 public class AMD64HotSpotBytecodeLIRBuilder extends BytecodeLIRBuilder {
 
-    public AMD64HotSpotBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) {
+    public AMD64HotSpotBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) {
         super(gen, parser);
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri May 02 11:33:47 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -41,7 +42,7 @@
 @Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction {
 
-    private final Register thread;
+    private final Register threadRegister;
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
     private final int threadLastJavaFpOffset;
@@ -49,32 +50,51 @@
     @Alive(REG) AllocatableValue senderSp;
     @Alive(REG) AllocatableValue senderFp;
 
-    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc, AllocatableValue senderSp,
-                    AllocatableValue senderFp) {
-        this.thread = thread;
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc,
+                    AllocatableValue senderSp, AllocatableValue senderFp, SaveRegistersOp saveRegisterOp) {
+        this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.threadLastJavaFpOffset = threadLastJavaFpOffset;
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.senderFp = senderFp;
+        this.saveRegisterOp = saveRegisterOp;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+        final int totalFrameSize = frameMap.totalFrameSize();
+
+        // Push return address.
         masm.push(asRegister(framePc));
+
+        // Push base pointer.
         masm.push(asRegister(senderFp));
-        masm.movq(rbp, rsp);
+        masm.movq(rbp, stackPointerRegister);
 
         /*
          * Allocate a full sized frame. Since return address and base pointer are already in place
          * (see above) we allocate two words less.
          */
-        masm.decrementq(rsp, totalFrameSize - 2 * crb.target.wordSize);
+        masm.decrementq(stackPointerRegister, totalFrameSize - 2 * crb.target.wordSize);
+
+        // Save return registers after moving the frame.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize), integerResultRegister);
+
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize), floatResultRegister);
 
         // Set up last Java values.
-        masm.movq(new AMD64Address(thread, threadLastJavaSpOffset), rsp);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaSpOffset), stackPointerRegister);
 
         /*
          * Save the PC since it cannot easily be retrieved using the last Java SP after we aligned
@@ -82,12 +102,12 @@
          * blob.
          */
         masm.leaq(rax, new AMD64Address(rip, 0));
-        masm.movq(new AMD64Address(thread, threadLastJavaPcOffset), rax);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaPcOffset), rax);
 
         // Use BP because the frames look interpreted now.
-        masm.movq(new AMD64Address(thread, threadLastJavaFpOffset), rbp);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaFpOffset), rbp);
 
         // Align the stack for the following unpackFrames call.
-        masm.andq(rsp, -(crb.target.stackAlignment));
+        masm.andq(stackPointerRegister, -(crb.target.stackAlignment));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri May 02 11:33:47 2014 +0200
@@ -26,10 +26,10 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.*;
 import static com.oracle.graal.hotspot.replacements.CRC32Substitutions.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.*;
@@ -63,7 +63,8 @@
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
 
-        link(new AMD64DeoptimizationStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64DeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64UncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
 
         // When the java.ext.dirs property is modified then the crypto classes might not be found.
         // If that's the case we ignore the ClassNotFoundException and continue since we cannot
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -26,24 +26,29 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.util.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
+import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
@@ -52,6 +57,7 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
 
 /**
@@ -184,8 +190,8 @@
         super.emitForeignCall(linkage, result, arguments, temps, info);
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        append(new AMD64HotSpotLeaveCurrentStackFrameOp());
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        append(new AMD64HotSpotLeaveCurrentStackFrameOp(saveRegisterOp));
     }
 
     public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
@@ -194,18 +200,18 @@
         append(new AMD64HotSpotLeaveDeoptimizedStackFrameOp(frameSizeVariable, initialInfoVariable));
     }
 
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        Register thread = getProviders().getRegisters().getThreadRegister();
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
         Variable framePcVariable = load(framePc);
         Variable senderSpVariable = load(senderSp);
         Variable senderFpVariable = load(senderFp);
-        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
-                        senderSpVariable, senderFpVariable));
+        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
+                        senderSpVariable, senderFpVariable, saveRegisterOp));
     }
 
-    public void emitLeaveUnpackFramesStackFrame() {
-        Register thread = getProviders().getRegisters().getThreadRegister();
-        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset()));
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), saveRegisterOp));
     }
 
     /**
@@ -281,7 +287,8 @@
             result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
             append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
         } else {
-            result = super.emitForeignCall(hotspotLinkage, deoptInfo, args);
+            assert deoptInfo == null;
+            result = super.emitForeignCall(hotspotLinkage, null, args);
         }
 
         if (destroysRegisters) {
@@ -315,6 +322,21 @@
         return result;
     }
 
+    public Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(DeoptimizationFetchUnrollInfoCallNode.FETCH_UNROLL_INFO);
+
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(Kind.Long));
+        append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
     protected AMD64ZapRegistersOp emitZapRegisters(Register[] zappedRegisters, Constant[] zapValues) {
         AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappedRegisters, zapValues);
         append(zap);
@@ -542,6 +564,14 @@
         return result;
     }
 
+    public static Register asNarrowReg(Value value) {
+        if (value.getPlatformKind() != NarrowOopStamp.NarrowOop) {
+            throw new InternalError("needed NarrowOop got: " + value.getKind());
+        } else {
+            return asRegister(value);
+        }
+    }
+
     public Value emitAtomicReadAndWrite(Value address, Value newValue) {
         PlatformKind kind = newValue.getPlatformKind();
         Kind memKind = getMemoryKind(kind);
@@ -551,4 +581,59 @@
         return result;
     }
 
+    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
+        @Alive({COMPOSITE}) protected AMD64AddressValue x;
+        @Use({CONST, REG}) protected Value y;
+        @State protected LIRFrameState state;
+
+        public CompareMemoryCompressedOp(AMD64AddressValue x, Value y, LIRFrameState state) {
+            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        protected void verify() {
+            assert y instanceof Constant || y.getPlatformKind() == NarrowOopStamp.NarrowOop;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            if (y instanceof Constant) {
+                Constant constant = (Constant) y;
+                if (constant.isNull()) {
+                    masm.cmpl(x.toAddress(), 0);
+                } else {
+                    if (y.getKind() == Kind.Object) {
+                        crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
+                    } else if (y.getKind() == Kind.Long) {
+                        crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere();
+                    }
+                    masm.cmpl(x.toAddress(), 0xdeaddead);
+                }
+            } else {
+                masm.cmpl(asNarrowReg(y), x.toAddress());
+            }
+        }
+    }
+
+    protected void emitCompareBranchMemoryCompressed(Value left, Value right, Condition cond, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability, LIRFrameState state) {
+        boolean mirrored = false;
+        if (left instanceof AMD64AddressValue) {
+            append(new CompareMemoryCompressedOp((AMD64AddressValue) left, right, state));
+        } else {
+            assert right instanceof AMD64AddressValue;
+            append(new CompareMemoryCompressedOp((AMD64AddressValue) right, left, state));
+            mirrored = true;
+        }
+
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -24,19 +24,50 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Pops the current frame off the stack including the return address.
+ * Pops the current frame off the stack including the return address and restores the return
+ * registers stored on the stack.
  */
 @Opcode("LEAVE_CURRENT_STACK_FRAME")
 final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp {
 
+    private final SaveRegistersOp saveRegisterOp;
+
+    public AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) {
+        this.saveRegisterOp = saveRegisterOp;
+    }
+
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointer = registerConfig.getFrameRegister();
+
+        // Restore integer result register.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+        masm.movptr(rdx, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(rdx) * stackSlotSize));
+
+        // Restore float result register.
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
+
+        /*
+         * All of the register save area will be popped of the stack. Only the return address
+         * remains.
+         */
         leaveFrameAndRestoreRbp(crb, masm);
-        masm.addq(rsp, crb.target.arch.getReturnAddressSize());
+
+        // Remove return address.
+        masm.addq(stackPointer, crb.target.arch.getReturnAddressSize());
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,13 +26,14 @@
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Pops the current frame off the stack including the return address.
+ * Pops a deoptimized stack frame off the stack including the return address.
  */
 @Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
 final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp {
@@ -47,9 +48,13 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        masm.addq(rsp, asRegister(frameSize));
-        // Restore the frame pointer before stack bang because if a stack overflow is thrown it
-        // needs to be pushed (and preserved).
+        Register stackPointer = crb.frameMap.registerConfig.getFrameRegister();
+        masm.addq(stackPointer, asRegister(frameSize));
+
+        /*
+         * Restore the frame pointer before stack bang because if a stack overflow is thrown it
+         * needs to be pushed (and preserved).
+         */
         masm.movq(rbp, asRegister(framePointer));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.amd64.AMD64.*;
-
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -38,26 +38,42 @@
 @Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction {
 
-    private final Register thread;
+    private final Register threadRegister;
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
     private final int threadLastJavaFpOffset;
 
-    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset) {
-        this.thread = thread;
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, SaveRegistersOp saveRegisterOp) {
+        this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.saveRegisterOp = saveRegisterOp;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+
         // Restore stack pointer.
-        masm.movq(rsp, new AMD64Address(thread, threadLastJavaSpOffset));
+        masm.movq(stackPointerRegister, new AMD64Address(threadRegister, threadLastJavaSpOffset));
 
         // Clear last Java frame values.
-        masm.movslq(new AMD64Address(thread, threadLastJavaSpOffset), 0);
-        masm.movslq(new AMD64Address(thread, threadLastJavaPcOffset), 0);
-        masm.movslq(new AMD64Address(thread, threadLastJavaFpOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaPcOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaFpOffset), 0);
+
+        // Restore return values.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.graal.hotspot.amd64;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.data.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Specialized code gen for comparison with compressed memory.
- */
-
-public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole {
-    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
-        @Alive({COMPOSITE}) protected AMD64AddressValue x;
-        @Use({CONST}) protected Value y;
-        @State protected LIRFrameState state;
-
-        public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) {
-            assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops;
-            this.x = x;
-            this.y = y;
-            this.state = state;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            Constant constant = (Constant) y;
-            if (constant.isNull()) {
-                masm.cmpl(x.toAddress(), 0);
-            } else {
-                if (y.getKind() == Kind.Object) {
-                    crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true));
-                } else if (y.getKind() == Kind.Long) {
-                    crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true));
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-                if (state != null) {
-                    crb.recordImplicitException(masm.position(), state);
-                }
-                masm.cmpl(x.toAddress(), 0xdeaddead);
-            }
-        }
-    }
-
-    AMD64HotSpotMemoryPeephole(AMD64NodeLIRBuilder gen) {
-        super(gen);
-    }
-
-    @Override
-    protected Kind getMemoryKind(Access access) {
-        PlatformKind kind = gen.getLIRGenerator().getPlatformKind(access.asNode().stamp());
-        if (kind == NarrowOopStamp.NarrowOop) {
-            return Kind.Int;
-        } else {
-            return (Kind) kind;
-        }
-    }
-
-    @Override
-    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
-                    double trueLabelProbability) {
-        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
-            ValueNode other = selectOtherInput(left, right, access);
-            Kind kind = getMemoryKind(access);
-
-            if (other.isConstant() && kind == Kind.Object && access.isCompressible()) {
-                ensureEvaluated(other);
-                gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access)));
-                Condition finalCondition = right == access ? cond.mirror() : cond;
-                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
-                return true;
-            }
-        }
-
-        return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
-    }
-}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -32,7 +32,9 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
@@ -45,16 +47,56 @@
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
  */
+@MatchableNodeImport({"com.oracle.graal.hotspot.nodes.HotSpotMatchableNodes"})
 public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) {
+    private static ValueNode filterCompression(ValueNode node) {
+        ValueNode result = node;
+        while (result instanceof CompressionNode) {
+            result = ((CompressionNode) result).getInput();
+        }
+        return result;
+    }
+
+    private void emitCompareCompressedMemory(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
+        Value value;
+        // This works by embedding the compressed form for constants, so force a constant instead of
+        // respecting what operand() would return.
+        if (valueNode.isConstant()) {
+            value = valueNode.asConstant();
+        } else {
+            value = gen.load(operand(valueNode));
+        }
+        AMD64AddressValue address = makeAddress(access);
+
+        Condition cond = compare.condition();
+        Value left;
+        Value right;
+        if (access == filterCompression(compare.x())) {
+            left = value;
+            right = address;
+        } else {
+            assert access == filterCompression(compare.y());
+            left = address;
+            right = value;
+            cond = cond.mirror();
+        }
+
+        LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+        double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+        getGen().emitCompareBranchMemoryCompressed(left, right, cond, trueLabel, falseLabel, trueLabelProbability, getState(access));
+    }
+
+    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         super(graph, gen);
-        memoryPeephole = new AMD64HotSpotMemoryPeephole(this);
         assert gen instanceof AMD64HotSpotLIRGenerator;
         assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
         ((AMD64HotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
@@ -201,4 +243,18 @@
         gen.emitMove(result, raxLocal);
         setResult(x, result);
     }
+
+    @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) {
+        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
+            return builder -> {
+                emitCompareCompressedMemory(root, value, access, compare);
+                return null;
+            };
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Fri May 02 11:33:47 2014 +0200
@@ -27,12 +27,11 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRGenLowerable {
+public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
 
     private final Constant functionPointer;
     @Input private final NodeInputList<ValueNode> args;
@@ -44,7 +43,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder generator) {
+    public void generate(NodeLIRBuilderTool generator) {
         AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
         Value[] parameter = new Value[args.count()];
         JavaType[] parameterTypes = new JavaType[args.count()];
@@ -55,7 +54,7 @@
         ResolvedJavaType returnType = stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess());
         CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes,
                         generator.getLIRGeneratorTool().target(), false);
-        ((AMD64LIRGenerator) gen.getLIRGeneratorTool()).emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
+        gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
         if (this.getKind() != Kind.Void) {
             generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64UncommonTrapStub.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+
+final class AMD64UncommonTrapStub extends UncommonTrapStub {
+
+    private RegisterConfig registerConfig;
+
+    public AMD64UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        Register[] allocatable = new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14};
+        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), allocatable);
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Fri May 02 11:33:47 2014 +0200
@@ -49,7 +49,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.gpu.*;
@@ -70,6 +69,7 @@
 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.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
@@ -302,9 +302,8 @@
         for (CodeAnnotation annotation : hostCode.getAnnotations()) {
             result.addAnnotation(annotation);
         }
-        CompilationResult.Mark[] noMarks = {};
         for (Mark mark : hostCode.getMarks()) {
-            result.recordMark(mark.pcOffset, mark.id, noMarks);
+            result.recordMark(mark.pcOffset, mark.id);
         }
         for (ExceptionHandler handler : hostCode.getExceptionHandlers()) {
             result.recordExceptionHandler(handler.pcOffset, handler.handlerPos);
@@ -376,7 +375,7 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new HSAILHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
@@ -386,7 +385,7 @@
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new HSAILHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -151,6 +151,7 @@
         return nodeResult;
     }
 
+    @Override
     public Value emitAtomicReadAndAdd(Value address, Value delta) {
         PlatformKind kind = delta.getPlatformKind();
         Kind memKind = getMemoryKind(kind);
@@ -161,6 +162,16 @@
     }
 
     @Override
+    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        PlatformKind kind = newValue.getPlatformKind();
+        Kind memKind = getMemoryKind(kind);
+        Variable result = newVariable(kind);
+        HSAILAddressValue addressValue = asAddressValue(address);
+        append(new HSAILMove.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
+        return result;
+    }
+
+    @Override
     public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
         emitDeoptimizeInner(actionAndReason, state, "emitDeoptimize");
     }
@@ -270,31 +281,8 @@
         return result;
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveUnpackFramesStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
     public SaveRegistersOp emitSaveAllRegisters() {
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        throw GraalInternalError.unimplemented();
-    }
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -44,7 +44,7 @@
  */
 public class HSAILHotSpotNodeLIRBuilder extends HSAILNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Fri May 02 11:33:47 2014 +0200
@@ -38,7 +38,6 @@
 import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.gpu.*;
@@ -55,6 +54,7 @@
 import com.oracle.graal.lir.ptx.PTXControlFlow.PTXPredicatedLIRInstruction;
 import com.oracle.graal.lir.ptx.PTXMemOp.LoadReturnAddrOp;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -356,12 +356,12 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new PTXHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new PTXHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -72,31 +72,8 @@
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveUnpackFramesStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
     public SaveRegistersOp emitSaveAllRegisters() {
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        throw GraalInternalError.unimplemented();
-    }
 }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -35,7 +35,7 @@
  */
 public class PTXHotSpotNodeLIRBuilder extends PTXNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,11 +35,14 @@
 
     public SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, target, linkage);
-        registerConfig = new SPARCHotSpotRegisterConfig(target, new Register[]{o0, o1, o2, o3, o4, o5, o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, f0, f1, f2, f3, f4, f5, f6, f7});
+        // This is basically the maximum we can spare. All other G and O register are used.
+        Register[] allocatable = new Register[]{g1, g3, g4, g5, o0, o1, o2, o3, o4};
+        registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable);
     }
 
     @Override
     public RegisterConfig getRegisterConfig() {
         return registerConfig;
     }
+
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Fri May 02 11:33:47 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri May 02 11:33:47 2014 +0200
@@ -44,7 +44,6 @@
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.RestoreWindow;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.hotspot.meta.*;
@@ -55,6 +54,7 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
 /**
  * HotSpot SPARC specific backend.
@@ -78,12 +78,17 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
         return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes);
     }
 
     @Override
-    public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) {
+    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        return new SPARCHotSpotLIRGenerationResult(lir, frameMap, stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         return new SPARCHotSpotNodeLIRBuilder(graph, lirGen);
     }
 
@@ -190,11 +195,6 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
-        return new LIRGenerationResultBase(lir, frameMap);
-    }
-
-    @Override
     public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
         SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
         FrameMap frameMap = crb.frameMap;
@@ -232,7 +232,7 @@
             MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
             SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
-            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null);
+            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,9 +48,8 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-
         // Save last Java frame.
-        new Add(stackPointer, new SPARCAddress(stackPointer, 0).getDisplacement(), g4).emit(masm);
+        new Add(stackPointer, STACK_BIAS, g4).emit(masm);
         new Stx(g4, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
 
         // Save the thread register when calling out to the runtime.
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Fri May 02 11:33:47 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that enters a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Temp(REG) AllocatableValue scratch;
+
+    SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.scratch = scratch;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        Register framePcRegister = asRegister(framePc);
+        Register senderSpRegister = asRegister(senderSp);
+        Register scratchRegister = asRegister(scratch);
+
+        // Save final sender SP to O5_savedSP.
+        new Mov(senderSpRegister, o5).emit(masm);
+
+        // Load final frame PC.
+        new Mov(framePcRegister, o7).emit(masm);
+
+        // Allocate a full sized frame.
+        new Save(sp, -totalFrameSize, sp).emit(masm);
+
+        new Mov(i0, o0).emit(masm);
+        new Mov(i1, o1).emit(masm);
+        new Mov(i2, o2).emit(masm);
+        new Mov(i3, o3).emit(masm);
+        new Mov(i4, o4).emit(masm);
+
+        // Set up last Java values.
+        new Add(sp, STACK_BIAS, scratchRegister).emit(masm);
+        new Stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+
+        // Clear last Java PC.
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        new Mov(thread, l7).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Fri May 02 11:33:47 2014 +0200
@@ -24,10 +24,10 @@
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,14 +22,49 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.gen.*;
 
-public interface SPARCHotSpotLIRGenerationResult extends LIRGenerationResult {
+public class SPARCHotSpotLIRGenerationResult extends LIRGenerationResultBase {
+
+    /**
+     * The slot reserved for storing the original return address when a frame is marked for
+     * deoptimization. The return address slot in the callee is overwritten with the address of a
+     * deoptimization stub.
+     */
+    private StackSlot deoptimizationRescueSlot;
+    private final Object stub;
+
+    /**
+     * Map from debug infos that need to be updated with callee save information to the operations
+     * that provide the information.
+     */
+    private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = new HashMap<>();
 
-    StackSlot getDeoptimizationRescueSlot();
+    public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) {
+        super(lir, frameMap);
+        this.stub = stub;
+    }
+
+    StackSlot getDeoptimizationRescueSlot() {
+        return deoptimizationRescueSlot;
+    }
 
-    Stub getStub();
+    public final void setDeoptimizationRescueSlot(StackSlot deoptimizationRescueSlot) {
+        this.deoptimizationRescueSlot = deoptimizationRescueSlot;
+    }
+
+    Stub getStub() {
+        return (Stub) stub;
+    }
+
+    Map<LIRFrameState, SaveRegistersOp> getCalleeSaveInfo() {
+        return calleeSaveInfo;
+    }
 
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*;
+import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -264,38 +266,78 @@
         throw GraalInternalError.unimplemented();
     }
 
-    public SaveRegistersOp emitSaveAllRegisters() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    /**
+     * @param savedRegisters the registers saved by this operation which may be subject to pruning
+     * @param savedRegisterLocations the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be pruned
+     */
+    protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations, boolean supportsRemove) {
+        SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+        append(save);
+        return save;
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    public SaveRegistersOp emitSaveAllRegisters() {
+        // We save all registers that were not saved by the save instruction.
+        // @formatter:off
+        Register[] savedRegisters = {
+                        // CPU
+                        g1, g3, g4, g5,
+                        // FPU
+                        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+                        f8,  f9,  f10, f11, f12, f13, f14, f15,
+                        f16, f17, f18, f19, f20, f21, f22, f23,
+                        f24, f25, f26, f27, f28, f29, f30, f31
+        };
+        // @formatter:on
+        StackSlot[] savedRegisterLocations = new StackSlot[savedRegisters.length];
+        for (int i = 0; i < savedRegisters.length; i++) {
+            PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+            assert kind != Kind.Illegal;
+            StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind);
+            savedRegisterLocations[i] = spillSlot;
+        }
+        return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
+    }
+
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        append(new SPARCHotSpotLeaveCurrentStackFrameOp());
     }
 
     public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp());
     }
 
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable scratchVariable = newVariable(getHostWordKind());
+        append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable));
     }
 
-    public void emitLeaveUnpackFramesStackFrame() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset()));
     }
 
     public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        Variable frameSizeVariable = load(frameSize);
+        Variable framePcVariable = load(framePc);
+        Variable senderSpVariable = load(senderSp);
+        Variable initialInfoVariable = load(initialInfo);
+        append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable));
     }
 
     public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
+
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
+        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister));
+        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(Kind.Long), trapRequest);
+        append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister));
+
+        return result;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack.
+ */
+@Opcode("LEAVE_CURRENT_STACK_FRAME")
+final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        new Mov(o0, i0).emit(masm);
+        new Mov(o1, i1).emit(masm);
+        new Mov(o2, i2).emit(masm);
+        new Mov(o3, i3).emit(masm);
+        new Mov(o4, i4).emit(masm);
+
+        leaveFrame(crb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pops the current frame off the stack including the return address.
+ */
+@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
+final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCHotSpotEpilogueOp {
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        // Save O registers over restore.
+        new Mov(o0, i0).emit(masm);
+        new Mov(o1, i1).emit(masm);
+        new Mov(o2, i2).emit(masm);
+        new Mov(o3, i3).emit(masm);
+        new Mov(o4, i4).emit(masm);
+
+        new RestoreWindow().emit(masm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits code that leaves a stack frame which is tailored to call the C++ method
+ * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}.
+ */
+@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
+final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+
+    private final Register thread;
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaPcOffset;
+    private final int threadJavaFrameAnchorFlagsOffset;
+
+    SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) {
+        this.thread = thread;
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaPcOffset = threadLastJavaPcOffset;
+        this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        /*
+         * Safe thread register manually since we are not using LEAF_SP for {@link
+         * DeoptimizationStub#UNPACK_FRAMES}.
+         */
+        new Mov(l7, thread).emit(masm);
+
+        // Clear last Java frame values.
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm);
+        new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm);
+        new Stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -43,7 +43,7 @@
 
 public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) {
+    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
         super(graph, lirGen);
         assert gen instanceof SPARCHotSpotLIRGenerator;
         assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Pushes an interpreter frame to the stack.
+ */
+@Opcode("PUSH_INTERPRETER_FRAME")
+final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction {
+
+    @Alive(REG) AllocatableValue frameSize;
+    @Alive(REG) AllocatableValue framePc;
+    @Alive(REG) AllocatableValue senderSp;
+    @Alive(REG) AllocatableValue initialInfo;
+
+    SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) {
+        this.frameSize = frameSize;
+        this.framePc = framePc;
+        this.senderSp = senderSp;
+        this.initialInfo = initialInfo;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        final Register frameSizeRegister = asRegister(frameSize);
+        final Register framePcRegister = asRegister(framePc);
+        final Register senderSpRegister = asRegister(senderSp);
+
+        // Save sender SP to O5_savedSP.
+        new Mov(senderSpRegister, o5).emit(masm);
+
+        new Neg(frameSizeRegister).emit(masm);
+        new Save(sp, frameSizeRegister, sp).emit(masm);
+
+        new Mov(i0, o0).emit(masm);
+        new Mov(i1, o1).emit(masm);
+        new Mov(i2, o2).emit(masm);
+        new Mov(i3, o3).emit(masm);
+        new Mov(i4, o4).emit(masm);
+
+        // NOTE: Don't touch I5 as it contains valuable saved SP!
+
+        // Move frame's new PC into i7
+        new Mov(framePcRegister, i7).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Fri May 02 11:33:47 2014 +0200
@@ -98,25 +98,27 @@
 
     private static Register[] initAllocatable(boolean reserveForHeapBase) {
         Register[] registers = null;
-        // @formatter:off
         if (reserveForHeapBase) {
-            registers = new Register[] {
+            // @formatter:off
+            registers = new Register[]{
                         // TODO this is not complete
                         o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
                         f0, f1, f2, f3, f4, f5, f6, f7
-                      };
+            };
+            // @formatter:on
         } else {
-            registers = new Register[] {
+            // @formatter:off
+            registers = new Register[]{
                         // TODO this is not complete
                         o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/
                         f0, f1, f2, f3, f4, f5, f6, f7
-                      };
+            };
+            // @formatter:on
         }
-       // @formatter:on
 
         if (RegisterPressure.getValue() != null) {
             String[] names = RegisterPressure.getValue().split(",");
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Fri May 02 11:33:47 2014 +0200
@@ -36,6 +36,8 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 
+import edu.umd.cs.findbugs.annotations.*;
+
 /**
  * Emits a safepoint poll.
  */
@@ -43,7 +45,7 @@
 public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
 
     @State protected LIRFrameState state;
-    @Temp({OperandFlag.REG}) private AllocatableValue temp;
+    @SuppressFBWarnings(value = "BC_IMPOSSIBLE_CAST", justification = "changed by the register allocator") @Temp({OperandFlag.REG}) private AllocatableValue temp;
 
     private final HotSpotVMConfig config;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 02 11:33:47 2014 +0200
@@ -26,6 +26,7 @@
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static com.oracle.graal.phases.common.InliningUtil.*;
@@ -117,11 +118,23 @@
      */
     private final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
 
-    public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) {
+    /**
+     * The address of the native CompileTask associated with this compilation. If 0L, then this
+     * compilation is being managed by a Graal compilation queue otherwise its managed by a native
+     * HotSpot compilation queue.
+     */
+    private final long ctask;
+
+    public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long ctask, boolean blocking) {
         this.backend = backend;
         this.method = method;
         this.entryBCI = entryBCI;
-        this.id = method.allocateCompileId(entryBCI);
+        if (ctask == 0L) {
+            this.id = method.allocateCompileId(entryBCI);
+        } else {
+            this.id = unsafe.getInt(ctask + backend.getRuntime().getConfig().compileTaskCompileIdOffset);
+        }
+        this.ctask = ctask;
         this.blocking = blocking;
         this.taskId = uniqueTaskIds.incrementAndGet();
         this.status = new AtomicReference<>(CompilationStatus.Queued);
@@ -337,13 +350,17 @@
                 System.exit(-1);
             }
         } finally {
+            int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+            if (ctask != 0L) {
+                unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
+            }
             if ((config.ciTime || config.ciTimeEach || PrintCompRate.getValue() != 0) && installedCode != null) {
-                long processedBytes = InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes;
+
                 long time = CompilationTime.getCurrentValue() - previousCompilationTime;
                 TimeUnit timeUnit = CompilationTime.getTimeUnit();
                 long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
                 CompilerToVM c2vm = backend.getRuntime().getCompilerToVM();
-                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, (int) processedBytes, time, timeUnitsPerSecond, installedCode);
+                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode);
             }
 
             if (clearFromCompilationQueue) {
@@ -388,7 +405,7 @@
         final HotSpotCodeCacheProvider codeCache = backend.getProviders().getCodeCache();
         InstalledCode installedCode = null;
         try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) {
-            installedCode = codeCache.installMethod(method, compResult);
+            installedCode = codeCache.installMethod(method, compResult, ctask);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Fri May 02 11:33:47 2014 +0200
@@ -317,7 +317,7 @@
     class CTWCompilationTask extends CompilationTask {
 
         CTWCompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method) {
-            super(backend, method, INVOCATION_ENTRY_BCI, false);
+            super(backend, method, INVOCATION_ENTRY_BCI, 0L, false);
         }
 
         /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri May 02 11:33:47 2014 +0200
@@ -45,11 +45,6 @@
 public abstract class HotSpotBackend extends Backend {
 
     /**
-     * Descriptor for {@link DeoptimizationStub}.
-     */
-    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
-
-    /**
      * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
      * {@linkplain HotSpotVMConfig#codeInstallerMarkIdExceptionHandlerEntry exception handler} in a
      * compiled method.
@@ -57,11 +52,6 @@
     public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class);
 
     /**
-     * Descriptor for SharedRuntime::deopt_blob()-&gt;unpack().
-     */
-    public static final ForeignCallDescriptor DEOPT_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class);
-
-    /**
      * Descriptor for SharedRuntime::get_ic_miss_stub().
      */
     public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Fri May 02 11:33:47 2014 +0200
@@ -34,11 +34,17 @@
     public final HotSpotResolvedJavaMethod method;
     public final int entryBCI;
     public final int id;
+    public final long ctask;
 
     public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult) {
+        this(target, method, compResult, 0L);
+    }
+
+    public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) {
         super(target, compResult);
         this.method = method;
         this.entryBCI = compResult.getEntryBCI();
         this.id = compResult.getId();
+        this.ctask = ctask;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Fri May 02 11:33:47 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CompilationResult.Call;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Fri May 02 11:33:47 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -39,6 +40,16 @@
 public abstract class HotSpotHostBackend extends HotSpotBackend implements HostBackend {
 
     /**
+     * Descriptor for {@link DeoptimizationStub#deoptimizationHandler}.
+     */
+    public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptimizationHandler", void.class);
+
+    /**
+     * Descriptor for {@link UncommonTrapStub#uncommonTrapHandler}.
+     */
+    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
+
+    /**
      * This will be 0 if stack banging is disabled.
      */
     protected final int pagesToBang;
@@ -63,7 +74,7 @@
             try (Scope s = Debug.scope("RegisterReplacements", new DebugDumpScope("RegisterReplacements"))) {
                 ServiceLoader<ReplacementsProvider> sl = ServiceLoader.loadInstalled(ReplacementsProvider.class);
                 for (ReplacementsProvider replacementsProvider : sl) {
-                    replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, replacements, providers.getCodeCache().getTarget());
+                    replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, providers.getSnippetReflection(), replacements, providers.getCodeCache().getTarget());
                 }
                 if (BootstrapReplacements.getValue()) {
                     for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.gen.*;
 
@@ -43,21 +45,87 @@
      */
     void emitTailcall(Value[] args, Value address);
 
-    void emitLeaveCurrentStackFrame();
-
-    void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo);
+    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
 
-    void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp);
-
-    void emitLeaveUnpackFramesStackFrame();
-
+    /**
+     * Emits code for a {@link SaveAllRegistersNode}.
+     *
+     * @return a {@link SaveRegistersOp} operation
+     */
     SaveRegistersOp emitSaveAllRegisters();
 
-    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
+    /**
+     * Emits code for a {@link LeaveCurrentStackFrameNode}.
+     *
+     * @param saveRegisterOp saved registers
+     */
+    default void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link LeaveDeoptimizedStackFrameNode}.
+     *
+     * @param frameSize
+     * @param initialInfo
+     */
+    default void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link EnterUnpackFramesStackFrameNode}.
+     *
+     * @param framePc
+     * @param senderSp
+     * @param senderFp
+     * @param saveRegisterOp
+     */
+    default void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 
-    void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo);
+    /**
+     * Emits code for a {@link LeaveUnpackFramesStackFrameNode}.
+     *
+     * @param saveRegisterOp
+     */
+    default void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link PushInterpreterFrameNode}.
+     *
+     * @param frameSize
+     * @param framePc
+     * @param senderSp
+     * @param initialInfo
+     */
+    default void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
 
-    Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp);
+    /**
+     * Emits code for a {@link UncommonTrapCallNode}.
+     *
+     * @param trapRequest
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link DeoptimizationFetchUnrollInfoCallNode}.
+     *
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 
     /**
      * Gets a stack slot for a lock at a given lock nesting depth.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri May 02 11:33:47 2014 +0200
@@ -170,7 +170,7 @@
                 String name = annotation.name();
                 Flags.Flag entry = flags.get(name);
                 if (entry == null) {
-                    if (!isRequired(currentArch, annotation.archs())) {
+                    if (annotation.optional() || !isRequired(currentArch, annotation.archs())) {
                         continue;
                     }
                     throw new IllegalArgumentException("flag not found: " + name);
@@ -716,6 +716,7 @@
     @HotSpotVMFlag(name = "CIPrintCompilerName") @Stable public boolean printCompilerName;
     @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining;
     @HotSpotVMFlag(name = "GraalUseFastLocking") @Stable public boolean useFastLocking;
+    @HotSpotVMFlag(name = "UseGraalCompilationQueue", optional = true) @Stable public boolean useGraalCompilationQueue;
     @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable;
     @HotSpotVMFlag(name = "GPUOffload") @Stable public boolean gpuOffload;
     @HotSpotVMFlag(name = "TieredCompilation") @Stable public boolean tieredCompilation;
@@ -794,6 +795,7 @@
     // offsets, ...
     @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages;
     @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging;
+    @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias;
 
     @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset;
     @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset;
@@ -1066,6 +1068,9 @@
     @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
     @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
 
+    @HotSpotVMField(name = "CompileTask::_compile_id", type = "uint", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskCompileIdOffset;
+    @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset;
+
     /**
      * Value of Method::extra_stack_entries().
      */
@@ -1352,8 +1357,6 @@
         return unsafe.getAddress(codeCacheHeap + codeHeapMemoryOffset + virtualSpaceHighBoundaryOffset);
     }
 
-    @Stable public long handleDeoptStub;
-
     @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub;
     @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub;
     @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_encryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingEncryptAESCryptStub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java	Fri May 02 11:33:47 2014 +0200
@@ -36,4 +36,6 @@
      * required on all architectures.
      */
     String[] archs() default {};
+
+    boolean optional() default false;
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Fri May 02 11:33:47 2014 +0200
@@ -33,8 +33,10 @@
     /**
      * Compiles a method to machine code. This method is called from the VM
      * (VMToCompiler::compileMethod).
+     *
+     * @param ctask the CompileTask pointer if this is a request from a HotSpot compiler thread
      */
-    void compileMethod(long metaspaceMethod, int entryBCI, boolean blocking);
+    void compileMethod(long metaspaceMethod, int entryBCI, long ctask, boolean blocking);
 
     void shutdownCompiler() throws Exception;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 02 11:33:47 2014 +0200
@@ -192,55 +192,57 @@
             }
         }
 
-        // Create compilation queue.
-        CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() {
-            public GraalDebugConfig getDebugConfig() {
-                return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null;
-            }
-        });
-        compileQueue = new Queue(factory);
+        if (runtime.getConfig().useGraalCompilationQueue) {
+
+            // Create compilation queue.
+            CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() {
+                public GraalDebugConfig getDebugConfig() {
+                    return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null;
+                }
+            });
+            compileQueue = new Queue(factory);
 
-        // Create queue status printing thread.
-        if (PrintQueue.getValue()) {
-            Thread t = new Thread() {
+            // Create queue status printing thread.
+            if (PrintQueue.getValue()) {
+                Thread t = new Thread() {
 
-                @Override
-                public void run() {
-                    while (true) {
-                        TTY.println(compileQueue.toString());
-                        try {
-                            Thread.sleep(1000);
-                        } catch (InterruptedException e) {
+                    @Override
+                    public void run() {
+                        while (true) {
+                            TTY.println(compileQueue.toString());
+                            try {
+                                Thread.sleep(1000);
+                            } catch (InterruptedException e) {
+                            }
                         }
                     }
-                }
-            };
-            t.setDaemon(true);
-            t.start();
-        }
-
-        if (PrintCompRate.getValue() != 0) {
-            if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) {
-                throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach");
+                };
+                t.setDaemon(true);
+                t.start();
             }
-            Thread t = new Thread() {
+
+            if (PrintCompRate.getValue() != 0) {
+                if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) {
+                    throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach");
+                }
+                Thread t = new Thread() {
 
-                @Override
-                public void run() {
-                    while (true) {
-                        runtime.getCompilerToVM().printCompilationStatistics(true, false);
-                        runtime.getCompilerToVM().resetCompilationStatistics();
-                        try {
-                            Thread.sleep(PrintCompRate.getValue());
-                        } catch (InterruptedException e) {
+                    @Override
+                    public void run() {
+                        while (true) {
+                            runtime.getCompilerToVM().printCompilationStatistics(true, false);
+                            runtime.getCompilerToVM().resetCompilationStatistics();
+                            try {
+                                Thread.sleep(PrintCompRate.getValue());
+                            } catch (InterruptedException e) {
+                            }
                         }
                     }
-                }
-            };
-            t.setDaemon(true);
-            t.start();
+                };
+                t.setDaemon(true);
+                t.start();
+            }
         }
-
         BenchmarkCounters.initialize(runtime.getCompilerToVM());
 
         compilerStartTime = System.nanoTime();
@@ -346,23 +348,24 @@
     private void enqueue(Method m) throws Throwable {
         JavaMethod javaMethod = runtime.getHostProviders().getMetaAccess().lookupJavaMethod(m);
         assert !((HotSpotResolvedJavaMethod) javaMethod).isAbstract() && !((HotSpotResolvedJavaMethod) javaMethod).isNative() : javaMethod;
-        compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, false);
+        compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, 0L, false);
     }
 
     public void shutdownCompiler() throws Exception {
-        try (Enqueueing enqueueing = new Enqueueing()) {
-            // We have to use a privileged action here because shutting down the compiler might be
-            // called from user code which very likely contains unprivileged frames.
-            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
-                public Void run() throws Exception {
-                    if (compileQueue != null) {
-                        compileQueue.shutdown();
+        if (runtime.getConfig().useGraalCompilationQueue) {
+            try (Enqueueing enqueueing = new Enqueueing()) {
+                // We have to use a privileged action here because shutting down the compiler might
+                // be called from user code which very likely contains unprivileged frames.
+                AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws Exception {
+                        if (compileQueue != null) {
+                            compileQueue.shutdown();
+                        }
+                        return null;
                     }
-                    return null;
-                }
-            });
+                });
+            }
         }
-
         printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false);
         phaseTransition("final");
 
@@ -537,22 +540,34 @@
     }
 
     @Override
-    public void compileMethod(long metaspaceMethod, final int entryBCI, final boolean blocking) {
+    public void compileMethod(long metaspaceMethod, final int entryBCI, long ctask, final boolean blocking) {
         final HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
-        // We have to use a privileged action here because compilations are enqueued from user code
-        // which very likely contains unprivileged frames.
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-            public Void run() {
-                compileMethod(method, entryBCI, blocking);
-                return null;
-            }
-        });
+        if (ctask != 0L) {
+            // This is on a VM CompilerThread - no user frames exist
+            compileMethod(method, entryBCI, ctask, false);
+        } else {
+            // We have to use a privileged action here because compilations are
+            // enqueued from user code which very likely contains unprivileged frames.
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    compileMethod(method, entryBCI, 0L, blocking);
+                    return null;
+                }
+            });
+        }
     }
 
     /**
      * Compiles a method to machine code.
      */
-    void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, final boolean blocking) {
+    void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, long ctask, final boolean blocking) {
+        if (ctask != 0L) {
+            HotSpotBackend backend = runtime.getHostBackend();
+            CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, false);
+            task.runCompilation(false);
+            return;
+        }
+
         boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
         if (osrCompilation && bootstrapRunning) {
             // no OSR compilations during bootstrap - the compiler is just too slow at this point,
@@ -575,7 +590,7 @@
                 assert method.isQueuedForCompilation();
 
                 HotSpotBackend backend = runtime.getHostBackend();
-                CompilationTask task = new CompilationTask(backend, method, entryBCI, block);
+                CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, block);
 
                 try {
                     compileQueue.execute(task);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Fri May 02 11:33:47 2014 +0200
@@ -99,7 +99,6 @@
 
     private static final boolean DUMP_STATIC = false;
 
-    public static String excludedClassPrefix = null;
     public static boolean enabled = false;
 
     public static final ConcurrentHashMap<String, Integer> indexes = new ConcurrentHashMap<>();
@@ -108,14 +107,23 @@
     public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>();
 
     @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block")
-    public static int getIndex(DynamicCounterNode counter) {
+    private static int getIndex(DynamicCounterNode counter) {
         if (!enabled) {
             throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName());
         }
-        String name = counter.getName();
+        String name;
         String group = counter.getGroup();
-        name = counter.isWithContext() && counter.graph().method() != null ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name +
-                        "#" + group;
+        if (counter.isWithContext()) {
+            StructuredGraph graph = counter.graph();
+            name = counter.getName() + " @ " + graph.graphId() + ":" + (graph.method() == null ? "" : MetaUtil.format("%h.%n", graph.method()));
+            if (graph.name != null) {
+                name += " (" + graph.name + ")";
+            }
+            name += "#" + group;
+
+        } else {
+            name = counter.getName() + "#" + group;
+        }
         Integer index = indexes.get(name);
         if (index == null) {
             synchronized (BenchmarkCounters.class) {
@@ -135,7 +143,7 @@
         return index;
     }
 
-    public static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
+    private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) {
         if (!groups.isEmpty()) {
             out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======");
             for (String group : new TreeSet<>(groups)) {
@@ -152,7 +160,7 @@
         }
     }
 
-    public static synchronized void clear(long[] counters) {
+    private static synchronized void clear(long[] counters) {
         delta = counters;
     }
 
@@ -228,7 +236,7 @@
         return (counter * 200 + 1) / sum / 2;
     }
 
-    public abstract static class CallbackOutputStream extends OutputStream {
+    private abstract static class CallbackOutputStream extends OutputStream {
 
         protected final PrintStream delegate;
         private final byte[][] patterns;
@@ -281,25 +289,30 @@
         final class BenchmarkCountersOutputStream extends CallbackOutputStream {
 
             private long startTime;
+            private boolean running;
             private boolean waitingForEnd;
 
             private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) {
-                super(delegate, new String[]{start, end, "\n"});
+                super(delegate, new String[]{"\n", end, start});
             }
 
             @Override
             protected void patternFound(int index) {
                 switch (index) {
-                    case 0:
+                    case 2:
                         startTime = System.nanoTime();
                         BenchmarkCounters.clear(compilerToVM.collectCounters());
+                        running = true;
                         break;
                     case 1:
-                        waitingForEnd = true;
+                        if (running) {
+                            waitingForEnd = true;
+                        }
                         break;
-                    case 2:
+                    case 0:
                         if (waitingForEnd) {
                             waitingForEnd = false;
+                            running = false;
                             BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters(), 100);
                         }
                         break;
@@ -321,7 +334,6 @@
                     throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out");
                 }
             }
-            excludedClassPrefix = "Lcom/oracle/graal/";
             enabled = true;
         }
         if (Options.GenericDynamicCounters.getValue()) {
@@ -363,26 +375,24 @@
 
     public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) {
         StructuredGraph graph = counter.graph();
-        if (excludedClassPrefix == null || (counter.graph().method() != null && !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix))) {
 
-            ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
+        ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false));
 
-            int index = BenchmarkCounters.getIndex(counter);
-            if (index >= config.graalCountersSize) {
-                throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
-            }
-            ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset, graph);
-            ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
-            ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
-            ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
-            IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
-            WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
+        int index = BenchmarkCounters.getIndex(counter);
+        if (index >= config.graalCountersSize) {
+            throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")");
+        }
+        ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, wordKind, config.graalCountersThreadOffset, graph);
+        ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false));
+        ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
+        ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
+        IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement()));
+        WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false));
 
-            graph.addBeforeFixed(counter, thread);
-            graph.addBeforeFixed(counter, readArray);
-            graph.addBeforeFixed(counter, read);
-            graph.addBeforeFixed(counter, write);
-        }
+        graph.addBeforeFixed(counter, thread);
+        graph.addBeforeFixed(counter, readArray);
+        graph.addBeforeFixed(counter, read);
+        graph.addBeforeFixed(counter, write);
         graph.removeFixed(counter);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Fri May 02 11:33:47 2014 +0200
@@ -192,8 +192,10 @@
             if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
                 newObjectSnippets.lower((NewMultiArrayNode) n, tool);
             }
-        } else if (n instanceof LoadExceptionObjectNode) {
-            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
+        } else if (n instanceof ExceptionObjectNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                lowerExceptionObjectNode((ExceptionObjectNode) n, 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.
@@ -732,6 +734,19 @@
         }
     }
 
+    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/meta/HotSpotCodeCacheProvider.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Fri May 02 11:33:47 2014 +0200
@@ -206,12 +206,12 @@
         return installedCode;
     }
 
-    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) {
+    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) {
         if (compResult.getId() == -1) {
             compResult.setId(method.allocateCompileId(compResult.getEntryBCI()));
         }
         HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), true);
-        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult), installedCode, method.getSpeculationLog());
+        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult, ctask), installedCode, method.getSpeculationLog());
         return logOrDump(installedCode, compResult);
     }
 
@@ -236,7 +236,7 @@
     @Override
     public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) {
         HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method;
-        return installMethod(hotspotMethod, compResult);
+        return installMethod(hotspotMethod, compResult, 0L);
     }
 
     public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) {
@@ -286,4 +286,8 @@
     public String disassemble(ResolvedJavaMethod method) {
         return new BytecodeDisassembler().disassemble(method);
     }
+
+    public SpeculationLog createSpeculationLog() {
+        return new HotSpotSpeculationLog();
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri May 02 11:33:47 2014 +0200
@@ -103,7 +103,6 @@
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
         TargetDescription target = providers.getCodeCache().getTarget();
 
-        registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub(), NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
 
         registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
@@ -119,7 +118,14 @@
         registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
+        /*
+         * We cannot use LEAF_SP here because on some architectures we have to align the stack
+         * manually before calling into the VM. See {@link
+         * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}.
+         */
         registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
 
         link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Fri May 02 11:33:47 2014 +0200
@@ -27,9 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -37,7 +35,7 @@
  * Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for
  * the entire execution of the associated method.
  */
-public final class AllocaNode extends FixedWithNextNode implements LIRGenResLowerable {
+public final class AllocaNode extends FixedWithNextNode implements LIRLowerable {
 
     /**
      * The number of slots in block.
@@ -58,8 +56,8 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
-        StackSlot array = res.getFrameMap().allocateStackSlots(slots, objects, null);
+    public void generate(NodeLIRBuilderTool gen) {
+        StackSlot array = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(slots, objects, null);
         Value result = gen.getLIRGeneratorTool().emitAddress(array);
         gen.setResult(this, result);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,12 +24,11 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +38,7 @@
  * check on the object.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
+public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single {
 
     private int lockDepth;
 
@@ -59,7 +58,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         assert lockDepth != -1;
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
         StackSlot slot = hsGen.getLockSlot(lockDepth);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,8 +23,6 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -32,7 +30,7 @@
 /**
  * Converts a compile-time constant Java string into a C string installed with the generated code.
  */
-public final class CStringNode extends FloatingNode implements LIRGenLowerable {
+public final class CStringNode extends FloatingNode implements LIRLowerable {
 
     private final String string;
 
@@ -41,7 +39,7 @@
         this.string = string;
     }
 
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         gen.setResult(this, emitCString(gen, string));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Fri May 02 11:33:47 2014 +0200
@@ -93,6 +93,10 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
+    public ValueNode getInput() {
+        return input;
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (input instanceof CompressionNode) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle 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.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.word.*;
+
+/**
+ * A call to the runtime code {@code Deoptimization::fetch_unroll_info}.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+
+    @Input private SaveAllRegistersNode registerSaver;
+    private final ForeignCallsProvider foreignCalls;
+    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = new ForeignCallDescriptor("fetchUnrollInfo", Word.class, Word.class);
+
+    public DeoptimizationFetchUnrollInfoCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver) {
+        super(StampFactory.forKind(Kind.fromJavaClass(FETCH_UNROLL_INFO.getResultType())));
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+        this.foreignCalls = foreignCalls;
+    }
+
+    @Override
+    public LocationIdentity[] getLocationIdentities() {
+        return foreignCalls.getKilledLocations(FETCH_UNROLL_INFO);
+    }
+
+    public SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizationFetchUnrollInfoCall(getSaveRegistersOp());
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word fetchUnrollInfo(long registerSaver);
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return null;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -38,7 +37,7 @@
  * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray
  * instruction.
  */
-public final class DimensionsNode extends FixedWithNextNode implements LIRGenResLowerable {
+public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable {
 
     private final int rank;
 
@@ -48,12 +47,13 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
         int size = rank * 4;
-        int wordSize = gen.getLIRGeneratorTool().target().wordSize;
+        int wordSize = lirGen.target().wordSize;
         int slots = roundUp(size, wordSize) / wordSize;
-        StackSlot array = res.getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
-        Value result = gen.getLIRGeneratorTool().emitAddress(array);
+        StackSlot array = lirGen.getResult().getFrameMap().allocateStackSlots(slots, new BitSet(0), null);
+        Value result = lirGen.emitAddress(array);
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,13 +23,12 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -39,7 +38,7 @@
  * expected value or the compared against value instead of a boolean.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint.Single {
+public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
@@ -79,7 +78,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ((HotSpotNodeLIRBuilder) gen).visitDirectCompareAndSwap(this);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Fri May 02 11:33:47 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -39,12 +40,18 @@
     @Input private ValueNode framePc;
     @Input private ValueNode senderSp;
     @Input private ValueNode senderFp;
+    @Input private SaveAllRegistersNode registerSaver;
 
-    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp) {
+    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp, ValueNode registerSaver) {
         super(StampFactory.forVoid());
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.senderFp = senderFp;
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
@@ -52,9 +59,9 @@
         Value operandValue = gen.operand(framePc);
         Value senderSpValue = gen.operand(senderSp);
         Value senderFpValue = gen.operand(senderFp);
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue, getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp);
+    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp, long registerSaver);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.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/LeaveCurrentStackFrameNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -33,15 +34,22 @@
  */
 public class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
-    public LeaveCurrentStackFrameNode() {
+    @Input private SaveAllRegistersNode registerSaver;
+
+    public LeaveCurrentStackFrameNode(ValueNode registerSaver) {
         super(StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame();
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame(getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void leaveCurrentStackFrame();
+    public static native void leaveCurrentStackFrame(long registerSaver);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Fri May 02 11:33:47 2014 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -34,15 +35,22 @@
  */
 public class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
-    public LeaveUnpackFramesStackFrameNode() {
+    @Input private SaveAllRegistersNode registerSaver;
+
+    public LeaveUnpackFramesStackFrameNode(ValueNode registerSaver) {
         super(StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame();
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame(getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void leaveUnpackFramesStackFrame();
+    public static native void leaveUnpackFramesStackFrame(long registerSaver);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadExceptionObjectNode.java	Fri May 02 11:33:47 2014 +0200
@@ -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.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/nodes/MonitorCounterNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Fri May 02 11:33:47 2014 +0200
@@ -26,8 +26,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -35,16 +33,16 @@
 /**
  * Node that is used to maintain a stack based counter of how many locks are currently held.
  */
-public final class MonitorCounterNode extends FloatingNode implements LIRGenResLowerable {
+public final class MonitorCounterNode extends FloatingNode implements LIRLowerable {
 
     private MonitorCounterNode() {
         super(null);
     }
 
     @Override
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
         assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
-        StackSlot counter = res.getFrameMap().allocateStackSlots(1, new BitSet(0), null);
+        StackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(1, new BitSet(0), null);
         Value result = gen.getLIRGeneratorTool().emitAddress(counter);
         gen.setResult(this, result);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Fri May 02 11:33:47 2014 +0200
@@ -25,18 +25,17 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
 /**
  * A call to the {@link NewArrayStub}.
  */
-public class NewArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
+public class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable {
 
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
@@ -61,9 +60,9 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY);
-        Variable result = gen.getLIRGenerator().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length));
+        Variable result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,13 +24,12 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
-public class PrefetchAllocateNode extends FixedWithNextNode implements LIRGenLowerable {
+public class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input private ValueNode distance;
     @Input private ValueNode address;
@@ -42,7 +41,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         ((HotSpotNodeLIRBuilder) gen).emitPrefetchAllocate(address, distance);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Fri May 02 11:33:47 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.java.*;
@@ -41,7 +40,7 @@
  * Performs a tail call to the specified target compiled method, with the parameter taken from the
  * supplied FrameState.
  */
-public class TailcallNode extends FixedWithNextNode implements LIRGenResLowerable {
+public class TailcallNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input(InputType.State) private FrameState frameState;
     @Input private ValueNode target;
@@ -58,20 +57,21 @@
         this.frameState = frameState;
     }
 
-    public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) {
+    public void generate(NodeLIRBuilderTool gen) {
         HotSpotVMConfig config = runtime().getConfig();
+        LIRGeneratorTool lirGen = gen.getLIRGeneratorTool();
         ResolvedJavaMethod method = frameState.method();
         boolean isStatic = method.isStatic();
 
         JavaType[] signature = MetaUtil.signatureToTypes(method.getSignature(), isStatic ? null : method.getDeclaringClass());
-        CallingConvention cc = res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.getLIRGeneratorTool().target(), false);
+        CallingConvention cc = lirGen.getResult().getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, lirGen.target(), false);
         List<ValueNode> parameters = new ArrayList<>();
         for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += HIRFrameStateBuilder.stackSlots(frameState.localAt(slot).getKind())) {
             parameters.add(frameState.localAt(slot));
         }
         Value[] args = gen.visitInvokeArguments(cc, parameters);
-        Value address = gen.getLIRGeneratorTool().emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
-        Value entry = gen.getLIRGeneratorTool().emitLoad(Kind.Long, address, null);
+        Value address = lirGen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0);
+        Value entry = lirGen.emitLoad(Kind.Long, address, null);
         HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
         hsgen.emitTailcall(args, entry);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java	Fri May 02 11:33:47 2014 +0200
@@ -34,7 +34,7 @@
 public class CallSiteSubstitutions implements ReplacementsProvider {
 
     @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         replacements.registerSubstitutions(ConstantCallSiteSubstitutions.class);
         replacements.registerSubstitutions(MutableCallSiteSubstitutions.class);
         replacements.registerSubstitutions(VolatileCallSiteSubstitutions.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Fri May 02 11:33:47 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
@@ -32,7 +33,7 @@
 public class HotSpotSubstitutions implements ReplacementsProvider {
 
     @Override
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         replacements.registerSubstitutions(ObjectSubstitutions.class);
         replacements.registerSubstitutions(SystemSubstitutions.class);
         replacements.registerSubstitutions(ThreadSubstitutions.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri May 02 11:33:47 2014 +0200
@@ -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;
@@ -44,6 +44,12 @@
 
 /**
  * Snippet for loading the exception object at the start of an exception dispatcher.
+ * <p>
+ * The frame state upon entry to an exception handler is such that it is a
+ * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
+ * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
+ * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
+ * find the exception object to be rethrown.
  */
 public class LoadExceptionObjectSnippets implements Snippets {
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Fri May 02 11:33:47 2014 +0200
@@ -45,30 +45,35 @@
  *
  * The steps taken by this frame are as follows:
  *
- * - push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all potentially
- * live registers (at a pollpoint many registers can be live).
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
  *
- * - call the C routine: Deoptimization::fetch_unroll_info (this function returns information about
- * the number and size of interpreter frames which are equivalent to the frame which is being
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
  * deoptimized)
  *
- * - deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
  * be captured in the vframeArray as needed.
  *
- * - deallocate the deoptimization frame
+ * <li>deallocate the deoptimization frame
  *
- * - in a loop using the information returned in the previous step push new interpreter frames (take
- * care to propagate the return values through each new frame pushed)
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
  *
- * - create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
  *
- * - call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
  * interpreter frame which was just created)
  *
- * - deallocate the dummy unpack_frame
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
  *
- * - ensure that all the return values are correctly set and then do a return to the interpreter
- * entry point
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
  */
 public class DeoptimizationStub extends SnippetStub {
 
@@ -97,46 +102,30 @@
     }
 
     /**
-     * Uncommon trap.
-     *
-     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
-     * routine captures the return values and returns a structure which describes the current frame
-     * size and the sizes of all replacement frames. The current frame is compiled code and may
-     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
-     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
-     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
-     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
-     * was patched.
-     *
-     * <p>
-     * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
-     * because we change the current stack layout and so the code is very sensitive to register
-     * allocation.</b>
+     * Deoptimization handler for normal deoptimization
+     * {@link HotSpotVMConfig#deoptimizationUnpackDeopt}.
      */
     @Snippet
-    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+    private static void deoptimizationHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
         final Word thread = registerAsWord(threadRegister);
-        long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
 
-        final int actionAndReason = readPendingDeoptimization(thread);
-        writePendingDeoptimization(thread, -1);
-
-        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason);
+        final Word unrollBlock = DeoptimizationFetchUnrollInfoCallNode.fetchUnrollInfo(registerSaver);
 
         // Pop all the frames we must move/replace.
         //
         // Frame picture (youngest to oldest)
-        // 1: self-frame (no frame link)
-        // 2: deoptimizing frame (no frame link)
+        // 1: self-frame
+        // 2: deoptimizing frame
         // 3: caller of deoptimizing frame (could be compiled/interpreted).
 
         // Pop self-frame.
-        LeaveCurrentStackFrameNode.leaveCurrentStackFrame();
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver);
 
         // Load the initial info we should save (e.g. frame pointer).
         final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
 
-        // Pop deoptimized frame
+        // Pop deoptimized frame.
         final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset());
         LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
 
@@ -144,13 +133,15 @@
          * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
          * total size of the interpreter frames plus shadow page size. Bang one page at a time
          * because large sizes can bang beyond yellow and red zones.
+         *
+         * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
          */
         final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
         final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages();
         Word stackPointer = readRegister(stackPointerRegister);
 
         for (int i = 1; i < bangPages; i++) {
-            stackPointer.writeInt(-(i * pageSize()), i);
+            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0);
         }
 
         // Load number of interpreter frames.
@@ -191,13 +182,13 @@
          * unknown alignment we need to align it here before calling C++ code.
          */
         final Word senderFp = initialInfo;
-        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp);
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver);
 
-        // Pass uncommon trap mode to unpack frames.
-        final int mode = deoptimizationUnpackUncommonTrap();
+        // Pass unpack deopt mode to unpack frames.
+        final int mode = deoptimizationUnpackDeopt();
         unpackFrames(UNPACK_FRAMES, thread, mode);
 
-        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame();
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver);
     }
 
     /**
@@ -221,6 +212,19 @@
         return config().useStackBanging ? config().stackShadowPages : 0;
     }
 
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    private static int stackBias() {
+        return config().stackBias;
+    }
+
     @Fold
     private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
         return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri May 02 11:33:47 2014 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
@@ -61,15 +60,9 @@
     protected Arguments makeArguments(SnippetInfo stub) {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
 
-        // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we
-        // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since
-        // the int[] class will never be unloaded.
-        Constant intArrayHub = intArrayType.klass();
-        intArrayHub = Constant.forIntegerKind(runtime().getTarget().wordKind, intArrayHub.asLong());
-
         Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS, LoweringTool.StandardLoweringStage.HIGH_TIER);
         args.add("hub", null);
-        args.addConst("intArrayHub", intArrayHub);
+        args.addConst("intArrayHub", intArrayType.klass());
         args.addConst("threadRegister", providers.getRegisters().getThreadRegister());
         return args;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.stubs.StubUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Uncommon trap stub.
+ *
+ * This is the entry point for code which is returning to a de-optimized frame.
+ *
+ * The steps taken by this frame are as follows:
+ *
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
+ *
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
+ * deoptimized)
+ *
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * be captured in the vframeArray as needed.
+ *
+ * <li>deallocate the deoptimization frame
+ *
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
+ *
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ *
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * interpreter frame which was just created)
+ *
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
+ *
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
+ */
+public class UncommonTrapStub extends SnippetStub {
+
+    private final TargetDescription target;
+
+    public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        this.target = target;
+    }
+
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        switch (index) {
+            case 0:
+                return providers.getRegisters().getThreadRegister();
+            case 1:
+                return providers.getRegisters().getStackPointerRegister();
+            default:
+                throw GraalInternalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
+        }
+    }
+
+    /**
+     * Uncommon trap handler.
+     *
+     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
+     * routine captures the return values and returns a structure which describes the current frame
+     * size and the sizes of all replacement frames. The current frame is compiled code and may
+     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
+     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
+     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
+     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
+     * was patched.
+     */
+    @Snippet
+    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+        final Word thread = registerAsWord(threadRegister);
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+
+        final int actionAndReason = readPendingDeoptimization(thread);
+        writePendingDeoptimization(thread, -1);
+
+        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason);
+
+        // Pop all the frames we must move/replace.
+        //
+        // Frame picture (youngest to oldest)
+        // 1: self-frame
+        // 2: deoptimizing frame
+        // 3: caller of deoptimizing frame (could be compiled/interpreted).
+
+        // Pop self-frame.
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver);
+
+        // Load the initial info we should save (e.g. frame pointer).
+        final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
+
+        // Pop deoptimized frame.
+        final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset());
+        LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
+
+        /*
+         * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
+         * total size of the interpreter frames plus shadow page size. Bang one page at a time
+         * because large sizes can bang beyond yellow and red zones.
+         * 
+         * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
+         */
+        final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
+        final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages();
+        Word stackPointer = readRegister(stackPointerRegister);
+
+        for (int i = 1; i < bangPages; i++) {
+            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0);
+        }
+
+        // Load number of interpreter frames.
+        final int numberOfFrames = unrollBlock.readInt(deoptimizationUnrollBlockNumberOfFramesOffset());
+
+        // Load address of array of frame sizes.
+        final Word frameSizes = unrollBlock.readWord(deoptimizationUnrollBlockFrameSizesOffset());
+
+        // Load address of array of frame PCs.
+        final Word framePcs = unrollBlock.readWord(deoptimizationUnrollBlockFramePcsOffset());
+
+        /*
+         * Get the current stack pointer (sender's original SP) before adjustment so that we can
+         * save it in the skeletal interpreter frame.
+         */
+        Word senderSp = readRegister(stackPointerRegister);
+
+        // Adjust old interpreter frame to make space for new frame's extra Java locals.
+        final int callerAdjustment = unrollBlock.readInt(deoptimizationUnrollBlockCallerAdjustmentOffset());
+        writeRegister(stackPointerRegister, readRegister(stackPointerRegister).subtract(callerAdjustment));
+
+        for (int i = 0; i < numberOfFrames; i++) {
+            final Word frameSize = frameSizes.readWord(i * wordSize());
+            final Word framePc = framePcs.readWord(i * wordSize());
+
+            // Push an interpreter frame onto the stack.
+            PushInterpreterFrameNode.pushInterpreterFrame(frameSize, framePc, senderSp, initialInfo);
+
+            // Get the current stack pointer (sender SP) and pass it to next frame.
+            senderSp = readRegister(stackPointerRegister);
+        }
+
+        // Get final return address.
+        final Word framePc = framePcs.readWord(numberOfFrames * wordSize());
+
+        /*
+         * Enter a frame to call out to unpack frames. Since we changed the stack pointer to an
+         * unknown alignment we need to align it here before calling C++ code.
+         */
+        final Word senderFp = initialInfo;
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver);
+
+        // Pass uncommon trap mode to unpack frames.
+        final int mode = deoptimizationUnpackUncommonTrap();
+        unpackFrames(UNPACK_FRAMES, thread, mode);
+
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver);
+    }
+
+    /**
+     * Reads the value of the passed register as a Word.
+     */
+    private static Word readRegister(Register register) {
+        return registerAsWord(register, false, false);
+    }
+
+    /**
+     * Writes the value of the passed register.
+     *
+     * @param value value the register should be set to
+     */
+    private static void writeRegister(Register register, Word value) {
+        writeRegisterAsWord(register, value);
+    }
+
+    @Fold
+    private static int stackShadowPages() {
+        return config().useStackBanging ? config().stackShadowPages : 0;
+    }
+
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    private static int stackBias() {
+        return config().stackBias;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+        return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+        return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+        return config().deoptimizationUnrollBlockNumberOfFramesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFramePcsOffset() {
+        return config().deoptimizationUnrollBlockFramePcsOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+        return config().deoptimizationUnrollBlockInitialInfoOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackDeopt() {
+        return config().deoptimizationUnpackDeopt;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackUncommonTrap() {
+        return config().deoptimizationUnpackUncommonTrap;
+    }
+
+    public static final ForeignCallDescriptor UNPACK_FRAMES = descriptorFor(UncommonTrapStub.class, "unpackFrames");
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -326,6 +326,7 @@
         } finally {
             lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
             monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
+            assert lockedObjects.length == monitorIds.length;
         }
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java	Fri May 02 11:33:47 2014 +0200
@@ -23,8 +23,9 @@
 
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,12 +62,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -49,17 +50,17 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,17 +57,17 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_InNested extends JTTTest {
 
@@ -48,12 +49,12 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized01 extends JTTTest {
 
@@ -38,12 +39,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized02 extends JTTTest {
 
@@ -36,12 +37,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.except;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Throw_Synchronized03 extends JTTTest {
 
@@ -41,12 +42,12 @@
         throw new Exception();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -37,27 +38,27 @@
         return sum;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 80);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java	Fri May 02 11:33:47 2014 +0200
@@ -23,8 +23,9 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -55,12 +56,12 @@
         return (int) (b + c + s + i + l + f + d);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 40);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1000);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -104,12 +105,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 40);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 80);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java	Fri May 02 11:33:47 2014 +0200
@@ -25,8 +25,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -106,7 +107,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java	Fri May 02 11:33:47 2014 +0200
@@ -23,8 +23,9 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,7 +49,7 @@
         return sum;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 15);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotspot;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /**
  * @bug 6196102
@@ -46,7 +47,7 @@
         return "ok";
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.hotspot;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 //@formatter:off
 
@@ -50,7 +51,7 @@
         return 95;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -45,17 +46,17 @@
         C
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.io.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         out.println(test(10000));
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 10000);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,10 +24,11 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import sun.misc.*;
 
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -55,7 +56,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -43,22 +44,22 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_Literal01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_asSubclass01 extends JTTTest {
 
@@ -53,27 +54,27 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_cast01 extends JTTTest {
 
@@ -57,27 +58,27 @@
         return i;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_forName01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Class_forName02 extends JTTTest {
 
@@ -51,27 +52,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,32 +57,32 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,32 +49,32 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.net.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -41,17 +42,17 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -81,27 +82,27 @@
 
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Object_getClass01 extends JTTTest {
 
@@ -49,27 +50,27 @@
         return null;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_toString01 extends JTTTest {
 
@@ -47,17 +48,17 @@
         return string;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,17 +34,17 @@
         return ("id" + i).intern() == ("id" + i).intern();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.lang;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,17 +34,17 @@
         return ("id" + i).intern().equals("id" + i);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.loop;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class LoopParseLong extends JTTTest {
 
@@ -98,7 +99,7 @@
         return negative ? result : -result;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("testShortened", "7", 10);
         runTest("testShortened", "-100", 10);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.loop;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         return "" + ('a' + count);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -33,7 +34,7 @@
         return p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -155,32 +156,32 @@
         ((Matrix[]) array)[val % array.length] = new Matrix(number);
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -57,7 +58,7 @@
         return Integer.valueOf(foo(new String[]{"asdf"}));
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.micro;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -58,7 +59,7 @@
         Object c = b;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -117,22 +118,22 @@
         return c2 ? 1 : 0;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 10);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 20);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 40);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.io.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -44,7 +45,7 @@
         return (String) arg;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", (Object) null);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.optimize;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  * Tests value numbering of instanceof operations.
@@ -76,17 +77,17 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -37,22 +38,22 @@
         return Class_getField01.class.getField(input).getName();
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "field");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "field2");
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", "field3");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -42,27 +43,27 @@
         public String field4;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "field");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "field2");
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", "field3");
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", "field4");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -39,17 +40,17 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "main");
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", "xx");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -52,37 +53,37 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Class_newInstance03 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,47 +60,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,47 +62,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -87,47 +88,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -61,47 +62,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,47 +60,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -67,47 +68,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -69,47 +70,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -69,47 +70,47 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest
+    @Test
     public void run5() throws Throwable {
         runTest("test", 5);
     }
 
-    @LongTest
+    @Test
     public void run6() throws Throwable {
         runTest("test", 6);
     }
 
-    @LongTest
+    @Test
     public void run7() throws Throwable {
         runTest("test", 7);
     }
 
-    @LongTest
+    @Test
     public void run8() throws Throwable {
         runTest("test", 8);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -56,27 +57,27 @@
         return arg.length;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -44,12 +45,12 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "test2");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -48,12 +49,12 @@
         field = args[0];
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", "test1");
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", "test2");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -51,22 +52,22 @@
     public void method3(int arg1, Object arg2) {
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.reflect;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -51,22 +52,22 @@
     public void method3() {
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Monitor_contended01 extends JTTTest implements Runnable {
 
@@ -71,7 +72,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Monitor_notowner01 extends JTTTest {
 
@@ -62,7 +63,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait01 extends JTTTest implements Runnable {
 
@@ -57,22 +58,22 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run3() throws Throwable {
         runTest("test", 15);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait02 extends JTTTest implements Runnable {
 
@@ -57,17 +58,17 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait03 extends JTTTest implements Runnable {
 
@@ -63,17 +64,17 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Object_wait04 extends JTTTest implements Runnable {
 
@@ -67,32 +68,32 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run4() throws Throwable {
         runTest("test", 4);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run5() throws Throwable {
         runTest("test", 5);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -59,22 +60,22 @@
         }
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_getState02 extends JTTTest {
 
@@ -33,7 +34,7 @@
         return new Thread().getState() == Thread.State.NEW;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java	Fri May 02 11:33:47 2014 +0200
@@ -26,8 +26,9 @@
 
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 //Test all, mainly monitors
 public class Thread_isInterrupted02 extends JTTTest {
@@ -85,12 +86,12 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 0, 0);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 1, 500);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -68,7 +69,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -66,7 +67,7 @@
 
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java	Fri May 02 11:33:47 2014 +0200
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 /*
  */
@@ -66,7 +67,7 @@
         }
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join01 extends JTTTest implements Runnable {
 
@@ -43,7 +44,7 @@
         cont = false;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java	Fri May 02 11:33:47 2014 +0200
@@ -27,8 +27,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join02 extends JTTTest implements Runnable {
 
@@ -50,7 +51,7 @@
         cont = false;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java	Fri May 02 11:33:47 2014 +0200
@@ -27,8 +27,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_join03 extends JTTTest implements Runnable {
 
@@ -47,7 +48,7 @@
         cont = false;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_new01 extends JTTTest {
 
@@ -45,27 +46,27 @@
         return false;
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public class Thread_new02 extends JTTTest implements Runnable {
 
@@ -51,27 +52,27 @@
         // do nothing.
     }
 
-    @LongTest
+    @Test
     public void run0() throws Throwable {
         runTest("test", 0);
     }
 
-    @LongTest
+    @Test
     public void run1() throws Throwable {
         runTest("test", 1);
     }
 
-    @LongTest
+    @Test
     public void run2() throws Throwable {
         runTest("test", 2);
     }
 
-    @LongTest
+    @Test
     public void run3() throws Throwable {
         runTest("test", 3);
     }
 
-    @LongTest
+    @Test
     public void run4() throws Throwable {
         runTest("test", 4);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,9 @@
  */
 package com.oracle.graal.jtt.threads;
 
+import org.junit.*;
+
 import com.oracle.graal.jtt.*;
-import com.oracle.graal.test.*;
 
 public final class Thread_sleep01 extends JTTTest {
 
@@ -35,17 +36,17 @@
         return System.currentTimeMillis() - before >= i;
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run0() throws Throwable {
         runTest("test", 10);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run1() throws Throwable {
         runTest("test", 20);
     }
 
-    @LongTest(timeout = 20000)
+    @Test(timeout = 20000)
     public void run2() throws Throwable {
         runTest("test", 100);
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri May 02 11:33:47 2014 +0200
@@ -39,8 +39,8 @@
 
     // @formatter:off
 
-    IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
-    LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
+    IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR,
+    LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR,
     FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
     INEG, LNEG, INOT, LNOT,
@@ -491,6 +491,14 @@
                     assert asIntReg(src).equals(AMD64.rcx);
                     masm.shrl(asIntReg(dst));
                     break;
+                case IROL:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.roll(asIntReg(dst));
+                    break;
+                case IROR:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rorl(asIntReg(dst));
+                    break;
 
                 case LADD:
                     masm.addq(asLongReg(dst), asLongReg(src));
@@ -522,6 +530,14 @@
                     assert asIntReg(src).equals(AMD64.rcx);
                     masm.shrq(asLongReg(dst));
                     break;
+                case LROL:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rolq(asLongReg(dst));
+                    break;
+                case LROR:
+                    assert asIntReg(src).equals(AMD64.rcx);
+                    masm.rorq(asLongReg(dst));
+                    break;
 
                 case FADD:
                     masm.addss(asFloatReg(dst), asFloatReg(src));
@@ -695,6 +711,12 @@
                 case IUSHR:
                     masm.shrl(asIntReg(dst), crb.asIntConst(src) & 31);
                     break;
+                case IROL:
+                    masm.roll(asIntReg(dst), crb.asIntConst(src) & 31);
+                    break;
+                case IROR:
+                    masm.rorl(asIntReg(dst), crb.asIntConst(src) & 31);
+                    break;
 
                 case LADD:
                     masm.addq(asLongReg(dst), crb.asIntConst(src));
@@ -723,6 +745,12 @@
                 case LUSHR:
                     masm.shrq(asLongReg(dst), crb.asIntConst(src) & 63);
                     break;
+                case LROL:
+                    masm.rolq(asLongReg(dst), crb.asIntConst(src) & 31);
+                    break;
+                case LROR:
+                    masm.rorq(asLongReg(dst), crb.asIntConst(src) & 31);
+                    break;
 
                 case FADD:
                     masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Fri May 02 11:33:47 2014 +0200
@@ -132,6 +132,9 @@
                     default:
                         throw GraalInternalError.shouldNotReachHere();
                 }
+
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
             }
         }
 
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Fri May 02 11:33:47 2014 +0200
@@ -480,6 +480,32 @@
         }
     }
 
+    @Opcode("ATOMIC_READ_AND_WRITE")
+    public static class AtomicReadAndWriteOp extends HSAILLIRInstruction {
+
+        private final Kind accessKind;
+
+        @Def protected AllocatableValue result;
+        @Use({COMPOSITE}) protected HSAILAddressValue address;
+        @Use({REG, CONST}) protected Value newValue;
+
+        public AtomicReadAndWriteOp(Kind accessKind, AllocatableValue result, HSAILAddressValue address, Value newValue) {
+            this.accessKind = accessKind;
+            this.result = result;
+            this.address = address;
+            this.newValue = newValue;
+        }
+
+        public HSAILAddressValue getAddress() {
+            return address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
+            masm.emitAtomicExch(accessKind, result, address.toAddress(), newValue);
+        }
+    }
+
     public static class NullCheckOp extends HSAILLIRInstruction {
 
         @Use protected Value input;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Fri May 02 11:33:47 2014 +0200
@@ -68,7 +68,7 @@
     FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
     DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
     INEG, LNEG, FNEG, DNEG, INOT, LNOT,
-    I2L, L2I, I2B, I2C, I2S,
+    L2I, B2I, S2I, B2L, S2L, I2L,
     F2D, D2F,
     I2F, I2D, F2I, D2I,
     L2F, L2D, F2L, D2L,
@@ -572,11 +572,11 @@
                 case L2I:
                     new Signx(asLongReg(src), asIntReg(dst)).emit(masm);
                     break;
-                case I2B:
+                case B2I:
                     new Sll(asIntReg(src), 24, asIntReg(dst)).emit(masm);
                     new Srl(asIntReg(dst), 24, asIntReg(dst)).emit(masm);
                     break;
-                case I2C:
+                case S2I:
                     new Sll(asIntReg(src), 16, asIntReg(dst)).emit(masm);
                     new Srl(asIntReg(dst), 16, asIntReg(dst)).emit(masm);
                     break;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Fri May 02 11:33:47 2014 +0200
@@ -270,13 +270,16 @@
     @Opcode("CMOVE")
     public static class CondMoveOp extends SPARCLIRInstruction {
 
+        private final Kind kind;
+
         @Def({REG, HINT}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Use({REG, STACK, CONST}) protected Value falseValue;
 
         private final ConditionFlag condition;
 
-        public CondMoveOp(Variable result, Condition condition, Variable trueValue, Value falseValue) {
+        public CondMoveOp(Kind kind, Variable result, Condition condition, Variable trueValue, Value falseValue) {
+            this.kind = kind;
             this.result = result;
             this.condition = intCond(condition);
             this.trueValue = trueValue;
@@ -285,20 +288,28 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            cmove(crb, masm, result, false, condition, false, trueValue, falseValue);
+            // check that we don't overwrite an input operand before it is used.
+            assert !result.equals(trueValue);
+
+            SPARCMove.move(crb, masm, result, falseValue);
+            cmove(crb, masm, kind, result, condition, trueValue);
         }
     }
 
     @Opcode("CMOVE")
     public static class FloatCondMoveOp extends SPARCLIRInstruction {
 
+        private final Kind kind;
+
         @Def({REG}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Alive({REG}) protected Value falseValue;
+
         private final ConditionFlag condition;
         private final boolean unorderedIsTrue;
 
-        public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+        public FloatCondMoveOp(Kind kind, Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+            this.kind = kind;
             this.result = result;
             this.condition = floatCond(condition);
             this.unorderedIsTrue = unorderedIsTrue;
@@ -308,18 +319,12 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            cmove(crb, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue);
-        }
-    }
+            // check that we don't overwrite an input operand before it is used.
+            assert !result.equals(trueValue);
 
-    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, boolean isFloat, ConditionFlag condition, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
-        // check that we don't overwrite an input operand before it is used.
-        assert !result.equals(trueValue);
+            SPARCMove.move(crb, masm, result, falseValue);
+            cmove(crb, masm, kind, result, condition, trueValue);
 
-        SPARCMove.move(crb, masm, result, falseValue);
-        cmove(crb, masm, result, condition, trueValue);
-
-        if (isFloat) {
             if (unorderedIsTrue && !trueOnUnordered(condition)) {
                 // cmove(crb, masm, result, ConditionFlag.Parity, trueValue);
                 throw GraalInternalError.unimplemented();
@@ -330,18 +335,20 @@
         }
     }
 
-    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, ConditionFlag cond, Value other) {
+    private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Kind kind, Value result, ConditionFlag cond, Value other) {
         if (!isRegister(other)) {
             SPARCMove.move(crb, masm, result, other);
-            throw new InternalError("result should be scratch");
+            throw GraalInternalError.shouldNotReachHere("result should be scratch");
         }
         assert !asRegister(other).equals(asRegister(result)) : "other already overwritten by previous move";
-        switch (other.getKind()) {
+        switch (kind) {
             case Int:
-                // XXX CC depends on compare
                 new Movcc(cond, CC.Icc, asRegister(other), asRegister(result)).emit(masm);
                 break;
             case Long:
+            case Object:
+                new Movcc(cond, CC.Xcc, asRegister(other), asRegister(result)).emit(masm);
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Fri May 02 11:33:47 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.lir.*;
 
 /**
@@ -33,7 +34,7 @@
  *
  * <pre>
  *   Base       Contents
- *
+ * 
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
@@ -88,8 +89,7 @@
 
     @Override
     protected int alignFrameSize(int size) {
-        int x = size + (target.stackAlignment - 1);
-        return (x / target.stackAlignment) * target.stackAlignment;
+        return NumUtil.roundUp(size, target.stackAlignment);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,32 +23,14 @@
 package com.oracle.graal.lir.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CompilationResult.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Add;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldf;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Lduh;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Membar;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Rdpc;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stb;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Sth;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Stx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cas;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Casx;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Clr;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setuw;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
@@ -154,32 +136,33 @@
 
         @Override
         public void emitMemAccess(SPARCMacroAssembler masm) {
-            SPARCAddress addr = address.toAddress();
+            final SPARCAddress addr = address.toAddress();
+            final Register dst = asRegister(result);
             switch (kind) {
                 case Boolean:
                 case Byte:
-                    new Ldsb(addr, asRegister(result)).emit(masm);
+                    new Ldsb(addr, dst).emit(masm);
                     break;
                 case Short:
-                    new Ldsh(addr, asRegister(result)).emit(masm);
+                    new Ldsh(addr, dst).emit(masm);
                     break;
                 case Char:
-                    new Lduh(addr, asRegister(result)).emit(masm);
+                    new Lduh(addr, dst).emit(masm);
                     break;
                 case Int:
-                    new Ldsw(addr, asRegister(result)).emit(masm);
+                    new Ldsw(addr, dst).emit(masm);
                     break;
                 case Long:
-                    new Ldx(addr, asRegister(result)).emit(masm);
+                    new Ldx(addr, dst).emit(masm);
                     break;
                 case Float:
-                    new Ldf(addr, asRegister(result)).emit(masm);
+                    new Ldf(addr, dst).emit(masm);
                     break;
                 case Double:
-                    new Lddf(addr, asRegister(result)).emit(masm);
+                    new Lddf(addr, dst).emit(masm);
                     break;
                 case Object:
-                    new Ldx(addr, asRegister(result)).emit(masm);
+                    new Ldx(addr, dst).emit(masm);
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -208,6 +191,26 @@
         }
     }
 
+    public static class LoadDataAddressOp extends SPARCLIRInstruction {
+
+        @Def({REG}) protected AllocatableValue result;
+        private final byte[] data;
+
+        public LoadDataAddressOp(AllocatableValue result, byte[] data) {
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            RawData rawData = new RawData(data, 16);
+            SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(rawData);
+            assert addr == masm.getPlaceholder();
+            final boolean forceRelocatable = true;
+            new Setx(0, asRegister(result), forceRelocatable).emit(masm);
+        }
+    }
+
     public static class MembarOp extends SPARCLIRInstruction {
 
         private final int barriers;
@@ -395,19 +398,25 @@
     }
 
     private static void reg2reg(SPARCAssembler masm, Value result, Value input) {
-        if (asRegister(input).equals(asRegister(result))) {
+        final Register src = asRegister(input);
+        final Register dst = asRegister(result);
+        if (src.equals(dst)) {
             return;
         }
         switch (input.getKind()) {
             case Int:
             case Long:
             case Object:
-                new Mov(asRegister(input), asRegister(result)).emit(masm);
+                new Mov(src, dst).emit(masm);
                 break;
             case Float:
+                new Fmovs(src, dst).emit(masm);
+                break;
             case Double:
+                new Fmovd(src, dst).emit(masm);
+                break;
             default:
-                throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
+                throw GraalInternalError.shouldNotReachHere();
         }
     }
 
@@ -423,7 +432,11 @@
                 new Stx(src, dst).emit(masm);
                 break;
             case Float:
+                new Stf(src, dst).emit(masm);
+                break;
             case Double:
+                new Stdf(src, dst).emit(masm);
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -461,7 +474,7 @@
                     }
                 }
                 break;
-            case Long: {
+            case Long:
                 if (crb.codeCache.needsDataPatch(input)) {
                     crb.recordInlineDataInCode(input);
                     new Setx(input.asLong(), asRegister(result), true).emit(masm);
@@ -473,8 +486,10 @@
                     }
                 }
                 break;
-            }
-            case Object: {
+            case Float:
+                new Ldf((SPARCAddress) crb.asFloatConstRef(input), asFloatReg(result)).emit(masm);
+                break;
+            case Object:
                 if (input.isNull()) {
                     new Clr(asRegister(result)).emit(masm);
                 } else if (crb.target.inlineObjects) {
@@ -488,7 +503,6 @@
                     throw GraalInternalError.shouldNotReachHere("the patched offset might be too big for the load");
                 }
                 break;
-            }
             default:
                 throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind());
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.sparc;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
+
+    /**
+     * The registers (potentially) saved by this operation.
+     */
+    protected final Register[] savedRegisters;
+
+    /**
+     * The slots to which the registers are saved.
+     */
+    @Def(STACK) protected final StackSlot[] slots;
+
+    /**
+     * Specifies if {@link #remove(Set)} should have an effect.
+     */
+    protected final boolean supportsRemove;
+
+    /**
+     *
+     * @param savedRegisters the registers saved by this operation which may be subject to
+     *            {@linkplain #remove(Set) pruning}
+     * @param slots the slots to which the registers are saved
+     * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
+     */
+    public SPARCSaveRegistersOp(Register[] savedRegisters, StackSlot[] slots, boolean supportsRemove) {
+        this.savedRegisters = savedRegisters;
+        this.slots = slots;
+        this.supportsRemove = supportsRemove;
+    }
+
+    private static void saveRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, StackSlot result, Register register) {
+        RegisterValue input = register.asValue(result.getKind());
+        SPARCMove.move(crb, masm, result, input);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                saveRegister(crb, masm, slots[i], savedRegisters[i]);
+            }
+        }
+    }
+
+    public StackSlot[] getSlots() {
+        return slots;
+    }
+
+    public boolean supportsRemove() {
+        return supportsRemove;
+    }
+
+    public int remove(Set<Register> doNotSave) {
+        if (!supportsRemove) {
+            throw new UnsupportedOperationException();
+        }
+        return prune(doNotSave, savedRegisters);
+    }
+
+    static int prune(Set<Register> toRemove, Register[] registers) {
+        int pruned = 0;
+        for (int i = 0; i < registers.length; i++) {
+            if (registers[i] != null) {
+                if (toRemove.contains(registers[i])) {
+                    registers[i] = null;
+                    pruned++;
+                }
+            }
+        }
+        return pruned;
+    }
+
+    public RegisterSaveLayout getMap(FrameMap frameMap) {
+        int total = 0;
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                total++;
+            }
+        }
+        Register[] keys = new Register[total];
+        int[] values = new int[total];
+        if (total != 0) {
+            int mapIndex = 0;
+            for (int i = 0; i < savedRegisters.length; i++) {
+                if (savedRegisters[i] != null) {
+                    keys[mapIndex] = savedRegisters[i];
+                    values[mapIndex] = frameMap.indexForStackSlot(slots[i]);
+                    mapIndex++;
+                }
+            }
+            assert mapIndex == total;
+        }
+        return new RegisterSaveLayout(keys, values);
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri May 02 11:33:47 2014 +0200
@@ -113,6 +113,15 @@
     }
 
     /**
+     * Gets the size of a stack slot.
+     *
+     * @return stack slot size
+     */
+    public int stackSlotSize() {
+        return target.wordSize;
+    }
+
+    /**
      * Gets the frame size of the compiled frame, not including the size of the
      * {@link Architecture#getReturnAddressSize() return address slot}.
      *
@@ -208,8 +217,8 @@
      * @return the index of the stack slot
      */
     public int indexForStackSlot(StackSlot slot) {
-        assert offsetForStackSlot(slot) % target.wordSize == 0;
-        return offsetForStackSlot(slot) / target.wordSize;
+        assert offsetForStackSlot(slot) % stackSlotSize() == 0;
+        return offsetForStackSlot(slot) / stackSlotSize();
     }
 
     /**
@@ -259,7 +268,7 @@
      * @param kind the {@link PlatformKind} to be stored in the spill slot.
      * @return the size in bytes
      */
-    protected int spillSlotSize(PlatformKind kind) {
+    public int spillSlotSize(PlatformKind kind) {
         return target.getSizeInBytes(kind);
     }
 
@@ -321,7 +330,7 @@
         if (slots == 0) {
             return null;
         }
-        spillSize += (slots * target.wordSize);
+        spillSize += (slots * stackSlotSize());
 
         if (!objects.isEmpty()) {
             assert objects.length() <= slots;
@@ -329,7 +338,7 @@
             for (int slotIndex = 0; slotIndex < slots; slotIndex++) {
                 StackSlot objectSlot = null;
                 if (objects.get(slotIndex)) {
-                    objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * target.wordSize);
+                    objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * stackSlotSize());
                     objectStackSlots.add(objectSlot);
                     if (outObjectStackSlots != null) {
                         outObjectStackSlots.add(objectSlot);
@@ -352,7 +361,7 @@
     }
 
     public ReferenceMap initReferenceMap(boolean hasRegisters) {
-        ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / target.wordSize);
+        ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / stackSlotSize());
         for (StackSlot slot : objectStackSlots) {
             setReference(slot, refMap);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Fri May 02 11:33:47 2014 +0200
@@ -92,14 +92,8 @@
         compilationResult.setTotalFrameSize(frameSize);
     }
 
-    private static final CompilationResult.Mark[] NO_REFS = {};
-
     public CompilationResult.Mark recordMark(Object id) {
-        return compilationResult.recordMark(asm.position(), id, NO_REFS);
-    }
-
-    public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) {
-        return compilationResult.recordMark(asm.position(), id, references);
+        return compilationResult.recordMark(asm.position(), id);
     }
 
     public void blockComment(String s) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -48,7 +48,7 @@
 /**
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
-public abstract class LIRGenerator implements ArithmeticLIRGenerator, LIRGeneratorTool, PlatformKindTool {
+public abstract class LIRGenerator implements LIRGeneratorTool, PlatformKindTool {
 
     public static class Options {
         // @formatter:off
@@ -62,9 +62,7 @@
     private final CodeGenProviders providers;
     private final CallingConvention cc;
 
-    protected AbstractBlock<?> currentBlock;
-    public final int traceLevel;
-    public final boolean printIRWithLIR;
+    private AbstractBlock<?> currentBlock;
 
     /**
      * Handle for an operation that loads a constant into a variable. The operation starts in the
@@ -173,8 +171,6 @@
         this.res = res;
         this.providers = providers;
         this.cc = cc;
-        this.traceLevel = Options.TraceLIRGeneratorLevel.getValue();
-        this.printIRWithLIR = Options.PrintIRWithLIR.getValue();
     }
 
     /**
@@ -272,7 +268,7 @@
     }
 
     public void append(LIRInstruction op) {
-        if (printIRWithLIR && !TTY.isSuppressed()) {
+        if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
             TTY.println(op.toStringWithIdPrefix());
             TTY.println();
         }
@@ -289,7 +285,7 @@
     }
 
     public final void doBlockStart(AbstractBlock<?> block) {
-        if (printIRWithLIR) {
+        if (Options.PrintIRWithLIR.getValue()) {
             TTY.print(block.toString());
         }
 
@@ -301,20 +297,20 @@
 
         append(new LabelOp(new Label(block.getId()), block.isAligned()));
 
-        if (traceLevel >= 1) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
             TTY.println("BEGIN Generating LIR for block B" + block.getId());
         }
     }
 
     public final void doBlockEnd(AbstractBlock<?> block) {
 
-        if (traceLevel >= 1) {
+        if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
             TTY.println("END Generating LIR for block B" + block.getId());
         }
 
         currentBlock = null;
 
-        if (printIRWithLIR) {
+        if (Options.PrintIRWithLIR.getValue()) {
             TTY.println();
         }
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Fri May 02 11:33:47 2014 +0200
@@ -22,13 +22,21 @@
  */
 package com.oracle.graal.lir.gen;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.LIRGenerator.*;
 
 public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
 
+    CodeGenProviders getProviders();
+
     TargetDescription target();
 
     MetaAccessProvider getMetaAccess();
@@ -37,6 +45,20 @@
 
     ForeignCallsProvider getForeignCalls();
 
+    AbstractBlock<?> getCurrentBlock();
+
+    LIRGenerationResult getResult();
+
+    boolean hasBlockEnd(AbstractBlock<?> block);
+
+    void doBlockStart(AbstractBlock<?> block);
+
+    void doBlockEnd(AbstractBlock<?> block);
+
+    Map<Constant, LoadConstant> getConstantLoads();
+
+    void setConstantLoads(Map<Constant, LoadConstant> constantLoads);
+
     Value emitLoad(PlatformKind kind, Value address, LIRFrameState state);
 
     void emitStore(PlatformKind kind, Value address, Value input, LIRFrameState state);
@@ -65,7 +87,7 @@
 
     void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state);
 
-    Value emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
+    Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
 
     /**
      * Checks whether the supplied constant can be used without loading it into a register for most
@@ -81,9 +103,9 @@
 
     RegisterAttributes attributes(Register register);
 
-    AllocatableValue newVariable(PlatformKind kind);
+    Variable newVariable(PlatformKind kind);
 
-    AllocatableValue emitMove(Value input);
+    Variable emitMove(Value input);
 
     void emitMove(AllocatableValue dst, Value src);
 
@@ -116,4 +138,62 @@
      * correct location.
      */
     void emitReturn(Value input);
+
+    AllocatableValue asAllocatable(Value value);
+
+    Variable load(Value value);
+
+    Value loadNonConst(Value value);
+
+    /**
+     * Returns true if the redundant move elimination optimization should be done after register
+     * allocation.
+     */
+    boolean canEliminateRedundantMoves();
+
+    /**
+     * Determines if only oop maps are required for the code generated from the LIR.
+     */
+    boolean needOnlyOopMaps();
+
+    /**
+     * Gets the ABI specific operand used to return a value of a given kind from a method.
+     *
+     * @param kind the kind of value being returned
+     * @return the operand representing the ABI defined location used return a value of kind
+     *         {@code kind}
+     */
+    AllocatableValue resultOperandFor(Kind kind);
+
+    void append(LIRInstruction op);
+
+    void emitJump(LabelRef label);
+
+    void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability);
+
+    void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability);
+
+    void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
+
+    Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
+
+    Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
+
+    void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value);
+
+    void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
+
+    CallingConvention getCallingConvention();
+
+    void emitBitCount(Variable result, Value operand);
+
+    void emitBitScanForward(Variable result, Value operand);
+
+    void emitBitScanReverse(Variable result, Value operand);
+
+    void emitByteSwap(Variable result, Value operand);
+
+    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Fri May 02 11:33:47 2014 +0200
@@ -114,7 +114,7 @@
                 FrameState exitState = exit.stateAfter();
                 if (exitState != null) {
                     exitState.applyToVirtual(v -> {
-                        if (v.usages().filter(n -> nodes.isMarked(n) && !(n instanceof VirtualState && exitState.isPartOfThisState((VirtualState) n))).isEmpty()) {
+                        if (v.usages().filter(n -> nodes.isMarked(n) && n != exit).isEmpty()) {
                             nodes.clear(v);
                         }
                     });
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public abstract class BinaryLogicNode extends LogicNode implements LIRLowerable, MemoryArithmeticLIRLowerable {
-
-    @Input private ValueNode x;
-    @Input private ValueNode y;
-
-    public ValueNode x() {
-        return x;
-    }
-
-    public ValueNode y() {
-        return y;
-    }
-
-    protected void setX(ValueNode x) {
-        updateUsages(this.x, x);
-        this.x = x;
-    }
-
-    protected void setY(ValueNode y) {
-        updateUsages(this.y, y);
-        this.y = y;
-    }
-
-    public BinaryLogicNode(ValueNode x, ValueNode y) {
-        assert x != null && y != null && x.getKind() == y.getKind();
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
-        return super.verify();
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-    }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return false;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable {
+
+    @Input private ValueNode x;
+    @Input private ValueNode y;
+
+    public ValueNode x() {
+        return x;
+    }
+
+    public ValueNode y() {
+        return y;
+    }
+
+    protected void setX(ValueNode x) {
+        updateUsages(this.x, x);
+        this.x = x;
+    }
+
+    protected void setY(ValueNode y) {
+        updateUsages(this.y, y);
+        this.y = y;
+    }
+
+    public BinaryOpLogicNode(ValueNode x, ValueNode y) {
+        assert x != null && y != null && x.getKind() == y.getKind();
+        this.x = x;
+        this.y = y;
+    }
+
+    public abstract TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY);
+
+    @Override
+    public boolean verify() {
+        assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp());
+        return super.verify();
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        switch (evaluate(tool.getConstantReflection(), x(), y())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri May 02 11:33:47 2014 +0200
@@ -95,8 +95,8 @@
         this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
         this.rethrowException = rethrowException;
         this.duringCall = duringCall;
-        assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
-        assert values.size() - localsSize - stackSize == monitorIds.size();
+        assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack";
+        assert this.locksSize() == this.monitorIds.size();
     }
 
     /**
@@ -220,6 +220,19 @@
      * correctly in slot encoding: a long or double will be followed by a null slot.
      */
     public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
+        return duplicateModified(newBci, method, newRethrowException, popKind, pushedValues);
+    }
+
+    /**
+     * Creates a copy of this frame state with one stack element of type popKind popped from the
+     * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted
+     * correctly in slot encoding: a long or double will be followed by a null slot.
+     */
+    public FrameState duplicateModified(Kind popKind, ValueNode... pushedValues) {
+        return duplicateModified(bci, method, rethrowException, popKind, pushedValues);
+    }
+
+    private FrameState duplicateModified(int newBci, ResolvedJavaMethod newMethod, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
         ArrayList<ValueNode> copy = new ArrayList<>(values.subList(0, localsSize + stackSize));
         if (popKind != Kind.Void) {
             if (stackAt(stackSize() - 1) == null) {
@@ -238,7 +251,7 @@
         int newStackSize = copy.size() - localsSize;
         copy.addAll(values.subList(localsSize + stackSize, values.size()));
 
-        FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
+        FrameState other = graph().add(new FrameState(newMethod, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -386,7 +399,7 @@
 
     @Override
     public boolean verify() {
-        assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks");
+        assertTrue(locksSize() == monitorIds.size(), "mismatch in number of locks");
         for (ValueNode value : values) {
             assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
             assertTrue(value == null || value instanceof VirtualObjectNode || (value.getKind() != Kind.Void), "unexpected value: %s", value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri May 02 11:33:47 2014 +0200
@@ -107,7 +107,8 @@
         } else if (condition() instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition();
             if (c.getValue() != negated) {
-                return graph().start();
+                this.replaceAtUsages(null);
+                return null;
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Fri May 02 11:33:47 2014 +0200
@@ -77,7 +77,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (getGuard() == graph().start() || getGuard() == null) {
+        if (getGuard() == null) {
             if (stamp().equals(object().stamp())) {
                 return object();
             } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri May 02 11:33:47 2014 +0200
@@ -51,6 +51,18 @@
         return condition;
     }
 
+    public boolean isNegated() {
+        return negated;
+    }
+
+    public DeoptimizationReason getReason() {
+        return reason;
+    }
+
+    public DeoptimizationAction getAction() {
+        return action;
+    }
+
     /**
      * Constructor for {@link #guardingNonNull(Object)} node intrinsic.
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri May 02 11:33:47 2014 +0200
@@ -34,7 +34,6 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -43,7 +42,7 @@
  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
  * of a comparison.
  */
-public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
 
     @Successor private BeginNode trueSuccessor;
     @Successor private BeginNode falseSuccessor;
@@ -132,11 +131,6 @@
     }
 
     @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return gen.emitIfMemory(this, access);
-    }
-
-    @Override
     public boolean verify() {
         assertTrue(condition() != null, "missing condition");
         assertTrue(trueSuccessor() != null, "missing trueSuccessor");
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Fri May 02 11:33:47 2014 +0200
@@ -43,6 +43,6 @@
 
     @Override
     public String targetName() {
-        return "Indirect#" + ((JavaMethod) target()).getName();
+        return MetaUtil.format("Indirect#%h.%n", target());
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri May 02 11:33:47 2014 +0200
@@ -37,7 +37,7 @@
     private static final double EXCEPTION_PROBA = 1e-5;
 
     @Successor private BeginNode next;
-    @Successor private DispatchBeginNode exceptionEdge;
+    @Successor private BeginNode exceptionEdge;
     @Input(InputType.Extension) private CallTargetNode callTarget;
     @Input(InputType.State) private FrameState stateDuring;
     @Input(InputType.State) private FrameState stateAfter;
@@ -47,7 +47,7 @@
     private boolean useForInlining;
     private double exceptionProbability;
 
-    public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci) {
+    public InvokeWithExceptionNode(CallTargetNode callTarget, BeginNode exceptionEdge, int bci) {
         super(callTarget.returnStamp());
         this.exceptionEdge = exceptionEdge;
         this.bci = bci;
@@ -57,11 +57,11 @@
         this.exceptionProbability = EXCEPTION_PROBA;
     }
 
-    public DispatchBeginNode exceptionEdge() {
+    public BeginNode exceptionEdge() {
         return exceptionEdge;
     }
 
-    public void setExceptionEdge(DispatchBeginNode x) {
+    public void setExceptionEdge(BeginNode x) {
         updatePredecessor(exceptionEdge, x);
         exceptionEdge = x;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri May 02 11:33:47 2014 +0200
@@ -155,7 +155,7 @@
                 return;
             }
             for (PhiNode phi : phis()) {
-                if (phi.usages().filter(isNotA(FrameState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
+                if (phi.usages().filter(isNotA(VirtualState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
                     return;
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri May 02 11:33:47 2014 +0200
@@ -74,6 +74,9 @@
         if (stamp() == StampFactory.forNodeIntrinsic()) {
             return false;
         }
+        if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
+            return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp()));
+        }
         return updateStamp(stamp().join(object().stamp()));
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable {
+
+    @Input private ValueNode object;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    protected void setX(ValueNode object) {
+        updateUsages(this.object, object);
+        this.object = object;
+    }
+
+    public UnaryOpLogicNode(ValueNode object) {
+        assert object != null;
+        this.object = object;
+    }
+
+    public abstract TriState evaluate(ValueNode forObject);
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Fri May 02 11:33:47 2014 +0200
@@ -45,6 +45,10 @@
 
     public abstract void applyToNonVirtual(NodeClosure<? super ValueNode> closure);
 
+    /**
+     * Performs a <b>pre-order</b> iteration over all elements reachable from this state that are a
+     * subclass of {@link VirtualState}.
+     */
     public abstract void applyToVirtual(VirtualClosure closure);
 
     public abstract boolean isPartOfThisState(VirtualState state);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -93,13 +92,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitAnd(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAndMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Fri May 02 11:33:47 2014 +0200
@@ -30,7 +30,7 @@
 /**
  * The {@code LogicNode} class definition.
  */
-public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode {
+public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     /**
      * Constructs a new logic operation node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
@@ -35,7 +36,7 @@
  * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
  * into variants that do not materialize the value (CompareIf, CompareGuard...)
  */
-public abstract class CompareNode extends BinaryLogicNode implements Canonicalizable {
+public abstract class CompareNode extends BinaryOpLogicNode {
 
     /**
      * Constructs a new Compare instruction.
@@ -90,9 +91,18 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (x().isConstant() && y().isConstant()) {
+            return TriState.get(condition().foldCondition(x().asConstant(), y().asConstant(), constantReflection, unorderedIsTrue()));
+        }
+        return TriState.UNKNOWN;
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant() && tool.getMetaAccess() != null) {
-            return LogicConstantNode.forBoolean(condition().foldCondition(x().asConstant(), y().asConstant(), tool.getConstantReflection(), unorderedIsTrue()), graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
         if (x().isConstant()) {
             if (y() instanceof ConditionalNode) {
@@ -110,7 +120,7 @@
         if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
             ConvertNode convertX = (ConvertNode) x();
             ConvertNode convertY = (ConvertNode) y();
-            if (convertX.isLossless() && convertY.isLossless() && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
+            if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
                 setX(convertX.getInput());
                 setY(convertY.getInput());
             }
@@ -132,8 +142,8 @@
         return this;
     }
 
-    private static ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
-        if (convert.isLossless()) {
+    private ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) {
+        if (convert.preservesOrder(condition())) {
             Constant reverseConverted = convert.reverse(constant);
             if (convert.convert(reverseConverted).equals(constant)) {
                 return ConstantNode.forPrimitive(convert.getInput().stamp(), reverseConverted, convert.graph());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
 
@@ -47,8 +48,23 @@
 
     public abstract Constant reverse(Constant c);
 
+    /**
+     * Check whether a conversion is lossless.
+     *
+     * @return true iff reverse(convert(c)) == c for all c
+     */
     public abstract boolean isLossless();
 
+    /**
+     * Check whether a conversion preserves comparison order.
+     *
+     * @param op a comparison operator
+     * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2
+     */
+    public boolean preservesOrder(Condition op) {
+        return isLossless();
+    }
+
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "+")
@@ -85,13 +84,4 @@
         }
         return false;
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAddMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Fri May 02 11:33:47 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
-public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     private final boolean isStrictFP;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Fri May 02 11:33:47 2014 +0200
@@ -30,14 +30,13 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
 
     private final FloatConvert op;
 
@@ -167,12 +166,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getInput())));
     }
-
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitFloatConvertMemory(getOp(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
@@ -61,13 +60,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitDiv(builder.operand(x()), builder.operand(y()), null));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitDivMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Fri May 02 11:33:47 2014 +0200
@@ -22,17 +22,20 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
 public final class FloatEqualsNode extends CompareNode {
 
     /**
      * Constructs a new floating point equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -51,4 +54,18 @@
     public boolean unorderedIsTrue() {
         return false;
     }
+
+    @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (forX.stamp() instanceof FloatStamp && forY.stamp() instanceof FloatStamp) {
+            FloatStamp xStamp = (FloatStamp) forX.stamp();
+            FloatStamp yStamp = (FloatStamp) forY.stamp();
+            if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) {
+                return TriState.TRUE;
+            } else if (xStamp.alwaysDistinct(yStamp)) {
+                return TriState.FALSE;
+            }
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Fri May 02 11:33:47 2014 +0200
@@ -22,11 +22,13 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "<")
 public final class FloatLessThanNode extends CompareNode {
@@ -35,7 +37,7 @@
 
     /**
      * Constructs a new floating point comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      * @param unorderedIsTrue whether a comparison that is undecided (involving NaNs, etc.) leads to
@@ -59,10 +61,10 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y() && !unorderedIsTrue()) {
-            return LogicConstantNode.contradiction(graph());
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) {
+            return TriState.FALSE;
         }
-        return super.canonical(tool);
+        return super.evaluate(constantReflection, forX, forY);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
@@ -71,13 +70,4 @@
         }
         builder.setResult(this, gen.emitMul(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitMulMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
@@ -61,13 +60,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitRem(builder.operand(x()), builder.operand(y()), null));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitRemMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "-")
@@ -80,13 +79,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSubMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -102,13 +101,4 @@
         }
         builder.setResult(this, gen.emitAdd(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitAddMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Fri May 02 11:33:47 2014 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
         super(stamp, x, y);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,18 +23,20 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|<|")
 public final class IntegerBelowThanNode extends CompareNode {
 
     /**
      * Constructs a new unsigned integer comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -55,28 +57,33 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.contradiction(graph());
-        } else {
-            if (x().isConstant() && x().asConstant().asLong() == 0) {
-                // 0 |<| y is the same as 0 != y
-                return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
-            }
-
-            if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-                IntegerStamp xStamp = (IntegerStamp) x().stamp();
-                IntegerStamp yStamp = (IntegerStamp) y().stamp();
-                if (yStamp.isPositive()) {
-                    if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
-                        return LogicConstantNode.tautology(graph());
-                    } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
-                        return LogicConstantNode.contradiction(graph());
-                    }
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.FALSE;
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (yStamp.isPositive()) {
+                if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+                    return TriState.TRUE;
+                } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+                    return TriState.FALSE;
                 }
             }
         }
+        return super.evaluate(constantReflection, forX, forY);
+    }
 
-        return super.canonical(tool);
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
+        }
+        if (x().isConstant() && x().asConstant().asLong() == 0) {
+            // 0 |<| y is the same as 0 != y
+            return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
+        }
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri May 02 11:33:47 2014 +0200
@@ -31,7 +31,7 @@
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
 
     private final int resultBits;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -35,7 +36,7 @@
 
     /**
      * Constructs a new integer equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -71,24 +72,28 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.TRUE;
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return TriState.FALSE;
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (GraphUtil.unproxify(x()) == GraphUtil.unproxify(y())) {
-            return LogicConstantNode.tautology(graph());
-        } else if (x().stamp().alwaysDistinct(y().stamp())) {
-            return LogicConstantNode.contradiction(graph());
-        }
-
-        ValueNode result = canonicalizeSymmetric(x(), y());
-        if (result != null) {
+        Node result = super.canonical(tool);
+        if (result != this) {
             return result;
         }
 
-        result = canonicalizeSymmetric(y(), x());
-        if (result != null) {
+        result = canonicalizeSymmetric(x(), y());
+        if (result != this) {
             return result;
         }
 
-        return super.canonical(tool);
+        return canonicalizeSymmetric(y(), x());
     }
 
     private ValueNode canonicalizeSymmetric(ValueNode x, ValueNode y) {
@@ -133,6 +138,6 @@
                 }
             }
         }
-        return null;
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,18 +23,20 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "<")
 public final class IntegerLessThanNode extends CompareNode {
 
     /**
      * Constructs a new integer comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -71,22 +73,32 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.FALSE;
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (xStamp.upperBound() < yStamp.lowerBound()) {
+                return TriState.TRUE;
+            } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
+                return TriState.FALSE;
+            }
+        }
+        return super.evaluate(constantReflection, forX, forY);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.contradiction(graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
         if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-            IntegerStamp xStamp = (IntegerStamp) x().stamp();
-            IntegerStamp yStamp = (IntegerStamp) y().stamp();
-            if (xStamp.upperBound() < yStamp.lowerBound()) {
-                return LogicConstantNode.tautology(graph());
-            } else if (xStamp.lowerBound() >= yStamp.upperBound()) {
-                return LogicConstantNode.contradiction(graph());
-            }
-            if (IntegerStamp.sameSign(xStamp, yStamp)) {
+            if (IntegerStamp.sameSign((IntegerStamp) x().stamp(), (IntegerStamp) y().stamp())) {
                 return graph().unique(new IntegerBelowThanNode(x(), y()));
             }
         }
-        return super.canonical(tool);
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri May 02 11:33:47 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
@@ -86,13 +85,4 @@
         }
         builder.setResult(this, gen.emitMul(op1, op2));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitMulMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -122,13 +121,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSubMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Fri May 02 11:33:47 2014 +0200
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -32,7 +32,7 @@
  * expression "(x &amp; y) == 0", meaning that it will return true if (and only if) no bit is set in
  * both x and y.
  */
-public class IntegerTestNode extends BinaryLogicNode implements Canonicalizable {
+public class IntegerTestNode extends BinaryOpLogicNode {
 
     /**
      * Constructs a new Test instruction.
@@ -45,19 +45,19 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && y().isConstant()) {
-            return LogicConstantNode.forBoolean((x().asConstant().asLong() & y().asConstant().asLong()) == 0, graph());
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            return TriState.get((forX.asConstant().asLong() & forY.asConstant().asLong()) == 0);
         }
         if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
-            IntegerStamp xStamp = (IntegerStamp) x().stamp();
-            IntegerStamp yStamp = (IntegerStamp) y().stamp();
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
             if ((xStamp.upMask() & yStamp.upMask()) == 0) {
-                return LogicConstantNode.tautology(graph());
+                return TriState.TRUE;
             } else if ((xStamp.downMask() & yStamp.downMask()) != 0) {
-                return LogicConstantNode.contradiction(graph());
+                return TriState.FALSE;
             }
         }
-        return this;
+        return TriState.UNKNOWN;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -33,21 +34,15 @@
 /**
  * An IsNullNode will be true if the supplied value is null, and false if it is non-null.
  */
-public final class IsNullNode extends LogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
-
-    @Input private ValueNode object;
-
-    public ValueNode object() {
-        return object;
-    }
+public final class IsNullNode extends UnaryOpLogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable {
 
     /**
      * Constructs a new IsNullNode instruction.
-     * 
+     *
      * @param object the instruction producing the object to check against null
      */
     public IsNullNode(ValueNode object) {
-        this.object = object;
+        super(object);
     }
 
     @Override
@@ -64,20 +59,31 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        Constant constant = object().asConstant();
-        if (constant != null) {
-            assert constant.getKind() == Kind.Object;
-            return LogicConstantNode.forBoolean(constant.isNull(), graph());
-        }
-        if (StampTool.isObjectNonNull(object.stamp())) {
-            return LogicConstantNode.contradiction(graph());
+        switch (evaluate(object())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
         }
         return this;
     }
 
     @Override
+    public TriState evaluate(ValueNode forObject) {
+        Constant constant = forObject.asConstant();
+        if (constant != null) {
+            assert constant.getKind() == Kind.Object;
+            return TriState.get(constant.isNull());
+        }
+        if (StampTool.isObjectNonNull(forObject.stamp())) {
+            return TriState.FALSE;
+        }
+        return TriState.UNKNOWN;
+    }
+
+    @Override
     public void virtualize(VirtualizerTool tool) {
-        if (tool.getObjectState(object) != null) {
+        if (tool.getObjectState(object()) != null) {
             tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -109,13 +108,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitNarrow(builder.operand(getInput()), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitNarrowMemory(getResultBits(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,19 +23,21 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "==")
 public final class ObjectEqualsNode extends CompareNode implements Virtualizable {
 
     /**
      * Constructs a new object equality comparison node.
-     * 
+     *
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
@@ -56,21 +58,28 @@
     }
 
     @Override
+    public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return TriState.TRUE;
+        } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            return TriState.FALSE;
+        } else {
+            return super.evaluate(constantReflection, forX, forY);
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (x() == y()) {
-            return LogicConstantNode.tautology(graph());
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
         }
-
         if (StampTool.isObjectAlwaysNull(x())) {
             return graph().unique(new IsNullNode(y()));
         } else if (StampTool.isObjectAlwaysNull(y())) {
             return graph().unique(new IsNullNode(x()));
         }
-        if (x().stamp().alwaysDistinct(y().stamp())) {
-            return LogicConstantNode.contradiction(graph());
-        }
-
-        return super.canonical(tool);
+        return this;
     }
 
     private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -78,13 +77,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitOr(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitOrMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Fri May 02 11:33:47 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -37,7 +36,7 @@
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
+public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
 
     @Input private ValueNode value;
 
@@ -109,15 +108,6 @@
         builder.setResult(this, gen.emitReinterpret(kind, builder.operand(value())));
     }
 
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitReinterpretMemory(stamp(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
-
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
         return value.graph().unique(new ReinterpretNode(toKind, value));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -110,13 +109,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitSignExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitSignExtendMemory(access, getInputBits(), getResultBits());
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Fri May 02 11:33:47 2014 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -77,13 +76,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitXor(builder.operand(x()), builder.operand(y())));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitXorMemory(x(), y(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,12 +23,12 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -65,6 +65,19 @@
     }
 
     @Override
+    public boolean preservesOrder(Condition op) {
+        switch (op) {
+            case GE:
+            case GT:
+            case LE:
+            case LT:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         ValueNode ret = canonicalConvert();
         if (ret != null) {
@@ -103,13 +116,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitZeroExtend(builder.operand(getInput()), getInputBits(), getResultBits()));
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access);
-        if (result != null) {
-            gen.setResult(this, result);
-        }
-        return result != null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Fri May 02 11:33:47 2014 +0200
@@ -25,8 +25,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 
 public final class Block extends AbstractBlockBase<Block> {
 
@@ -67,7 +67,8 @@
     }
 
     public boolean isExceptionEntry() {
-        return getBeginNode() instanceof ExceptionObjectNode;
+        Node predecessor = getBeginNode().predecessor();
+        return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge();
     }
 
     public Block getFirstPredecessor() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Fri May 02 11:33:47 2014 +0200
@@ -30,7 +30,7 @@
  * This node can be used to add a counter to the code that will estimate the dynamic number of calls
  * by adding an increment to the compiled code. This should of course only be used for
  * debugging/testing purposes.
- * 
+ *
  * A unique counter will be created for each unique name passed to the constructor. Depending on the
  * value of withContext, the name of the root method is added to the counter's name.
  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri May 02 11:33:47 2014 +0200
@@ -38,8 +38,8 @@
 @NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
 public final class AddLocationNode extends LocationNode implements Canonicalizable {
 
-    @Input private ValueNode x;
-    @Input private ValueNode y;
+    @Input(InputType.Association) private ValueNode x;
+    @Input(InputType.Association) private ValueNode y;
 
     protected LocationNode getX() {
         return (LocationNode) x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java	Fri May 02 11:33:47 2014 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * A node that may be guarded by a {@linkplain GuardingNode guarding node}.
  */
-public interface GuardedNode {
+public interface GuardedNode extends NodeInterface {
 
     GuardingNode getGuard();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Fri May 02 11:33:47 2014 +0200
@@ -40,7 +40,7 @@
         /**
          * This method is used to determine which memory location is killed by this node. Returning
          * the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory locations.
-         * 
+         *
          * @return the identity of the location killed by this node.
          */
         LocationIdentity getLocationIdentity();
@@ -53,7 +53,7 @@
          * This method is used to determine which set of memory locations is killed by this node.
          * Returning the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory
          * locations.
-         * 
+         *
          * @return the identities of all locations killed by this node.
          */
         LocationIdentity[] getLocationIdentities();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Fri May 02 11:33:47 2014 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * This interface marks nodes that are part of the memory graph.
  */
-public interface MemoryNode {
+public interface MemoryNode extends NodeInterface {
 
     ValueNode asNode();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri May 02 11:33:47 2014 +0200
@@ -60,21 +60,30 @@
     }
 
     @Override
-    public boolean inferStamp() {
-        if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
-            return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp()));
-        }
-        return updateStamp(object.stamp().join(stamp()));
-    }
-
-    @Override
     public Node canonical(CanonicalizerTool tool) {
         assert getKind() == Kind.Object && object.getKind() == Kind.Object;
-        if (stamp().equals(object.stamp())) {
-            return object;
-        } else {
+
+        ObjectStamp my = (ObjectStamp) stamp();
+        ObjectStamp other = (ObjectStamp) object.stamp();
+
+        if (my.type() == null || other.type() == null) {
+            return this;
+        }
+        if (my.isExactType() && !other.isExactType()) {
             return this;
         }
+        if (my.nonNull() && !other.nonNull()) {
+            return this;
+        }
+        if (!my.type().isAssignableFrom(other.type())) {
+            return this;
+        }
+        /*
+         * The unsafe cast does not add any new type information, so it can be removed. Note that
+         * this means that the unsafe cast cannot be used to "drop" type information (in which case
+         * it must not be canonicalized in any case).
+         */
+        return object;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri May 02 11:33:47 2014 +0200
@@ -22,13 +22,9 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,6 +33,7 @@
  * The entry to an exception handler with the exception coming from a call (as opposed to a local
  * throw instruction or implicit exception).
  */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, MemoryCheckpoint.Single {
 
     public ExceptionObjectNode(MetaAccessProvider metaAccess) {
@@ -49,56 +46,13 @@
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        //
-    }
-
-    private boolean isLowered() {
-        return (stamp() == StampFactory.forVoid());
-    }
-
-    /**
-     * The frame state upon entry to an exception handler is such that it is a
-     * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly
-     * the exception object (per the JVM spec) to rethrow. This means that the code creating this
-     * state (i.e. the {@link LoadExceptionObjectNode}) cannot cause a deoptimization as the
-     * runtime/interpreter would not have a valid location for the exception object to be rethrown.
-     */
-    @Override
     public void lower(LoweringTool tool) {
-        if (isLowered()) {
-            return;
-        }
-        LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp()));
-        loadException.setStateAfter(stateAfter());
-        List<GuardedNode> guardedNodes = new ArrayList<>();
-        for (Node usage : usages().snapshot()) {
-            if (usage instanceof GuardedNode) {
-                // can't replace the guard with LoadExceptionObjectNode as it is not a GuardingNode
-                // so temporarily change it to remove the GuardedNode from usages
-                GuardedNode guardedNode = (GuardedNode) usage;
-                guardedNode.setGuard(graph().add(new BeginNode()));
-                guardedNodes.add(guardedNode);
-            }
-        }
-        replaceAtUsages(loadException);
-        for (GuardedNode guardedNode : guardedNodes) {
-            BeginNode dummyGuard = (BeginNode) guardedNode.getGuard();
-            guardedNode.setGuard(this);
-            graph().removeFixed(dummyGuard);
-        }
-        graph().addAfterFixed(this, loadException);
-        setStateAfter(null);
-        setStamp(StampFactory.forVoid());
-        loadException.lower(tool);
+        tool.getLowerer().lower(this, tool);
     }
 
     @Override
     public boolean verify() {
-        if (isLowered()) {
-            return true;
-        }
-        assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state");
+        assertTrue(stateAfter() != null, "an exception handler needs a frame state");
         return super.verify();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -33,21 +34,20 @@
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-public final class InstanceOfNode extends LogicNode implements Canonicalizable, Lowerable, Virtualizable {
+public final class InstanceOfNode extends UnaryOpLogicNode implements Canonicalizable, Lowerable, Virtualizable {
 
-    @Input private ValueNode object;
     private final ResolvedJavaType type;
     private JavaTypeProfile profile;
 
     /**
      * Constructs a new InstanceOfNode.
-     * 
+     *
      * @param type the target type of the instanceof check
      * @param object the object being tested by the instanceof
      */
     public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+        super(object);
         this.type = type;
-        this.object = object;
         this.profile = profile;
         assert type != null;
     }
@@ -59,13 +59,39 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        Stamp stamp = object().stamp();
+        switch (evaluate(object())) {
+            case FALSE:
+                return LogicConstantNode.contradiction(graph());
+            case TRUE:
+                return LogicConstantNode.tautology(graph());
+            case UNKNOWN:
+                Stamp stamp = object().stamp();
+                if (stamp instanceof ObjectStamp) {
+                    ObjectStamp objectStamp = (ObjectStamp) stamp;
+                    ResolvedJavaType stampType = objectStamp.type();
+                    if (stampType != null && type().isAssignableFrom(stampType)) {
+                        if (!objectStamp.nonNull()) {
+                            // the instanceof matches if the object is non-null, so return true
+                            // depending on the null-ness.
+                            IsNullNode isNull = graph().unique(new IsNullNode(object()));
+                            return graph().unique(new LogicNegationNode(isNull));
+                        }
+                    }
+                }
+                return this;
+        }
+        return this;
+    }
+
+    @Override
+    public TriState evaluate(ValueNode forObject) {
+        Stamp stamp = forObject.stamp();
         if (!(stamp instanceof ObjectStamp)) {
-            return this;
+            return TriState.UNKNOWN;
         }
         ObjectStamp objectStamp = (ObjectStamp) stamp;
         if (objectStamp.alwaysNull()) {
-            return LogicConstantNode.contradiction(graph());
+            return TriState.FALSE;
         }
 
         ResolvedJavaType stampType = objectStamp.type();
@@ -74,34 +100,25 @@
             if (subType) {
                 if (objectStamp.nonNull()) {
                     // the instanceOf matches, so return true
-                    return LogicConstantNode.tautology(graph());
-                } else {
-                    // the instanceof matches if the object is non-null, so return true depending on
-                    // the null-ness.
-                    IsNullNode isNull = graph().unique(new IsNullNode(object()));
-                    return graph().unique(new LogicNegationNode(isNull));
+                    return TriState.TRUE;
                 }
             } else {
                 if (objectStamp.isExactType()) {
                     // since this type check failed for an exact type we know that it can never
                     // succeed at run time. we also don't care about null values, since they will
                     // also make the check fail.
-                    return LogicConstantNode.contradiction(graph());
+                    return TriState.FALSE;
                 } else {
                     boolean superType = stampType.isAssignableFrom(type());
                     if (!superType && !stampType.isInterface() && !type().isInterface()) {
-                        return LogicConstantNode.contradiction(graph());
+                        return TriState.FALSE;
                     }
                     // since the subtype comparison was only performed on a declared type we don't
                     // really know if it might be true at run time...
                 }
             }
         }
-        return this;
-    }
-
-    public ValueNode object() {
-        return object;
+        return TriState.UNKNOWN;
     }
 
     /**
@@ -121,7 +138,7 @@
 
     @Override
     public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
+        State state = tool.getObjectState(object());
         if (state != null) {
             tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph()));
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.nodes.java;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * Loads an exception object passed by the runtime from a callee to an exception handler in a
- * caller. The node is only produced when lowering an {@link ExceptionObjectNode}.
- * <p>
- * The frame state upon entry to an exception handler is such that it is a
- * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the
- * exception object (per the JVM spec) to rethrow. This means that the code generated for this node
- * must not cause a deoptimization as the runtime/interpreter would not have a valid location to
- * find the exception object to be rethrown.
- */
-public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
-
-    public LoadExceptionObjectNode(Stamp stamp) {
-        super(stamp);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        tool.getLowerer().lower(this, tool);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java	Fri May 02 11:33:47 2014 +0200
@@ -22,13 +22,14 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
  * Interface implemented by nodes that can replace themselves with lower level nodes during a phase
  * that transforms a graph to replace higher level nodes with lower level nodes.
  */
-public interface Lowerable {
+public interface Lowerable extends NodeInterface {
 
     /**
      * Expand this node into lower level nodes expressing the same semantics. If the introduced
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Marks nodes which may be lowered in combination with a memory operation.
- */
-public interface MemoryArithmeticLIRLowerable {
-
-    /**
-     * Attempt to generate a memory form of a node operation. On platforms that support it this will
-     * be called when the merging is safe.
-     * 
-     * @param gen
-     * @param access the memory input which can potentially merge into this operation.
-     * @return null if it's not possible to emit a memory form of this operation. A non-null value
-     *         will be set as the operand of this node.
-     */
-    boolean generate(MemoryArithmeticLIRLowerer gen, Access access);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * This interface can be used to generate LIR for arithmetic operations where one of the operations
- * is load (@see ArithmeticLIRLowerable).
- */
-public interface MemoryArithmeticLIRLowerer {
-
-    Value setResult(ValueNode x, Value operand);
-
-    Value emitAddMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitMulMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitSubMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitDivMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitRemMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitXorMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitOrMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitAndMemory(ValueNode x, ValueNode y, Access access);
-
-    Value emitReinterpretMemory(Stamp stamp, Access access);
-
-    Value emitSignExtendMemory(Access access, int fromBits, int toBits);
-
-    Value emitNarrowMemory(int resultBits, Access access);
-
-    Value emitZeroExtendMemory(int inputBits, int resultBits, Access access);
-
-    Value emitFloatConvertMemory(FloatConvert op, Access access);
-
-    boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred);
-
-    boolean emitIfMemory(IfNode ifNode, Access access);
-
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Fri May 02 11:33:47 2014 +0200
@@ -26,10 +26,12 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 
 public interface NodeLIRBuilderTool extends NodeMappableLIRBuilder {
@@ -68,5 +70,13 @@
 
     Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments);
 
-    MemoryArithmeticLIRLowerer getMemoryLowerer();
+    Variable newVariable(Kind kind);
+
+    void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length);
+
+    void emitBitCount(Variable result, Value operand);
+
+    void emitBitScanForward(Variable result, Value operand);
+
+    void doBlock(Block block, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Fri May 02 11:33:47 2014 +0200
@@ -29,9 +29,7 @@
 /**
  * Interface for nodes which have {@link FrameState} nodes as input.
  */
-public interface NodeWithState {
-
-    Node asNode();
+public interface NodeWithState extends NodeInterface {
 
     default NodeIterable<FrameState> states() {
         return asNode().inputs().filter(FrameState.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java	Fri May 02 11:33:47 2014 +0200
@@ -24,11 +24,12 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 
 /**
  * Interface for service providers that register replacements with the compiler.
  */
 public interface ReplacementsProvider {
 
-    void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target);
+    void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Fri May 02 11:33:47 2014 +0200
@@ -506,22 +506,22 @@
     }
 
     /**
-     * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain ValueNode} has if it is
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is
      * a {@linkplain Stamp#isLegal() legal} Object value.
      *
      * @param node the node to check
-     * @return the javat type this value has if it is a legal Object type, null otherwise
+     * @return the Java type this value has if it is a legal Object type, null otherwise
      */
     public static ResolvedJavaType typeOrNull(ValueNode node) {
         return typeOrNull(node.stamp());
     }
 
     /**
-     * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain Stamp} has if it is a
+     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a
      * {@linkplain Stamp#isLegal() legal} Object stamp.
      *
      * @param stamp the stamp to check
-     * @return the java type this stamp has if it is a legal Object stamp, null otherwise
+     * @return the Java type this stamp has if it is a legal Object stamp, null otherwise
      */
     public static ResolvedJavaType typeOrNull(Stamp stamp) {
         if (stamp instanceof ObjectStamp && stamp.isLegal()) {
@@ -532,12 +532,12 @@
 
     /**
      * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#isLegal() legal} Object
-     * value whose java type is known exactly. If this method returns true then the
-     * {@linkplain ResolvedJavaType java type} returned by {@link #typeOrNull(ValueNode)} is the
-     * concrete dynamic/runtime java type of this value.
+     * value whose Java type is known exactly. If this method returns true then the
+     * {@linkplain ResolvedJavaType Java type} returned by {@link #typeOrNull(ValueNode)} is the
+     * concrete dynamic/runtime Java type of this value.
      *
      * @param node the node to check
-     * @return true if this node represents a legal object value whose java type is known exactly
+     * @return true if this node represents a legal object value whose Java type is known exactly
      */
     public static boolean isExactType(ValueNode node) {
         return isExactType(node.stamp());
@@ -545,12 +545,12 @@
 
     /**
      * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} Object
-     * stamp whose {@linkplain ResolvedJavaType java type} is known exactly. If this method returns
-     * true then the java type returned by {@link #typeOrNull(Stamp)} is the only concrete
-     * dynamic/runtime java type possible for values of this stamp.
+     * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns
+     * true then the Java type returned by {@link #typeOrNull(Stamp)} is the only concrete
+     * dynamic/runtime Java type possible for values of this stamp.
      *
      * @param stamp the stamp to check
-     * @return true if this node represents a legal object stamp whose java type is known exactly
+     * @return true if this node represents a legal object stamp whose Java type is known exactly
      */
     public static boolean isExactType(Stamp stamp) {
         if (stamp instanceof ObjectStamp && stamp.isLegal()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri May 02 11:33:47 2014 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
@@ -42,12 +43,12 @@
         }
     };
 
-    public static void killCFG(Node node) {
+    public static void killCFG(Node node, SimplifierTool tool) {
         assert node.isAlive();
         if (node instanceof AbstractEndNode) {
             // We reached a control flow end.
             AbstractEndNode end = (AbstractEndNode) node;
-            killEnd(end);
+            killEnd(end, tool);
         } else {
             // Normal control flow node.
             /*
@@ -57,13 +58,17 @@
              * while processing one branch.
              */
             for (Node successor : node.successors()) {
-                killCFG(successor);
+                killCFG(successor, tool);
             }
         }
         propagateKill(node);
     }
 
-    private static void killEnd(AbstractEndNode end) {
+    public static void killCFG(Node node) {
+        killCFG(node, null);
+    }
+
+    private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
         MergeNode merge = end.merge();
         if (merge != null) {
             merge.removeEnd(end);
@@ -85,12 +90,17 @@
                     killCFG(loopBody);
                 }
                 begin.safeDelete();
-            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not
-                                                                                                         // a
-                                                                                                         // loop
-                                                                                                         // anymore
+            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
+                // not a loop anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+                }
                 graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
-            } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore
+            } else if (merge.phiPredecessorCount() == 1) {
+                // not a merge anymore
+                if (tool != null) {
+                    merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+                }
                 graph.reduceTrivialMerge(merge);
             }
         }
@@ -333,6 +343,14 @@
         return v;
     }
 
+    public static boolean tryKillUnused(Node node) {
+        if (node.isAlive() && isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
+            killWithUnusedFloatingInputs(node);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Exhaustive search for {@link GraphUtil#originalValue(ValueNode)} when a simple search fails.
      * This can happen in the presence of complicated phi/proxy/phi constructs.
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java	Fri May 02 11:33:47 2014 +0200
@@ -40,8 +40,10 @@
  *
  * <pre>
  * ServiceLoader&lt;Options&gt; sl = ServiceLoader.loadInstalled(Options.class);
- * for (OptionDescriptor desc : sl) {
- *     // use desc
+ * for (Options opts : sl) {
+ *     for (OptionDescriptor desc : sl) {
+ *         // use desc
+ *     }
  * }
  * </pre>
  */
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri May 02 11:33:47 2014 +0200
@@ -178,7 +178,7 @@
                 }
                 StructuredGraph graph = (StructuredGraph) node.graph();
                 Mark mark = graph.getMark();
-                if (!tryKillUnused(node)) {
+                if (!GraphUtil.tryKillUnused(node)) {
                     if (!tryCanonicalize(node, nodeClass)) {
                         if (node instanceof ValueNode) {
                             ValueNode valueNode = (ValueNode) node;
@@ -200,14 +200,6 @@
             }
         }
 
-        private static boolean tryKillUnused(Node node) {
-            if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) {
-                GraphUtil.killWithUnusedFloatingInputs(node);
-                return true;
-            }
-            return false;
-        }
-
         public static boolean tryGlobalValueNumbering(Node node, NodeClass nodeClass) {
             if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) {
                 Node newNode = node.graph().findDuplicate(node);
@@ -354,7 +346,7 @@
             @Override
             public void deleteBranch(Node branch) {
                 branch.predecessor().replaceFirstSuccessor(branch, null);
-                GraphUtil.killCFG(branch);
+                GraphUtil.killCFG(branch, this);
             }
 
             /**
@@ -383,7 +375,7 @@
 
             @Override
             public void removeIfUnused(Node node) {
-                tryKillUnused(node);
+                GraphUtil.tryKillUnused(node);
             }
 
             @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri May 02 11:33:47 2014 +0200
@@ -1316,8 +1316,6 @@
         assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
         assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
 
-        Kind returnKind = invokeNode.getKind();
-
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter == null || stateAfter.isAlive();
         if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
@@ -1401,38 +1399,8 @@
         }
 
         if (stateAfter != null) {
-            FrameState outerFrameState = null;
+            processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge);
             int callerLockDepth = stateAfter.nestedLockDepth();
-            for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
-                FrameState frameState = (FrameState) duplicates.get(original);
-                if (frameState != null && frameState.isAlive()) {
-                    assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
-                    if (frameState.bci == BytecodeFrame.AFTER_BCI) {
-                        frameState.replaceAndDelete(returnKind == Kind.Void ? stateAfter : stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), returnKind,
-                                        frameState.stackAt(0)));
-                    } else if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized())) {
-                        if (stateAtExceptionEdge != null) {
-                            frameState.replaceAndDelete(stateAtExceptionEdge);
-                        } else {
-                            handleMissingAfterExceptionFrameState(frameState);
-                        }
-                    } else if (frameState.bci == BytecodeFrame.UNWIND_BCI) {
-                        handleMissingAfterExceptionFrameState(frameState);
-                    } else {
-                        // only handle the outermost frame states
-                        if (frameState.outerFrameState() == null) {
-                            assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
-                            assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
-                                            frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
-                            if (outerFrameState == null) {
-                                outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.getKind());
-                                outerFrameState.setDuringCall(true);
-                            }
-                            frameState.setOuterFrameState(outerFrameState);
-                        }
-                    }
-                }
-            }
             if (callerLockDepth != 0) {
                 for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
                     MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
@@ -1470,10 +1438,61 @@
         return duplicates;
     }
 
-    protected static void handleMissingAfterExceptionFrameState(FrameState nonReplacableFrameState) {
-        Graph graph = nonReplacableFrameState.graph();
+    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge) {
+        FrameState stateAtReturn = invoke.stateAfter();
+        FrameState outerFrameState = null;
+        Kind invokeReturnKind = invoke.asNode().getKind();
+        for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+            FrameState frameState = (FrameState) duplicates.get(original);
+            if (frameState != null && frameState.isAlive()) {
+                if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+                    /*
+                     * pop return kind from invoke's stateAfter and replace with this frameState's
+                     * return value (top of stack)
+                     */
+                    FrameState stateAfterReturn = stateAtReturn;
+                    if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) {
+                        stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
+                    }
+                    frameState.replaceAndDelete(stateAfterReturn);
+                } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
+                    /*
+                     * pop exception object from invoke's stateAfter and replace with this
+                     * frameState's exception object (top of stack)
+                     */
+                    FrameState stateAfterException = stateAtExceptionEdge;
+                    if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
+                        stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0));
+                    }
+                    frameState.replaceAndDelete(stateAfterException);
+                } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+                    handleMissingAfterExceptionFrameState(frameState);
+                } else {
+                    // only handle the outermost frame states
+                    if (frameState.outerFrameState() == null) {
+                        assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
+                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
+                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
+                                        frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
+                        if (outerFrameState == null) {
+                            outerFrameState = stateAtReturn.duplicateModified(invoke.bci(), stateAtReturn.rethrowException(), invokeReturnKind);
+                            outerFrameState.setDuringCall(true);
+                        }
+                        frameState.setOuterFrameState(outerFrameState);
+                    }
+                }
+            }
+        }
+    }
+
+    private static boolean isStateAfterException(FrameState frameState) {
+        return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized());
+    }
+
+    protected static void handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
+        Graph graph = nonReplaceableFrameState.graph();
         NodeWorkList workList = graph.createNodeWorkList();
-        workList.add(nonReplacableFrameState);
+        workList.add(nonReplaceableFrameState);
         for (Node node : workList) {
             FrameState fs = (FrameState) node;
             for (Node usage : fs.usages().snapshot()) {
@@ -1494,7 +1513,10 @@
                             GraphUtil.killCFG(end);
                         }
                     } else {
-                        DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                        FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                        if (fixedStateSplit instanceof BeginNode) {
+                            deoptimizeNode = BeginNode.begin(deoptimizeNode);
+                        }
                         fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
                         GraphUtil.killCFG(fixedStateSplit);
                     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Fri May 02 11:33:47 2014 +0200
@@ -62,7 +62,7 @@
             canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
             listener.getChangedNodes().clear();
             if (++count > MAX_ITERATIONS) {
-                throw new BailoutException("Number of iterations in conditional elimination phase exceeds " + MAX_ITERATIONS);
+                throw new BailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds " + MAX_ITERATIONS);
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri May 02 11:33:47 2014 +0200
@@ -240,14 +240,20 @@
 
         private final PhaseContext context;
         private final SchedulePhase schedule;
+        private final int iteration;
 
         private Round(int iteration, PhaseContext context) {
-            super("LoweringIteration" + iteration);
+            this.iteration = iteration;
             this.context = context;
             this.schedule = new SchedulePhase();
         }
 
         @Override
+        protected CharSequence createName() {
+            return "LoweringIteration" + iteration;
+        }
+
+        @Override
         public void run(StructuredGraph graph) {
             schedule.apply(graph, false);
             processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Fri May 02 11:33:47 2014 +0200
@@ -55,8 +55,11 @@
 
     private static final String GROUP_NAME = "~profiled weight";
     private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)";
+    private static final String GROUP_NAME_INVOKES = "~profiled invokes";
 
     private static final boolean WITH_SECTION_HEADER = false;
+    private static boolean WITH_INVOKE_FREE_SECTIONS = false;
+    private static boolean WITH_INVOKES = true;
 
     @Override
     protected void run(StructuredGraph graph) {
@@ -72,7 +75,22 @@
                 addSectionCounters(loop.header.getBeginNode(), loop.blocks, loop.children, schedule, probabilities);
             }
         }
-        addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+        // don't put the counter increase directly after the start (problems with OSR)
+        FixedWithNextNode current = graph.start();
+        while (current.next() instanceof FixedWithNextNode) {
+            current = (FixedWithNextNode) current.next();
+        }
+        addSectionCounters(current, Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities);
+
+        if (WITH_INVOKES) {
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Invoke) {
+                    Invoke invoke = (Invoke) node;
+                    DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode());
+
+                }
+            }
+        }
     }
 
     private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) {
@@ -82,7 +100,7 @@
         }
         double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start);
         DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
-        if (!hasInvoke(blocks)) {
+        if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) {
             DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next());
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.phases.graph.PostOrderNodeIterator;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.util.ArrayList;
+
+/**
+ * <p>
+ * For readability purposes the code realizing control-flow-sensitive reductions is chopped into
+ * several classes in an inheritance hierarchy, this class being their common ancestor. That way,
+ * many dependencies can be ruled out immediately (e.g., private members of a class aren't needed by
+ * other classes). The whole thing is reminiscent of trait-based patterns, minus their
+ * disadvantages.
+ * </p>
+ *
+ *
+ * <p>
+ * This class makes available little more than a few fields and a few utility methods used
+ * throughout the remaining components making up control-flow sensitive reductions.
+ * </p>
+ */
+public abstract class BaseReduction extends PostOrderNodeIterator<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");
+
+    /**
+     * <p>
+     * Upon visiting a {@link com.oracle.graal.nodes.FixedNode FixedNode} in
+     * {@link #node(com.oracle.graal.nodes.FixedNode)}, an impossible path may be detected. We'd
+     * like to insert an unconditional deoptimizing node as a hint for Dead Code Elimination to kill
+     * that branch. However that can't be made on the go (a
+     * {@link com.oracle.graal.nodes.ControlSinkNode} can't have successors). Thus their insertion
+     * is postponed till the end of a round of
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}.
+     * </p>
+     *
+     * @see State#impossiblePath()
+     * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#finished()
+     */
+    public static class PostponedDeopt {
+
+        private final boolean goesBeforeFixed;
+        private final FixedWithNextNode fixed;
+        private final DeoptimizationReason deoptReason;
+
+        public PostponedDeopt(boolean goesBeforeFixed, FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            this.goesBeforeFixed = goesBeforeFixed;
+            this.fixed = fixed;
+            this.deoptReason = deoptReason;
+        }
+
+        public void doRewrite(LogicNode falseConstant) {
+            StructuredGraph graph = fixed.graph();
+            // have to insert a FixedNode other than a ControlSinkNode
+            FixedGuardNode buckStopsHere = graph.add(new FixedGuardNode(falseConstant, deoptReason, DeoptimizationAction.None));
+            if (goesBeforeFixed) {
+                fixed.replaceAtPredecessor(buckStopsHere);
+            } else {
+                graph.addAfterFixed(fixed, buckStopsHere);
+            }
+        }
+
+    }
+
+    protected static class PostponedDeopts extends ArrayList<PostponedDeopt> {
+
+        private static final long serialVersionUID = 7188324432387121238L;
+
+        /**
+         * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right before the fixed
+         * argument, will be done once we're done traversing the graph.
+         *
+         * @see #finished()
+         */
+        void addDeoptBefore(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            add(new PostponedDeopt(true, fixed, deoptReason));
+        }
+
+        /**
+         * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right after the fixed
+         * argument, will be done once we're done traversing the graph.
+         *
+         * @see #finished()
+         */
+        void addDeoptAfter(FixedWithNextNode fixed, DeoptimizationReason deoptReason) {
+            add(new PostponedDeopt(false, fixed, deoptReason));
+        }
+
+    }
+
+    /**
+     * <p>
+     * One of the promises of
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+     * is that a "maximally reduced" node is returned. That is achieved in part by leveraging
+     * {@link com.oracle.graal.graph.Node#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)}.
+     * Doing so, in turn, requires this subclass of
+     * {@link com.oracle.graal.graph.spi.CanonicalizerTool}.
+     * </p>
+     */
+    public final class Tool implements CanonicalizerTool {
+
+        private final PhaseContext context;
+
+        public Tool(PhaseContext context) {
+            this.context = context;
+        }
+
+        @Override
+        public Assumptions assumptions() {
+            return context.getAssumptions();
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return context.getMetaAccess();
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return context.getConstantReflection();
+        }
+
+        /**
+         * Postpone
+         * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)}
+         * until {@link FlowSensitiveReduction#finished()} for the reasons covered there.
+         */
+        @Override
+        public void removeIfUnused(Node node) {
+            // GraphUtil.tryKillUnused(node);
+        }
+
+        @Override
+        public boolean canonicalizeReads() {
+            return false;
+        }
+    } // end of class FlowSensitiveReduction.Tool
+
+    protected final LogicConstantNode trueConstant;
+    protected final LogicConstantNode falseConstant;
+    protected final ConstantNode nullConstant;
+
+    protected final CanonicalizerTool tool;
+    protected final StructuredGraph graph;
+
+    protected EquationalReasoner reasoner;
+
+    protected final PostponedDeopts postponedDeopts = new PostponedDeopts();
+
+    protected BaseReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState);
+        graph = start.graph();
+        trueConstant = LogicConstantNode.tautology(graph);
+        falseConstant = LogicConstantNode.contradiction(graph);
+        nullConstant = ConstantNode.defaultForKind(Kind.Object, graph); // ConstantNode.forObject(null,
+                                                                        // metaAccess, graph);
+        tool = new Tool(context);
+        reasoner = new EquationalReasoner(graph, tool, trueConstant, falseConstant, nullConstant);
+    }
+
+    /**
+     * <p>
+     * Test whether the output's stamp is an upcast of that of the input. For example, upon
+     * replacing a CheckCastNode in
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, com.oracle.graal.nodes.ValueNode)}
+     * we don't want to be left with an upcast, as it loses precision.
+     * </p>
+     *
+     * <p>
+     * As usual with object stamps, they can be compared along different dimensions (alwaysNull,
+     * etc.) It's enough for one such dimension to show precision loss for the end result to be
+     * reported as such.
+     * </p>
+     *
+     */
+    public static boolean precisionLoss(ValueNode input, ValueNode output) {
+        ObjectStamp inputStamp = (ObjectStamp) input.stamp();
+        ObjectStamp outputStamp = (ObjectStamp) output.stamp();
+        if (FlowUtil.isMorePrecise(inputStamp.type(), outputStamp.type())) {
+            return true;
+        }
+        if (lessThan(outputStamp.alwaysNull(), inputStamp.alwaysNull())) {
+            return true;
+        }
+        if (lessThan(outputStamp.nonNull(), inputStamp.nonNull())) {
+            return true;
+        }
+        if (lessThan(outputStamp.isExactType(), inputStamp.isExactType())) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean lessThan(boolean a, boolean b) {
+        return a == false && b == true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.LogicNode;
+import com.oracle.graal.nodes.ShortCircuitOrNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.InstanceOfNode;
+
+/**
+ * @see #extract(com.oracle.graal.nodes.LogicNode)
+ */
+class CastCheckExtractor {
+
+    public final ResolvedJavaType type;
+    public final ValueNode subject;
+
+    CastCheckExtractor(ResolvedJavaType type, ValueNode subject) {
+        this.type = type;
+        this.subject = subject;
+    }
+
+    private static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) {
+        if (x instanceof IsNullNode) {
+            IsNullNode isNull = (IsNullNode) x;
+            ValueNode subject = isNull.object();
+            if (isInstanceOfCheckOn(y, subject)) {
+                InstanceOfNode iOf = (InstanceOfNode) y;
+                return new CastCheckExtractor(iOf.type(), subject);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method detects whether the argument realizes the CheckCast pattern. If so, distills and
+     * returns the essentials of such check, otherwise returns null.
+     */
+    static CastCheckExtractor extract(LogicNode cond) {
+        if (!(cond instanceof ShortCircuitOrNode)) {
+            return null;
+        }
+        ShortCircuitOrNode orNode = (ShortCircuitOrNode) cond;
+        if (orNode.isXNegated() || orNode.isYNegated()) {
+            return null;
+        }
+        CastCheckExtractor result = extractCastCheckInfo(orNode.getX(), orNode.getY());
+        if (result != null) {
+            return result;
+        }
+        result = extractCastCheckInfo(orNode.getY(), orNode.getX());
+        return result;
+    }
+
+    /**
+     * Porcelain method.
+     */
+    static boolean isInstanceOfCheckOn(LogicNode cond, ValueNode subject) {
+        if (!(cond instanceof InstanceOfNode)) {
+            return false;
+        }
+        InstanceOfNode io = (InstanceOfNode) cond;
+        return io.object() == subject;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.java.CheckCastNode}.
+ * </p>
+ *
+ * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+ */
+public abstract class CheckCastReduction extends GuardingPiReduction {
+
+    public CheckCastReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * This phase is able to refine the types of reference-values at use sites provided a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} is available witnessing
+     * that fact.
+     * </p>
+     *
+     * <p>
+     * This method turns non-redundant {@link com.oracle.graal.nodes.java.CheckCastNode}s into
+     * {@link com.oracle.graal.nodes.GuardingPiNode}s. Once such lowering has been performed (during
+     * run N of this phase) follow-up runs attempt to further simplify the resulting node, see
+     * {@link EquationalReasoner#downcastGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode, Witness)}
+     * and {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+     * </p>
+     *
+     * <p>
+     * Precondition: the inputs (ie, object) hasn't been deverbosified yet.
+     * </p>
+     */
+    protected final void visitCheckCastNode(CheckCastNode checkCast) {
+
+        /*
+         * checkCast.object() hasn't been deverbosified yet.
+         */
+
+        if (!FlowUtil.hasLegalObjectStamp(checkCast)) {
+            // This situation is exercised by test Class_cast01
+            return;
+        }
+
+        final ValueNode subject = checkCast.object();
+        final ResolvedJavaType toType = checkCast.type();
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        // --------- checkCast deemed redundant by subject-stamp alone ---------
+        // --------- in particular due to stamp informing always null ----------
+        boolean isRedundantPerStamp = StampTool.isObjectAlwaysNull(subject) || (subjectType != null && toType.isAssignableFrom(subjectType));
+        if (isRedundantPerStamp) {
+            metricCheckCastRemoved.increment();
+            checkCast.replaceAtUsages(subject);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        assert !StampTool.isObjectAlwaysNull(subject) : "Null as per stamp subjects should have been handled above";
+
+        // --------- checkCast deemed unsatisfiable by subject-stamp alone ---------
+        if (state.knownNotToConform(subject, toType)) {
+            postponedDeopts.addDeoptBefore(checkCast, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException);
+            state.impossiblePath();
+            // let FixedGuardNode(false).simplify() prune the dead-code control-path
+            return;
+        }
+
+        /*
+         * Remark: subject may be TypeProxyNode, GuardedValueNode, ProxyNode, GuardingPiNode, among
+         * others.
+         */
+
+        PiNode untrivialNull = reasoner.nonTrivialNull(subject);
+        if (untrivialNull != null) {
+            metricCheckCastRemoved.increment();
+            checkCast.replaceAtUsages(untrivialNull);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        Witness w = state.typeInfo(subject);
+
+        if (w == null) {
+            /*
+             * If there's no witness, attempting `downcast(subject)` is futile.
+             */
+            visitCheckCastNodeLackingWitness(checkCast);
+            return;
+        }
+
+        visitCheckCastNodeWithWitness(checkCast);
+
+    }
+
+    /**
+     * Given that no witness is available for the {@link com.oracle.graal.nodes.java.CheckCastNode}
+     * 's subject there's no point in downcasting such subject, ie no
+     * {@link com.oracle.graal.nodes.PiNode} can be fabricated for the subject.
+     *
+     * @see #lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode,
+     *      com.oracle.graal.nodes.ValueNode)
+     *
+     */
+    private void visitCheckCastNodeLackingWitness(CheckCastNode checkCast) {
+        final ValueNode subject = checkCast.object();
+        final ResolvedJavaType toType = checkCast.type();
+        if (toType.isInterface()) {
+            return;
+        }
+        assert reasoner.downcast(subject) == subject;
+        lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+    }
+
+    /**
+     * Porcelain method.
+     *
+     * <p>
+     * Rather than tracking the CheckCastNode via {@link com.oracle.graal.phases.common.cfs.State
+     * State} (doing so woud add a special case because a
+     * {@link com.oracle.graal.nodes.java.CheckCastNode} isn't a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode}) this method creates an anchor by
+     * lowering the CheckCastNode into a FixedGuardNode. Not the same way as done by
+     * {@link com.oracle.graal.nodes.java.CheckCastNode#lower(com.oracle.graal.nodes.spi.LoweringTool)}
+     * which lowers into a {@link com.oracle.graal.nodes.GuardingPiNode} (which is not a
+     * {@link com.oracle.graal.nodes.extended.GuardingNode}).
+     * </p>
+     *
+     * <p>
+     * With that, state tracking can proceed as usual.
+     * </p>
+     *
+     * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     *
+     */
+    public void lowerCheckCastAnchorFriendlyWay(CheckCastNode checkCast, ValueNode subject) {
+        ValueNode originalCheckCastObject = checkCast.object();
+
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        final ResolvedJavaType toType = checkCast.type();
+        ObjectStamp resultStamp = (ObjectStamp) StampFactory.declared(toType);
+        JavaTypeProfile profile = checkCast.profile();
+
+        assert FlowUtil.isLegalObjectStamp(subjectStamp);
+        assert subjectStamp.type() == null || !toType.isAssignableFrom(subjectStamp.type()) : "No need to lower in an anchor-friendly way in the first place";
+
+        /*
+         * Depending on what is known about the subject:
+         * 
+         * (a) definitely-non-null
+         * 
+         * (b) null-not-seen-in-profiling
+         * 
+         * (c) runtime-null-check-needed
+         * 
+         * the condition (of the cast-guard to be emitted) and the stamp (of the PiNode to be
+         * emitted) are going to be different. Each of the three branches below deals with one of
+         * the cases above.
+         */
+        LogicNode condition;
+        if (subjectStamp.nonNull()) {
+            /*
+             * (1 of 3) definitely-non-null
+             */
+            // addWithoutUnique for the same reason as in CheckCastNode.lower()
+            condition = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+            reasoner.added.add(condition);
+            resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+            // TODO fix in CheckCastNode.lower()
+        } else {
+            if (profile != null && profile.getNullSeen() == ProfilingInfo.TriState.FALSE) {
+                /*
+                 * (2 of 3) null-not-seen-in-profiling
+                 */
+                IsNullNode isNN = graph.unique(new IsNullNode(subject));
+                reasoner.added.add(isNN);
+                FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true));
+                graph.addBeforeFixed(checkCast, nullCheck);
+                // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+                PiNode nonNullGuarded = graph.unique(new PiNode(subject, FlowUtil.asNonNullStamp(subjectStamp), nullCheck));
+                reasoner.added.add(nonNullGuarded);
+                // addWithoutUnique for the same reason as in CheckCastNode.lower()
+                condition = graph.addWithoutUnique(new InstanceOfNode(toType, nonNullGuarded, profile));
+                reasoner.added.add(condition);
+                resultStamp = FlowUtil.asNonNullStamp(resultStamp);
+            } else {
+                /*
+                 * (3 of 3) runtime-null-check-needed
+                 */
+                // addWithoutUnique for the same reason as in CheckCastNode.lower()
+                InstanceOfNode typeTest = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile));
+                reasoner.added.add(typeTest);
+                LogicNode nullTest = graph.unique(new IsNullNode(subject));
+                reasoner.added.add(nullTest);
+                // TODO (ds) replace with probability of null-seen when available
+                final double shortCircuitProbability = NOT_FREQUENT_PROBABILITY;
+                condition = LogicNode.or(nullTest, typeTest, shortCircuitProbability);
+                reasoner.added.add(condition);
+            }
+        }
+
+        /*
+         * Add a cast-guard (checking only what needs to be checked) and a PiNode (to be used in
+         * place of the CheckCastNode).
+         */
+        FixedGuardNode castGuard = graph.add(new FixedGuardNode(condition, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException, InvalidateReprofile));
+        graph.addBeforeFixed(checkCast, castGuard);
+
+        assert FlowUtil.isLegalObjectStamp(resultStamp);
+        Witness w = state.typeInfo(subject);
+        assert !isTypeOfWitnessBetter(w, resultStamp);
+
+        if (!FlowUtil.lacksUsages(checkCast)) {
+            // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+            PiNode checkedObject = graph.unique(new PiNode(subject, resultStamp, castGuard));
+            reasoner.added.add(checkedObject);
+            assert !precisionLoss(originalCheckCastObject, checkedObject);
+            assert !precisionLoss(subject, checkedObject);
+            checkCast.replaceAtUsages(checkedObject);
+        }
+
+        graph.removeFixed(checkCast);
+
+        if (resultStamp.nonNull()) {
+            state.trackIO(subject, toType, castGuard);
+        } else {
+            state.trackCC(subject, toType, castGuard);
+        }
+    }
+
+    /**
+     * Porcelain method.
+     */
+    public static boolean isTypeOfWitnessBetter(Witness w, ObjectStamp stamp) {
+        if (w == null) {
+            return false;
+        }
+        return FlowUtil.isMorePrecise(w.type(), stamp.type());
+    }
+
+    /**
+     *
+     * Please note in this method "subject" refers to the downcasted input to the checkCast.
+     *
+     * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     */
+    private void visitCheckCastNodeWithWitness(CheckCastNode checkCast) {
+
+        final ResolvedJavaType toType = checkCast.type();
+
+        ValueNode subject;
+        if (checkCast.object() instanceof CheckCastNode) {
+            subject = reasoner.downcast(checkCast);
+            if (subject == checkCast) {
+                subject = reasoner.downcast(checkCast.object());
+            }
+        } else {
+            subject = reasoner.downcast(checkCast.object());
+        }
+
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        /*
+         * At this point, two sources of (partial) information: the witness and the stamp of
+         * subject. The latter might be more precise than the witness (eg, subject might be
+         * GuardedValueNode)
+         */
+
+        // --------- checkCast made redundant by downcasting its input ---------
+        if (subjectType != null && toType.isAssignableFrom(subjectType)) {
+            checkCast.replaceAtUsages(subject);
+            graph.removeFixed(checkCast);
+            return;
+        }
+
+        /*
+         * At this point, `downcast()` might or might not have delivered a more precise value. If
+         * more precise, it wasn't precise enough to conform to `toType`. Even so, for the
+         * `toType.isInterface()` case (dealt with below) we'll replace the checkCast's input with
+         * that value (its class-stamp being more precise than the original).
+         */
+
+        if (toType.isInterface()) {
+            boolean wasDowncasted = (subject != checkCast.object());
+            if (wasDowncasted) {
+                FlowUtil.replaceInPlace(checkCast, checkCast.object(), subject);
+            }
+            return;
+        }
+
+        lowerCheckCastAnchorFriendlyWay(checkCast, subject);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,948 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.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 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;
+
+/**
+ * <p>
+ * This class implements a simple partial evaluator that recursively reduces a given
+ * {@link com.oracle.graal.nodes.calc.FloatingNode} into a simpler one based on the current state.
+ * Such evaluator comes handy when visiting a {@link com.oracle.graal.nodes.FixedNode} N, just
+ * before updating the state for N. At the pre-state, an {@link EquationalReasoner} can be used to
+ * reduce N's inputs (actually only those inputs of Value and Condition
+ * {@link com.oracle.graal.graph.InputType InputType}). For an explanation of where it's warranted
+ * to replace "old input" with "reduced input", see the inline comments in method
+ * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node n) deverbosify(Node n)}
+ * </p>
+ *
+ * <p>
+ * The name {@link EquationalReasoner EquationalReasoner} was chosen because it conveys what it
+ * does.
+ * </p>
+ */
+public final class EquationalReasoner {
+
+    private static final DebugMetric metricInstanceOfRemoved = Debug.metric("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 final StructuredGraph graph;
+    private final CanonicalizerTool tool;
+    private final LogicConstantNode trueConstant;
+    private final LogicConstantNode falseConstant;
+    private final ConstantNode nullConstant;
+
+    private State state;
+    private NodeBitMap visited;
+
+    /**
+     * The reduction of a {@link com.oracle.graal.nodes.calc.FloatingNode} performed by
+     * {@link EquationalReasoner EquationalReasoner} may result in a FloatingNode being added to the
+     * graph. Those nodes aren't tracked in the {@link EquationalReasoner#visited visited}
+     * {@link com.oracle.graal.graph.NodeBitMap NodeBitMap} but in this set instead (those nodes are
+     * added after the {@link com.oracle.graal.graph.NodeBitMap} was obtained).
+     */
+    final Set<ValueNode> added = java.util.Collections.newSetFromMap(new IdentityHashMap<ValueNode, Boolean>());
+
+    /**
+     * The reduction of a FloatingNode performed by {@link EquationalReasoner EquationalReasoner}
+     * may result in a FloatingNode being added to the graph. Those nodes are tracked in this map,
+     * to avoid recomputing them.
+     *
+     * The substitutions tracked in this field become invalid as described in
+     * {@link #updateState(com.oracle.graal.phases.common.cfs.State) updateState(State)}
+     */
+    private final IdentityHashMap<ValueNode, ValueNode> substs = new IdentityHashMap<>();
+
+    public EquationalReasoner(StructuredGraph graph, CanonicalizerTool tool, LogicConstantNode trueConstant, LogicConstantNode falseConstant, ConstantNode nullConstant) {
+        this.graph = graph;
+        this.tool = tool;
+        this.trueConstant = trueConstant;
+        this.falseConstant = falseConstant;
+        this.nullConstant = nullConstant;
+    }
+
+    /**
+     * {@link #added} grows during a run of
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase
+     * FlowSensitiveReductionPhase}, and doesn't survive across runs.
+     */
+    public void forceState(State s) {
+        state = s;
+        substs.clear();
+        added.clear();
+        visited = null;
+        versionNrAsofLastForce = s.versionNr;
+    }
+
+    /**
+     * <p>
+     * Gaining more precise type information about an SSA value doesn't "invalidate" as such any of
+     * the substitutions tracked in {@link EquationalReasoner#substs substs}, at least not in the
+     * sense of making the value tracked by one such entry "wrong". However, clearing the
+     * {@link EquationalReasoner#substs substs} is still justified because next time they are
+     * computed, the newly computed reduction could (in principle) be more effective (due to the
+     * more precise type information).
+     * </p>
+     *
+     * <p>
+     * Between clearings of cached substitutions, it is expected they get applied a number of times
+     * to justify the bookkeeping cost.
+     * </p>
+     *
+     */
+    public void updateState(State s) {
+        assert s != null;
+        if (state == null || state != s || state.versionNr != versionNrAsofLastForce) {
+            forceState(s);
+        }
+    }
+
+    private int versionNrAsofLastForce = 0;
+
+    /**
+     * Reduce the argument based on the state at the program point where the argument is consumed.
+     * For most FixedNodes, that's how their inputs can be reduced. Two exceptions:
+     * <ul>
+     * <li>
+     * the condition of a {@link com.oracle.graal.nodes.GuardingPiNode}, see
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+     * </li>
+     * <li>
+     * the condition of a {@link com.oracle.graal.nodes.FixedGuardNode}, see
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)}
+     * </li>
+     *
+     * </ul>
+     *
+     *
+     * <p>
+     * Part of the reduction work is delegated to baseCase-style reducers, whose contract explicitly
+     * requires them not to deverbosify the argument's inputs --- the decision is made based on the
+     * argument only (thus "base case"). Returning the unmodified argument is how a baseCase-style
+     * tells this method to fall to the default case (for a floating node only: walk into the
+     * argument's inputs, canonicalize followed by
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+     * rememberSubstitution()} if any input changed).
+     * </p>
+     *
+     * <p>
+     * This method must behave as a function (idempotent query method), ie refrain from mutating the
+     * state other than updating caches:
+     * <ul>
+     * <li>{@link EquationalReasoner#added EquationalReasoner#added},</li>
+     * <li>{@link EquationalReasoner#visited EquationalReasoner#visited} and</li>
+     * <li>the cache updated via
+     * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)
+     * EquationalReasoner#rememberSubstitution(ValueNode, FloatingNode)}.</li>
+     * </ul>
+     * </p>
+     *
+     * <p>
+     * In turn, baseCase-style reducers are even more constrained: besides behaving as functions,
+     * their contract prevents them from updating any caches (basically because they already grab
+     * the answer from caches, if the answer isn't there they should just return their unmodified
+     * argument).
+     * </p>
+     *
+     * <p>
+     * This method returns:
+     * <ul>
+     * <li>
+     * the original argument, in case no reduction possible.</li>
+     * <li>
+     * a {@link com.oracle.graal.nodes.ValueNode ValueNode} different from the argument, in case the
+     * conditions for a reduction were met. The node being returned might be already in the graph.
+     * In any case it's canonicalized already, the caller need not perform that again.</li>
+     * <li>
+     * the unmodified argument, in case no reduction was made. Otherwise, a maximally reduced
+     * {@link com.oracle.graal.nodes.ValueNode}.</li>
+     * </ul>
+     * </p>
+     *
+     * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)
+     *
+     * @see com.oracle.graal.phases.common.cfs.BaseReduction.Tool
+     *
+     */
+    public Node deverbosify(final Node n) {
+
+        // --------------------------------------------------------------------
+        // cases that don't initiate any call-chain that may enter this method
+        // --------------------------------------------------------------------
+
+        if (n == null) {
+            return null;
+        }
+        assert !(n instanceof GuardNode) : "This phase not yet ready to run during MidTier";
+        if (!(n instanceof ValueNode)) {
+            return n;
+        }
+        ValueNode v = (ValueNode) n;
+        if (v.stamp() instanceof IllegalStamp) {
+            return v;
+        }
+        if (FlowUtil.isLiteralNode(v)) {
+            return v;
+        }
+        ValueNode result = substs.get(v);
+        if (result != null) {
+            // picked cached substitution
+            return result;
+        }
+        if ((visited != null && visited.contains(n)) || added.contains(v)) {
+            return v;
+        }
+
+        // --------------------------------------------------------------------
+        // stack overflow prevention via added, visited
+        // --------------------------------------------------------------------
+
+        if (visited == null) {
+            visited = graph.createNodeBitMap();
+        }
+        visited.mark(n);
+
+        /*
+         * Past this point, if we ever want `n` to be deverbosified, it must be looked-up by one of
+         * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)`
+         */
+        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;
+    }
+
+    /**
+     * This method:
+     *
+     * <ul>
+     * <li>
+     * Recurses only over floating inputs to attempt reductions, leave anything else as is.</li>
+     * <li>
+     * Performs copy-on-write aka lazy-DAG-copying as described in source comments, in-line.</li>
+     * <li>
+     * Usage: must be called only from {@link #deverbosify(com.oracle.graal.graph.Node)
+     * deverbosify(Node)}.</li>
+     * </ul>
+     */
+    public Node deverbosifyFloatingNode(final FloatingNode n) {
+
+        assert n != null : "Should have been caught in deverbosify()";
+        assert !(n instanceof ValueProxy) : "Should have been caught in deverbosify()";
+        assert !FlowUtil.isLiteralNode(n) : "Should have been caught in deverbosify()";
+
+        if (n instanceof PhiNode) {
+            /*
+             * Each input to a PhiNode should be deverbosified with the state applicable to the path
+             * providing such input, as done in visitAbstractEndNode()
+             */
+            return n;
+        }
+
+        final FloatingNode f = baseCaseFloating(n);
+        if (f != n) {
+            return f;
+        }
+
+        FloatingNode changed = null;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(f)) {
+            /*
+             * Although deverbosify() is invoked below, it's only for floating inputs. That way, the
+             * state can't be used to make invalid conclusions.
+             */
+            Node j = (i instanceof FloatingNode) ? deverbosify(i) : i;
+            if (i != j) {
+                assert j != f;
+                if (changed == null) {
+                    changed = (FloatingNode) f.copyWithInputs();
+                    added.add(changed);
+                    // copyWithInputs() implies graph.unique(changed)
+                    assert changed.isAlive();
+                    assert FlowUtil.lacksUsages(changed);
+                }
+                /*
+                 * Note: we don't trade i for j at each usage of i (doing so would change meaning)
+                 * but only at those usages consumed by `changed`. In turn, `changed` won't replace
+                 * `n` at arbitrary usages, but only where such substitution is valid as per the
+                 * state holding there. In practice, this means the buck stops at the "root"
+                 * FixedNode on whose inputs deverbosify() is invoked for the first time, via
+                 * deverbosifyInputsInPlace().
+                 */
+                FlowUtil.replaceInPlace(changed, i, j);
+            }
+        }
+        if (changed == null) {
+            assert visited.contains(f) || added.contains(f);
+            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;
+            }
+        }
+        FlowUtil.inferStampAndCheck(changed);
+        added.add(changed);
+        ValueNode canon = (ValueNode) changed.canonical(tool);
+        // might be already in `added`, no problem adding it again.
+        added.add(canon);
+        rememberSubstitution(f, canon);
+        return canon;
+    }
+
+    /**
+     * In case of doubt (on whether a reduction actually triggered) it's always ok to invoke "
+     * <code>rememberSubstitution(f, downcast(f))</code>": this method records a map entry only if
+     * pre-image and image differ.
+     *
+     * @return the image of the substitution (ie, the second argument) unmodified.
+     */
+    private <M extends ValueNode> M rememberSubstitution(ValueNode from, M to) {
+        assert from != null && to != null;
+        if (from == to) {
+            return to;
+        }
+        // we don't track literals because they map to themselves
+        if (FlowUtil.isLiteralNode(from)) {
+            assert from == to;
+            return to;
+        }
+        /*
+         * It's ok for different keys (which were not unique in the graph after all) to map to the
+         * same value. However any given key can't map to different values.
+         */
+        ValueNode image = substs.get(from);
+        if (image != null) {
+            assert image == to;
+            return to;
+        }
+        substs.put(from, to);
+        return to;
+    }
+
+    /**
+     * The contract for this baseCase-style method is covered in
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()}
+     *
+     * @return a {@link com.oracle.graal.nodes.calc.FloatingNode} different from the argument, in
+     *         case a reduction was made. The node being returned might be already in the graph. In
+     *         any case it's canonicalized already, the caller need not perform that again. In case
+     *         no reduction was made, this method returns the unmodified argument.
+     */
+    private FloatingNode baseCaseFloating(final FloatingNode f) {
+        if (f instanceof LogicNode) {
+            FloatingNode result = baseCaseLogicNode((LogicNode) f);
+            return rememberSubstitution(f, result);
+        }
+        return f;
+    }
+
+    /**
+     * <p>
+     * Reduce the argument based on the state at the program point for it (ie, based on
+     * "valid facts" only, without relying on any floating-guard-assumption).
+     * </p>
+     *
+     * <p>
+     * The inputs of the argument aren't traversed into, for that
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()} should be used instead.
+     * </p>
+     * <p>
+     * This method must behave as a function (idempotent query method): it should refrain from
+     * changing the state, as well as from updating caches (other than DebugMetric-s).
+     * </p>
+     *
+     * @return a {@link com.oracle.graal.nodes.LogicNode} different from the argument, in case a
+     *         reduction was made. The node being returned might be already in the graph. In any
+     *         case it's canonicalized already, the caller need not perform that again. In case no
+     *         reduction was made, this method returns the unmodified argument.
+     *
+     */
+    public FloatingNode baseCaseLogicNode(LogicNode condition) {
+        assert condition != null;
+        if (condition instanceof LogicConstantNode) {
+            return condition;
+        } else if (state.trueFacts.containsKey(condition)) {
+            metricEquationalReasoning.increment();
+            return trueConstant;
+        } else if (state.falseFacts.containsKey(condition)) {
+            metricEquationalReasoning.increment();
+            return falseConstant;
+        } else {
+            if (condition instanceof InstanceOfNode) {
+                return baseCaseInstanceOfNode((InstanceOfNode) condition);
+            } else if (condition instanceof IsNullNode) {
+                return baseCaseIsNullNode((IsNullNode) condition);
+            } else if (condition instanceof ObjectEqualsNode) {
+                return baseCaseObjectEqualsNode((ObjectEqualsNode) condition);
+            }
+        }
+        return condition;
+    }
+
+    /**
+     * Actually the same result delivered by this method could be obtained by just letting
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify()} handle the argument in the default case for floating nodes
+     * (ie, deverbosify inputs followed by canonicalize). However it's done here for metrics
+     * purposes.
+     *
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+     *         otherwise the unmodified argument.
+     *
+     */
+    private LogicNode baseCaseInstanceOfNode(InstanceOfNode instanceOf) {
+        ValueNode scrutinee = GraphUtil.unproxify(instanceOf.object());
+        if (!FlowUtil.hasLegalObjectStamp(scrutinee)) {
+            return instanceOf;
+        }
+        if (state.isNull(scrutinee)) {
+            metricInstanceOfRemoved.increment();
+            return falseConstant;
+        } else if (state.isNonNull(scrutinee) && state.knownToConform(scrutinee, instanceOf.type())) {
+            metricInstanceOfRemoved.increment();
+            return trueConstant;
+        }
+        return instanceOf;
+    }
+
+    /**
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was
+     *         performed; otherwise the unmodified argument.
+     *
+     */
+    private FloatingNode baseCaseIsNullNode(IsNullNode isNull) {
+        ValueNode object = isNull.object();
+        if (!FlowUtil.hasLegalObjectStamp(object)) {
+            return isNull;
+        }
+        ValueNode scrutinee = GraphUtil.unproxify(isNull.object());
+        GuardingNode evidence = nonTrivialNullAnchor(scrutinee);
+        if (evidence != null) {
+            metricNullCheckRemoved.increment();
+            return trueConstant;
+        } else if (state.isNonNull(scrutinee)) {
+            metricNullCheckRemoved.increment();
+            return falseConstant;
+        }
+        return isNull;
+    }
+
+    /**
+     * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made;
+     *         otherwise the unmodified argument.
+     */
+    private LogicNode baseCaseObjectEqualsNode(ObjectEqualsNode equals) {
+        if (!FlowUtil.hasLegalObjectStamp(equals.x()) || !FlowUtil.hasLegalObjectStamp(equals.y())) {
+            return equals;
+        }
+        ValueNode x = GraphUtil.unproxify(equals.x());
+        ValueNode y = GraphUtil.unproxify(equals.y());
+        if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) {
+            metricObjectEqualsRemoved.increment();
+            return falseConstant;
+        } else if (state.isNull(x) && state.isNull(y)) {
+            metricObjectEqualsRemoved.increment();
+            return trueConstant;
+        }
+        return equals;
+    }
+
+    /**
+     * It's always ok to use "<code>downcast(object)</code>" instead of " <code>object</code>"
+     * because this method re-wraps the argument in a {@link com.oracle.graal.nodes.PiNode} only if
+     * the new stamp is strictly more refined than the original.
+     *
+     * <p>
+     * This method does not
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * .
+     * </p>
+     *
+     * @return One of:
+     *         <ul>
+     *         <li>a {@link com.oracle.graal.nodes.PiNode} with more precise stamp than the input if
+     *         the state warrants such downcasting</li>
+     *         <li>a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} for the same
+     *         scrutinee in question</li>
+     *         <li>the unmodified argument otherwise.</li>
+     *         </ul>
+     */
+    ValueNode downcast(final ValueNode object) {
+
+        // -------------------------------------------------
+        // actions based only on the stamp of the input node
+        // -------------------------------------------------
+
+        if (!FlowUtil.hasLegalObjectStamp(object)) {
+            return object;
+        }
+        if (FlowUtil.isLiteralNode(object)) {
+            return object;
+        }
+        if (StampTool.isObjectAlwaysNull(object.stamp())) {
+            return object;
+        }
+
+        // ------------------------------------------
+        // actions based on the stamp and the witness
+        // ------------------------------------------
+
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+
+        PiNode untrivialNull = nonTrivialNull(scrutinee);
+        if (untrivialNull != null) {
+            return untrivialNull;
+        }
+
+        Witness w = state.typeInfo(scrutinee);
+        if (w == null) {
+            // no additional hints being tracked for the scrutinee
+            return object;
+        }
+
+        assert !w.clueless();
+
+        ObjectStamp inputStamp = (ObjectStamp) object.stamp();
+        ObjectStamp witnessStamp = w.asStamp();
+        if (inputStamp.equals(witnessStamp) || !FlowUtil.isMorePrecise(witnessStamp, inputStamp)) {
+            // the witness offers no additional precision over current one
+            fixupTypeProfileStamp(object);
+            return object;
+        }
+
+        assert !FlowUtil.isMorePrecise(inputStamp.type(), w.type());
+
+        ValueNode result;
+        if (object instanceof ValueProxy) {
+            result = downcastValueProxy((ValueProxy) object, w);
+        } else {
+            result = downcastedUtil(object, w);
+        }
+
+        assert !BaseReduction.precisionLoss(object, result);
+
+        return result;
+    }
+
+    /**
+     * TODO TypeProfileProxyNode.inferStamp doesn't infer non-null from non-null payload
+     *
+     * <p>
+     * And there's a bunch of asserts in
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} that assert no
+     * type-precision gets lost. Thus the need to fix-up on our own, as done here.
+     * </p>
+     */
+    private static void fixupTypeProfileStamp(ValueNode object) {
+        if (!(object instanceof TypeProfileProxyNode)) {
+            return;
+        }
+        TypeProfileProxyNode profile = (TypeProfileProxyNode) object;
+        ObjectStamp outgoinStamp = (ObjectStamp) profile.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) profile.getObject().stamp();
+        if (payloadStamp.nonNull() && !outgoinStamp.nonNull()) {
+            profile.setStamp(FlowUtil.asNonNullStamp(outgoinStamp));
+        }
+    }
+
+    /**
+     * <p>
+     * Porcelain method.
+     * </p>
+     *
+     * <p>
+     * Utility to create, add to the graph,
+     * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * , and return a {@link com.oracle.graal.nodes.PiNode} that narrows into the given stamp,
+     * anchoring the payload.
+     * </p>
+     *
+     * <p>
+     * The resulting node might not have been in the graph already.
+     * </p>
+     */
+    private PiNode wrapInPiNode(ValueNode payload, GuardingNode anchor, ObjectStamp newStamp, boolean remember) {
+        try (Debug.Scope s = Debug.scope("Downcast", payload)) {
+            assert payload != anchor : payload.graph().toString();
+            metricDowncasting.increment();
+            PiNode result = graph.unique(new PiNode(payload, newStamp, anchor.asNode()));
+            // we've possibly got a new node in the graph --- bookkeeping is in order.
+            added.add(result);
+            if (remember) {
+                rememberSubstitution(payload, result);
+            }
+            Debug.log("Downcasting from %s to %s", payload, result);
+            return result;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    /**
+     * <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>
+     * <li><b>null</b>, if the argument is known null due to its stamp. Otherwise,</li>
+     * <li><b>a PiNode</b> wrapping the null constant and an anchor offering evidence as to why the
+     * argument is known null, if such anchor is available. Otherwise,</li>
+     * <li><b>null</b></li>
+     * </ul>
+     * <p>
+     * This method does not
+     * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)}
+     * .
+     * </p>
+     */
+    public PiNode nonTrivialNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        GuardingNode anchor = nonTrivialNullAnchor(object);
+        if (anchor == null) {
+            return null;
+        }
+        if (object instanceof GuardedNode && StampTool.isObjectAlwaysNull(object.stamp())) {
+            return (PiNode) object;
+        }
+        // notice nullConstant is wrapped, not object
+        PiNode result = wrapInPiNode(nullConstant, anchor, (ObjectStamp) StampFactory.alwaysNull(), false);
+        return result;
+    }
+
+    // @formatter:off
+    /**
+     * <p>ValueProxys can be classified along two dimensions,
+     * in addition to the fixed-floating dichotomy.</p>
+     *
+     * <p>
+     *     First, we might be interested in separating those ValueProxys
+     *     that are entitled to change (usually narrow) their stamp from those that aren't.
+     *     In the first category are:
+     *       PiNode, PiArrayNode, GuardingPiNode,
+     *       CheckCastNode, UnsafeCastNode, and
+     *       GuardedValueNode.
+     * </p>
+     *
+     * <p>
+     *     A note on stamp-narrowing ValueProxys:
+     *     our state abstraction tracks only the type refinements induced by CheckCastNode and GuardingPiNode
+     *     (which are fixed nodes, unlike the other stamp-narrowing ValueProxys;
+     *     the reason being that the state abstraction can be updated only at fixed nodes).
+     *     As a result, the witness for a (PiNode, PiArrayNode, UnsafeCastNode, or GuardedValueNode)
+     *     may be less precise than the proxy's stamp. We don't want to lose such precision,
+     *     thus <code>downcast(proxy) == proxy</code> in such cases.
+     * </p>
+     *
+     * <p>
+     *     The second classification focuses on
+     *     the additional information that travels with the proxy
+     *     (in addition to its "payload", ie getOriginalValue(), and any narrowing-stamp).
+     *     Such additional information boils down to:
+     *
+     *   (a) type profile (TypeProfileProxyNode)
+     *   (b) type profile (CheckCastNode)
+     *   (c) anchor (GuardedValueNode)
+     *   (d) anchor (PiNode)
+     *   (e) anchor and array length (PiArrayNode)
+     *   (f) optional anchor (UnsafeCastNode)
+     *   (g) deopt-condition (GuardingPiNode)
+     *   (h) LocationIdentity (MemoryProxyNOde)
+     *   (i) control-flow dependency (FixedValueAnchorNode)
+     *   (j) proxyPoint (ProxyNode -- think loops)
+     *</p>
+     */
+    // @formatter:on
+    private ValueNode downcastValueProxy(ValueProxy proxy, Witness w) {
+        assert FlowUtil.hasLegalObjectStamp((ValueNode) proxy);
+        assert FlowUtil.hasLegalObjectStamp((proxy).getOriginalNode());
+        assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify(proxy.getOriginalNode());
+
+        assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify((proxy).getOriginalNode());
+
+        if (proxy instanceof PiNode) {
+            return downcastPiNodeOrPiArrayNode((PiNode) proxy, w);
+        } else if (proxy instanceof GuardingPiNode) {
+            return downcastGuardingPiNode((GuardingPiNode) proxy, w);
+        } else if (proxy instanceof TypeProfileProxyNode) {
+            return downcastTypeProfileProxyNode((TypeProfileProxyNode) proxy);
+        } else if (proxy instanceof CheckCastNode) {
+            return downcastCheckCastNode((CheckCastNode) proxy, w);
+        } else if (proxy instanceof ProxyNode || proxy instanceof GuardedValueNode) {
+            // TODO scaladacapo return downcastedUtil((ValueNode) proxy, w);
+            return (ValueNode) proxy;
+        }
+
+        assert false : "TODO case not yet handled";
+
+        // TODO complete the missing implementation for the cases not yet handled
+
+        return ((ValueNode) proxy);
+    }
+
+    /**
+     * <p>
+     * Why would we want to downcast a GuardingPiNode? Is it even possible? Like, for example, a
+     * GuardingPiNode originating in the lowering of a CheckCastNode (carried out by
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     * visitCheckCastNode()}).
+     * </p>
+     *
+     * <p>
+     * It's both possible and desirable. Example: <code>
+     *         Number n = (Number) o;
+     *         if (n instanceof Integer) {
+     *            return n.intValue();
+     *         }
+     *     </code>
+     *
+     * The receiver of intValue() is a usage of a previous checkCast, for which the current witness
+     * provides a more refined type (and an anchor). In this case, the advantage of downcasting a
+     * GuardingPiNode is clear: devirtualizing the `intValue()` callsite.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    public ValueNode downcastGuardingPiNode(GuardingPiNode envelope, Witness w) {
+        assert envelope != w.guard().asNode() : "The stamp of " + envelope + " would lead to downcasting with that very same GuardingPiNode as guard.";
+        return downcastedUtil(envelope, w);
+    }
+
+    /**
+     * <p>
+     * This method accepts both {@link com.oracle.graal.nodes.PiNode} and
+     * {@link com.oracle.graal.nodes.PiArrayNode} argument.
+     * </p>
+     *
+     * <p>
+     * In case a witness reveals a strictly more precise type than the
+     * {@link com.oracle.graal.nodes.PiNode}'s stamp, this method wraps the argument in a new
+     * {@link com.oracle.graal.nodes.PiNode} with updated stamp, and returns it.
+     * </p>
+     *
+     * <p>
+     * A {@link com.oracle.graal.nodes.PiArrayNode} argument ends up wrapped in a
+     * {@link com.oracle.graal.nodes.PiNode}. Thus, the
+     * {@link com.oracle.graal.nodes.PiArrayNode#length} information doesn't get lost.
+     * </p>
+     *
+     * <p>
+     * Note: {@link com.oracle.graal.nodes.PiNode}'s semantics allow un-packing its payload as soon
+     * as it type conforms to that of the {@link com.oracle.graal.nodes.PiNode} (that's what
+     * {@link com.oracle.graal.nodes.PiNode#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)
+     * PiNode.canonical()} does). Not clear the benefits of duplicating that logic here.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastPiNodeOrPiArrayNode(PiNode envelope, Witness w) {
+        return downcastedUtil(envelope, w);
+    }
+
+    /**
+     * <p>
+     * In a case the payload of the {@link com.oracle.graal.nodes.TypeProfileProxyNode} can be
+     * downcasted, this method returns a copy-on-write version with the downcasted payload.
+     * </p>
+     *
+     * <p>
+     * Otherwise returns the unmodified argument.
+     * </p>
+     *
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastTypeProfileProxyNode(TypeProfileProxyNode envelope) {
+        ValueNode payload = envelope.getOriginalNode();
+        ValueNode d = downcast(payload);
+        if (payload != d) {
+            TypeProfileProxyNode changed = (TypeProfileProxyNode) envelope.copyWithInputs();
+            added.add(changed);
+            // copyWithInputs() implies graph.unique(changed)
+            FlowUtil.replaceInPlace(changed, payload, d);
+            FlowUtil.inferStampAndCheck(changed);
+            fixupTypeProfileStamp(changed);
+            /*
+             * It's not prudent to (1) obtain the canonical() of the (changed) TypeProfileProxyNode
+             * to (2) replace its usages; because we're potentially walking a DAG (after all,
+             * TypeProfileProxyNode is a floating-node). Those steps, which admittedly are needed,
+             * are better performed upon replacing in-place the inputs of a FixedNode, or during
+             * Canonicalize.
+             */
+            return changed;
+        }
+        fixupTypeProfileStamp(envelope);
+        return envelope;
+    }
+
+    /**
+     * <p>
+     * Re-wrap the checkCast in a type-refining {@link com.oracle.graal.nodes.PiNode PiNode} only if
+     * the downcasted scrutinee does not conform to the checkCast's target-type.
+     * </p>
+     */
+    private ValueNode downcastCheckCastNode(CheckCastNode checkCast, Witness w) {
+
+        final ResolvedJavaType toType = checkCast.type();
+
+        if (checkCast.object() instanceof CheckCastNode) {
+            ValueNode innerMost = checkCast;
+            while (innerMost instanceof CheckCastNode) {
+                innerMost = ((CheckCastNode) innerMost).object();
+            }
+            ValueNode deepest = downcast(innerMost);
+            ResolvedJavaType deepestType = ((ObjectStamp) deepest.stamp()).type();
+            if ((deepestType != null && deepestType.equals(toType)) || FlowUtil.isMorePrecise(deepestType, toType)) {
+                assert !w.knowsBetterThan(deepest);
+                return deepest;
+            }
+        }
+
+        ValueNode subject = downcast(checkCast.object());
+        ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
+        ResolvedJavaType subjectType = subjectStamp.type();
+
+        if (subjectType != null && toType.isAssignableFrom(subjectType)) {
+            assert !w.knowsBetterThan(subject);
+            return subject;
+        }
+
+        return downcastedUtil(checkCast, w);
+    }
+
+    /**
+     * <p>
+     * Porcelain method.
+     * </p>
+     *
+     * <p>
+     * This method wraps the argument in a new {@link com.oracle.graal.nodes.PiNode PiNode} (created
+     * to hold an updated stamp) provided the argument's stamp can be strictly refined, and returns
+     * it.
+     * </p>
+     */
+    private ValueNode downcastedUtil(ValueNode subject, Witness w) {
+
+        ObjectStamp originalStamp = (ObjectStamp) subject.stamp();
+        ObjectStamp outgoingStamp = originalStamp;
+
+        if (w.isNonNull() && !outgoingStamp.nonNull()) {
+            outgoingStamp = FlowUtil.asNonNullStamp(outgoingStamp);
+        }
+        if (FlowUtil.isMorePrecise(w.type(), outgoingStamp.type())) {
+            outgoingStamp = FlowUtil.asRefinedStamp(outgoingStamp, w.type());
+        }
+
+        if (outgoingStamp != originalStamp) {
+            assert FlowUtil.isMorePrecise(outgoingStamp, originalStamp);
+
+            boolean isWitnessGuardAnAliasForScrutinee = false;
+            if (w.guard() instanceof GuardingPiNode || w.guard() instanceof PiNode) {
+                /*
+                 * The guard offered by the witness canonicalizes into its subject (a possibly
+                 * type-refined scrutinee) provided its subject conforms as per stamp.
+                 */
+                if (w.guard().asNode().stamp().equals(outgoingStamp)) {
+                    isWitnessGuardAnAliasForScrutinee = true;
+                }
+            }
+
+            ValueNode result;
+            if (isWitnessGuardAnAliasForScrutinee) {
+                result = w.guard().asNode();
+                assert !w.knowsBetterThan(result);
+                return result; // TODO this works. explain why.
+            } else {
+                result = wrapInPiNode(subject, w.guard(), outgoingStamp, true);
+                assert !w.knowsBetterThan(result);
+                return result;
+            }
+
+        } else {
+            assert !w.knowsBetterThan(subject);
+            return subject;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.FixedGuardNode}.
+ * </p>
+ * 
+ * @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)
+ */
+public abstract class FixedGuardReduction extends CheckCastReduction {
+
+    public FixedGuardReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * In case the condition is constant,
+     * {@link com.oracle.graal.nodes.FixedGuardNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)
+     * FixedGuardNode#simplify(SimplifierTool)} will eventually remove the
+     * {@link com.oracle.graal.nodes.FixedGuardNode} ("always succeeds") or kill the code that
+     * should be killed ("always fails").
+     * 
+     * <p>
+     * The only thing we do here is tracking as true fact (from this program point onwards) the
+     * condition of the {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}.
+     * </p>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     */
+    protected final void visitFixedGuardNode(FixedGuardNode f) {
+
+        /*
+         * A FixedGuardNode with LogicConstantNode condition is left untouched.
+         */
+
+        if (f.condition() instanceof LogicConstantNode) {
+            if (FlowUtil.alwaysFails(f.isNegated(), f.condition())) {
+                state.impossiblePath();
+                // let FixedGuardNode(false).simplify() prune the dead-code control-path
+                return;
+            }
+            assert FlowUtil.alwaysSucceeds(f.isNegated(), f.condition());
+            return;
+        }
+
+        /*
+         * Attempt to eliminate the current FixedGuardNode by using another GuardingNode already in
+         * scope and with equivalent 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);
+            return;
+        }
+
+        final LogicNode cond = f.condition();
+        final boolean isTrue = !f.isNegated();
+
+        /*
+         * FixedGuardNode requires handling similar to that of GuardingPiNode, (ie the condition
+         * can't simply be deverbosified in place). A replacement anchor is needed, ie an anchor
+         * that amounts to the same combination of (negated, condition) for the FixedGuardNode at
+         * hand.
+         */
+
+        // 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
+        }
+
+        state.addFact(isTrue, cond, f);
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private void markFixedGuardNodeAlwaysFails(FixedGuardNode f) {
+        metricFixedGuardNodeRemoved.increment();
+        state.impossiblePath();
+        f.setCondition(f.isNegated() ? trueConstant : falseConstant);
+        // `f.condition()` if unused will be removed in finished()
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * <p>
+     * The `replacement` guard must be such that it implies the `old` guard.
+     * </p>
+     */
+    private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) {
+        if (replacement == null) {
+            return;
+        }
+        metricFixedGuardNodeRemoved.increment();
+        old.replaceAtUsages(replacement.asNode());
+        graph.removeFixed(old);
+        // `old.condition()` if unused will be removed in finished()
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.LoadHubNode;
+import com.oracle.graal.nodes.extended.NullCheckNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.IllegalStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import java.lang.reflect.Modifier;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+
+/**
+ * <p>
+ * All control-flow-sensitive reductions follow the common pattern of
+ * <ul>
+ * <li>Recognizing properties of interest (ie, LogicNode-s) at control-flow splits, as well as upon
+ * check-casts and fixed-guards.</li>
+ * <li>Using the information thus tracked to simplify
+ * <ul>
+ * <li>side-effects free expressions, via
+ * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+ * </li>
+ * <li>control-flow, eg. by eliminating redundant fixed-guards and check-casts, ie which are known
+ * always to hold.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @see com.oracle.graal.phases.common.cfs.CheckCastReduction
+ * @see com.oracle.graal.phases.common.cfs.GuardingPiReduction
+ * @see com.oracle.graal.phases.common.cfs.FixedGuardReduction
+ *
+ */
+public class FlowSensitiveReduction extends FixedGuardReduction {
+
+    public FlowSensitiveReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * This method performs two kinds of cleanup:
+     * <ol>
+     * <li>
+     * marking as unreachable certain code-paths, as described in
+     * {@link com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt}</li>
+     * <li>
+     * Removing nodes not in use that were added during this phase, as described next.</li>
+     * </ol>
+     * </p>
+     *
+     *
+     * <p>
+     * Methods like
+     * {@link com.oracle.graal.phases.common.cfs.FlowUtil#replaceInPlace(com.oracle.graal.graph.Node, com.oracle.graal.graph.Node, com.oracle.graal.graph.Node)}
+     * may result in old inputs becoming disconnected from the graph. It's not advisable to
+     * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} at
+     * that moment, because one of the inputs that might get killed is one of {@link #nullConstant},
+     * {@link #falseConstant}, or {@link #trueConstant}; which thus could get killed too early,
+     * before another invocation of
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
+     * needs them. To recap,
+     * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} also
+     * recursively visits the inputs of the its argument.
+     * </p>
+     *
+     * <p>
+     * This method goes over all of the nodes that deverbosification might have added, which are
+     * either:
+     * <ul>
+     * <li>
+     * {@link com.oracle.graal.nodes.calc.FloatingNode}, added by
+     * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosifyFloatingNode(com.oracle.graal.nodes.calc.FloatingNode)}
+     * ; or</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode}, added by
+     * {@link #deverbosifyInputsCopyOnWrite(com.oracle.graal.nodes.java.MethodCallTargetNode)}</li>
+     * </ul>
+     *
+     * Checking if they aren't in use, proceeding to remove them in that case.
+     * </p>
+     *
+     */
+    @Override
+    public void finished() {
+        if (!postponedDeopts.isEmpty()) {
+            for (PostponedDeopt postponed : postponedDeopts) {
+                postponed.doRewrite(falseConstant);
+            }
+            new DeadCodeEliminationPhase().apply(graph);
+        }
+        for (MethodCallTargetNode mcn : graph.getNodes().filter(MethodCallTargetNode.class)) {
+            if (mcn.isAlive() && FlowUtil.lacksUsages(mcn)) {
+                mcn.safeDelete();
+            }
+        }
+        for (Node n : graph.getNodes().filter(FloatingNode.class)) {
+            GraphUtil.tryKillUnused(n);
+        }
+        assert !isAliveWithoutUsages(trueConstant);
+        assert !isAliveWithoutUsages(falseConstant);
+        assert !isAliveWithoutUsages(nullConstant);
+    }
+
+    private static boolean isAliveWithoutUsages(FloatingNode node) {
+        return node.isAlive() && FlowUtil.lacksUsages(node);
+    }
+
+    private void registerControlSplit(Node pred, BeginNode begin) {
+        assert pred != null && begin != null;
+        assert !state.isUnreachable;
+
+        if (begin instanceof LoopExitNode) {
+            state.clear();
+        }
+
+        if (pred instanceof IfNode) {
+            registerIfNode((IfNode) pred, begin);
+        } else if (pred instanceof TypeSwitchNode) {
+            registerTypeSwitchNode((TypeSwitchNode) pred, begin);
+        }
+    }
+
+    private void registerIfNode(IfNode ifNode, BeginNode begin) {
+        final boolean isThenBranch = (begin == ifNode.trueSuccessor());
+
+        if (ifNode.condition() instanceof LogicConstantNode) {
+            final LogicConstantNode constCond = (LogicConstantNode) ifNode.condition();
+            if (isThenBranch != constCond.getValue()) {
+                state.impossiblePath();
+                // let IfNode(constant) prune the dead-code control-path
+            }
+        }
+
+        if (state.isUnreachable) {
+            if (!(ifNode.condition() instanceof LogicConstantNode)) {
+                // if condition constant, no need to add a Deopt node
+                postponedDeopts.addDeoptAfter(begin, UnreachedCode);
+            }
+        } else {
+            state.addFact(isThenBranch, ifNode.condition(), begin);
+        }
+    }
+
+    /**
+     * TODO When tracking integer-stamps, the state at each successor of a TypeSwitchNode should
+     * track an integer-stamp for the LoadHubNode (meet over the constants leading to that
+     * successor). However, are LoadHubNode-s shared frequently enough?
+     */
+    private void registerTypeSwitchNode(TypeSwitchNode typeSwitch, BeginNode begin) {
+        if (typeSwitch.value() instanceof LoadHubNode) {
+            LoadHubNode loadHub = (LoadHubNode) typeSwitch.value();
+            ResolvedJavaType type = null;
+            for (int i = 0; i < typeSwitch.keyCount(); i++) {
+                if (typeSwitch.keySuccessor(i) == begin) {
+                    if (type == null) {
+                        type = typeSwitch.typeAt(i);
+                    } else {
+                        type = FlowUtil.widen(type, typeSwitch.typeAt(i));
+                    }
+                }
+            }
+            if (type == null) {
+                // `begin` denotes the default case of the TypeSwitchNode
+                return;
+            }
+            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);
+        }
+    }
+
+    /**
+     *
+     * <p>
+     * Reduce input nodes based on the state at the program point for the argument (ie, based on
+     * "valid facts" only, without relying on any floating-guard-assumption).
+     * </p>
+     *
+     * <p>
+     * For each (direct or indirect) child, a copy-on-write version is made in case any of its
+     * children changed, with the copy accommodating the updated children. If the parent was shared,
+     * copy-on-write prevents the updates from becoming visible to anyone but the invoker of this
+     * method.
+     * </p>
+     *
+     * <p>
+     * <b> Please note the parent node is mutated upon any descendant changing. No copy-on-write is
+     * performed for the parent node itself. </b>
+     * </p>
+     *
+     * <p>
+     * In more detail, for each direct {@link com.oracle.graal.nodes.ValueNode} input of the node at
+     * hand,
+     *
+     * <ol>
+     * <li>
+     * Obtain a lazy-copied version (via spanning tree) of the DAG rooted at the input-usage in
+     * question. Lazy-copying is done by walking a spanning tree of the original DAG, stopping at
+     * non-FloatingNodes but transitively walking FloatingNodes and their inputs. Upon arriving at a
+     * (floating) node N, the state's facts are checked to determine whether a constant C can be
+     * used instead in the resulting lazy-copied DAG. A NodeBitMap is used to realize the spanning
+     * tree.</li>
+     *
+     * <li>
+     * Provided one or more N-to-C node replacements took place, the resulting lazy-copied DAG has a
+     * parent different from the original (ie different object identity) which indicates the
+     * (copied, updated) DAG should replace the original via replaceFirstInput(), and inferStamp()
+     * should be invoked to reflect the updated inputs.</li>
+     *
+     * </ol>
+     * </p>
+     *
+     * @return whether any reduction was performed on the inputs of the arguments.
+     */
+    public boolean deverbosifyInputsInPlace(ValueNode parent) {
+        boolean changed = false;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
+            assert !(i instanceof GuardNode) : "ConditionalElim shouldn't run in MidTier";
+            ValueNode j = (ValueNode) reasoner.deverbosify(i);
+            if (i != j) {
+                changed = true;
+                FlowUtil.replaceInPlace(parent, i, j);
+            }
+        }
+        if (changed) {
+            FlowUtil.inferStampAndCheck(parent);
+        }
+        return changed;
+    }
+
+    /**
+     * Similar to {@link #deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)}, except that
+     * not the parent but a fresh clone is updated upon any of its children changing.
+     *
+     * @return the original parent if no updated took place, a copy-on-write version of it
+     *         otherwise.
+     *
+     */
+    private MethodCallTargetNode deverbosifyInputsCopyOnWrite(MethodCallTargetNode parent) {
+        MethodCallTargetNode changed = null;
+        for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
+            Node j = reasoner.deverbosify(i);
+            if (i != j) {
+                assert j != parent;
+                if (changed == null) {
+                    changed = (MethodCallTargetNode) parent.copyWithInputs();
+                    reasoner.added.add(changed);
+                    // copyWithInputs() implies graph.unique(changed)
+                    assert changed.isAlive();
+                    assert FlowUtil.lacksUsages(changed);
+                }
+                FlowUtil.replaceInPlace(changed, i, j);
+            }
+        }
+        if (changed == null) {
+            return parent;
+        }
+        FlowUtil.inferStampAndCheck(changed);
+        /*
+         * No need to rememberSubstitution() because not called from deverbosify(). In detail, it's
+         * only deverbosify() that skips visited nodes (thus we'd better have recorded any
+         * substitutions we want for them). Not this case.
+         */
+        return changed;
+    }
+
+    /**
+     * Precondition: This method assumes that either:
+     *
+     * <ul>
+     * <li>the state has already stabilized (ie no more pending iterations in the "iterative"
+     * dataflow algorithm); or</li>
+     * <li>any rewritings made based on the state in its current form are conservative enough to be
+     * safe.</li>
+     * </ul>
+     *
+     * <p>
+     * The overarching goal is to perform just enough rewriting to trigger other phases (
+     * {@link com.oracle.graal.graph.spi.SimplifierTool SimplifierTool},
+     * {@link com.oracle.graal.phases.common.DeadCodeEliminationPhase DeadCodeEliminationPhase},
+     * etc) to perform the bulk of rewriting, thus lowering the maintenance burden.
+     * </p>
+     *
+     */
+    @Override
+    protected void node(FixedNode node) {
+
+        assert node.isAlive();
+
+        /*-------------------------------------------------------------------------------------
+         * Step 1: Unreachable paths are still visited (PostOrderNodeIterator requires all ends
+         * of a merge to have been visited), but time is saved by neither updating the state nor
+         * rewriting anything while on an an unreachable path.
+         *-------------------------------------------------------------------------------------
+         */
+        if (state.isUnreachable) {
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 2: For an AbstractBeginNode, determine whether this path is reachable, register
+         * any associated guards.
+         *-------------------------------------------------------------------------------------
+         */
+        if (node instanceof BeginNode) {
+            BeginNode begin = (BeginNode) node;
+            Node pred = node.predecessor();
+
+            if (pred != null) {
+                registerControlSplit(pred, begin);
+            }
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 3: Check whether EquationalReasoner caches should be cleared upon state updates.
+         *-------------------------------------------------------------------------------------
+         */
+        reasoner.updateState(state);
+
+        /*-------------------------------------------------------------------------------------
+         * Step 4: Whatever special-case handling makes sense for the FixedNode at hand before
+         * its inputs are reduced.
+         *-------------------------------------------------------------------------------------
+         */
+
+        if (node instanceof AbstractEndNode) {
+            visitAbstractEndNode((AbstractEndNode) node);
+            return;
+        } else if (node instanceof Invoke) {
+            visitInvoke((Invoke) node);
+            return;
+        } else if (node instanceof CheckCastNode) {
+            // it's important not to call deverbosification for visitCheckCastNode()
+            visitCheckCastNode((CheckCastNode) node);
+            return;
+        } else if (node instanceof GuardingPiNode) {
+            visitGuardingPiNode((GuardingPiNode) node);
+            return;
+        } else if (node instanceof NullCheckNode) {
+            visitNullCheckNode((NullCheckNode) node);
+            return;
+        } else if (node instanceof FixedGuardNode) {
+            visitFixedGuardNode((FixedGuardNode) node);
+            return;
+        } else if (node instanceof ConditionAnchorNode) {
+            // ConditionAnchorNode shouldn't occur during HighTier
+            return;
+        }
+
+        /*-------------------------------------------------------------------------------------
+         * Step 5: After special-case handling, we do our best for those FixedNode-s
+         * where the effort to reduce their inputs might pay off.
+         *
+         * Why is this useful? For example, by the time the AbstractBeginNode for an If-branch
+         * is visited (in general a ControlSplitNode), the If-condition will have gone already
+         * through simplification (and thus potentially have been reduced to a
+         * LogicConstantNode).
+         *-------------------------------------------------------------------------------------
+         */
+        boolean paysOffToReduce = false;
+        if (node instanceof ControlSplitNode) {
+            // desire to simplify control flow
+            paysOffToReduce = true;
+        } else if (node instanceof ReturnNode) {
+            paysOffToReduce = true;
+        } else if (node instanceof AccessFieldNode || node instanceof AccessArrayNode) {
+            // desire to remove null-checks
+            paysOffToReduce = true;
+        }
+
+        // TODO comb the remaining FixedWithNextNode subclasses, pick those with good changes of
+        // paying-off
+
+        // TODO UnsafeLoadNode takes a condition
+
+        if (paysOffToReduce) {
+            deverbosifyInputsInPlace(node);
+        }
+
+        /*---------------------------------------------------------------------------------------
+         * Step 6: Any additional special-case handling, this time after having inputs reduced.
+         * For example, leverage anchors provided by the FixedNode, to add facts to the factbase.
+         *---------------------------------------------------------------------------------------
+         */
+
+        // TODO some nodes are GuardingNodes (eg, FixedAccessNode) we could use them to track state
+        // TODO others are additionally guarded (eg JavaReadNode), thus *their* guards could be
+        // simplified.
+
+    }
+
+    /**
+     * In case the scrutinee:
+     *
+     * <ul>
+     * <li>is known to be null, an unconditional deopt is added.</li>
+     * <li>is known to be non-null, the NullCheckNode is removed.</li>
+     * <li>otherwise, the NullCheckNode is lowered to a FixedGuardNode which then allows using it as
+     * anchor for state-tracking.</li>
+     * </ul>
+     *
+     * <p>
+     * Precondition: the input (ie, object) hasn't been deverbosified yet.
+     * </p>
+     */
+    private void visitNullCheckNode(NullCheckNode ncn) {
+        ValueNode object = ncn.getObject();
+        if (state.isNull(object)) {
+            postponedDeopts.addDeoptBefore(ncn, NullCheckException);
+            state.impossiblePath();
+            return;
+        }
+        if (state.isNonNull(object)) {
+            /*
+             * Redundant NullCheckNode. Unlike GuardingPiNode or FixedGuardNode, NullCheckNode-s
+             * aren't used as GuardingNode-s, thus in this case can be removed without further ado.
+             */
+            assert FlowUtil.lacksUsages(ncn);
+            graph.removeFixed(ncn);
+            return;
+        }
+        /*
+         * Lower the NullCheckNode to a FixedGuardNode which then allows using it as anchor for
+         * state-tracking. TODO the assumption here is that the code emitted for the resulting
+         * FixedGuardNode is as efficient as for NullCheckNode.
+         */
+        IsNullNode isNN = graph.unique(new IsNullNode(object));
+        reasoner.added.add(isNN);
+        FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true));
+        graph.replaceFixedWithFixed(ncn, nullCheck);
+
+        state.trackNN(object, nullCheck);
+    }
+
+    /**
+     * The {@link com.oracle.graal.nodes.AbstractEndNode} at the end of the current code path
+     * contributes values to {@link com.oracle.graal.nodes.PhiNode}s. Now is a good time to
+     * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)
+     * EquationalReasoner#deverbosify} those values.
+     *
+     * <p>
+     * Precondition: inputs haven't been deverbosified yet.
+     * </p>
+     */
+    private void visitAbstractEndNode(AbstractEndNode endNode) {
+        MergeNode merge = endNode.merge();
+        for (PhiNode phi : merge.phis()) {
+            if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+                assert phi.verify();
+                int index = merge.phiPredecessorIndex(endNode);
+                ValueNode original = phi.valueAt(index);
+                ValueNode reduced = (ValueNode) reasoner.deverbosify(original);
+                if (reduced != original) {
+                    phi.setValueAt(index, reduced);
+                    // `original` if unused will be removed in finished()
+                }
+            }
+        }
+    }
+
+    /**
+     * One or more arguments at `invoke` may have control-flow sensitive simplifications. In such
+     * case, a new {@link com.oracle.graal.nodes.java.MethodCallTargetNode MethodCallTargetNode} is
+     * prepared just for this callsite, consuming reduced arguments. This proves useful in
+     * connection with inlining, in order to specialize callees on the types of arguments other than
+     * the receiver (examples: multi-methods, the inlining problem, lambdas as arguments).
+     *
+     * <p>
+     * Precondition: inputs haven't been deverbosified yet.
+     * </p>
+     */
+    private void visitInvoke(Invoke invoke) {
+        if (invoke.asNode().stamp() instanceof IllegalStamp) {
+            return; // just to be safe
+        }
+        boolean isMethodCallTarget = invoke.callTarget() instanceof MethodCallTargetNode;
+        if (!isMethodCallTarget) {
+            return;
+        }
+        FlowUtil.replaceInPlace(invoke.asNode(), invoke.callTarget(), deverbosifyInputsCopyOnWrite((MethodCallTargetNode) invoke.callTarget()));
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        if (callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Virtual) {
+            return;
+        }
+        ValueNode receiver = callTarget.receiver();
+        if (receiver == null) {
+            return;
+        }
+        if (!FlowUtil.hasLegalObjectStamp(receiver)) {
+            return;
+        }
+        Witness w = state.typeInfo(receiver);
+        ResolvedJavaType type;
+        ResolvedJavaType stampType = StampTool.typeOrNull(receiver);
+        if (w == null || w.cluelessAboutType()) {
+            // can't improve on stamp but wil try to devirtualize anyway
+            type = stampType;
+        } else {
+            type = FlowUtil.tighten(w.type(), stampType);
+        }
+        if (type == null) {
+            return;
+        }
+        ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
+        if (method == null) {
+            return;
+        }
+        if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
+            metricMethodResolved.increment();
+            callTarget.setInvokeKind(MethodCallTargetNode.InvokeKind.Special);
+            callTarget.setTargetMethod(method);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+public class FlowSensitiveReductionPhase extends BasePhase<PhaseContext> {
+
+    private final MetaAccessProvider metaAccess;
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public FlowSensitiveReductionPhase(MetaAccessProvider metaAccess) {
+        this.metaAccess = metaAccess;
+    }
+
+    @Override
+    protected final void run(StructuredGraph graph, PhaseContext context) {
+        try (Debug.Scope s = Debug.scope("FlowSensitiveReduction")) {
+            Debug.dump(graph, "FlowSensitiveReduction initial");
+            new FlowSensitiveReduction(graph.start(), new State(), context).apply();
+            Debug.dump(graph, "FlowSensitiveReduction done");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugConfig;
+import com.oracle.graal.debug.DebugConfigScope;
+import com.oracle.graal.debug.internal.DebugScope;
+import com.oracle.graal.graph.InputType;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class FlowUtil {
+
+    private FlowUtil() {
+        // no instances of this class
+    }
+
+    public static boolean lacksUsages(Node n) {
+        return n.recordsUsages() && n.usages().isEmpty();
+    }
+
+    public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null || b == null) {
+            return null;
+        } else if (a.equals(b)) {
+            return a;
+        } else {
+            return a.findLeastCommonAncestor(b);
+        }
+    }
+
+    /**
+     * @return whether the first argument is strictly more precise than the second.
+     */
+    public static boolean isMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null) {
+            return false;
+        }
+        if (b == null) {
+            return true;
+        }
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (a.equals(b)) {
+            return false;
+        }
+        if (b.isInterface()) {
+            return b.isAssignableFrom(a);
+        }
+        if (a.isInterface()) {
+            return b.isInterface() && b.isAssignableFrom(a);
+        }
+        return b.isAssignableFrom(a);
+    }
+
+    public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null) {
+            assert b == null || !b.isPrimitive();
+            return b;
+        }
+        if (b == null) {
+            assert !a.isPrimitive();
+            return a;
+        }
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (a.equals(b)) {
+            return a;
+        }
+        if (isMorePrecise(a, b)) {
+            return a;
+        } else if (isMorePrecise(b, a)) {
+            return b;
+        } else {
+            /*
+             * Not comparable, two cases:
+             * 
+             * Example 1: 'a' standing for j.l.Number and 'b' for j.l.String We return null for lack
+             * of a value representing NullType, the right answer. Same goes when both arguments are
+             * non-comparable interfaces.
+             * 
+             * Example 2: 'a' standing for sun/nio/ch/DirectBuffer (an interface) and b for
+             * java/nio/Buffer (an abstract class). The class always takes precedence.
+             */
+            if (a.isInterface()) {
+                return b.isInterface() ? null : b;
+            }
+            if (b.isInterface()) {
+                return a.isInterface() ? null : a;
+            }
+            return null; // a and b aren't comparable, can't tighten() them
+        }
+    }
+
+    /**
+     *
+     * There are "illegal" stamps that are not of type IllegalStamp.
+     *
+     * For example, there may be an IntegerStamp with upperBound < lowerBound that returns
+     * !isLegal() but we still know it's an integer and thus not of type IllegalStamp.
+     *
+     * An IllegalStamp should never happen. In contrast, !isLegal() values could happen due to dead
+     * code not yet removed, or upon some non-sideeffecting instructions floating out of a dead
+     * branch.
+     */
+    public static boolean isLegalObjectStamp(Stamp s) {
+        return isObjectStamp(s) && s.isLegal();
+    }
+
+    public static boolean hasLegalObjectStamp(ValueNode v) {
+        return isLegalObjectStamp(v.stamp());
+    }
+
+    public static boolean isObjectStamp(Stamp stamp) {
+        return stamp instanceof ObjectStamp;
+    }
+
+    public static void inferStampAndCheck(ValueNode n) {
+        n.inferStamp();
+        if (n.stamp() instanceof ObjectStamp) {
+            ObjectStamp objectStamp = (ObjectStamp) n.stamp();
+            assert !objectStamp.isExactType() || objectStamp.type() != null;
+        }
+    }
+
+    /**
+     * Compares the arguments along three dimensions (nullness, exactness, and type). For the first
+     * argument to be more precise than the second, it may not score lower in any dimension and must
+     * score higher in at least one dimension.
+     *
+     * When comparing types s and t, sameness counts as 0; while being more precise is awarded with
+     * a score of 1. In all other cases (non-comparable, or supertype) the score is -1.
+     *
+     * @return whether the first argument is strictly more precise than the second.
+     */
+    public static boolean isMorePrecise(ObjectStamp a, ObjectStamp b) {
+        int d0 = MINUS(a.alwaysNull(), b.alwaysNull());
+        if (d0 == -1) {
+            return false;
+        }
+        int d1 = MINUS(a.nonNull(), b.nonNull());
+        if (d1 == -1) {
+            return false;
+        }
+        int d2 = MINUS(a.isExactType(), b.isExactType());
+        if (d2 == -1) {
+            return false;
+        }
+        int d3;
+        ResolvedJavaType ta = a.type();
+        ResolvedJavaType tb = b.type();
+        if (ta == null) {
+            d3 = (tb == null) ? 0 : -1;
+        } else if (tb == null) {
+            d3 = 1;
+        } else if (isMorePrecise(ta, tb)) {
+            d3 = 1;
+        } else if (ta.equals(tb)) {
+            d3 = 0;
+        } else {
+            d3 = -1;
+        }
+        if (d3 == -1) {
+            return false;
+        }
+        int maxScore = Math.max(Math.max(d0, d1), Math.max(d2, d3));
+        return maxScore > 0;
+    }
+
+    private static int MINUS(boolean a, boolean b) {
+        int aa = a ? 1 : 0;
+        int bb = b ? 1 : 0;
+        return aa - bb;
+    }
+
+    public static LogicConstantNode asLogicConstantNode(LogicNode cond) {
+        return (cond instanceof LogicConstantNode) ? (LogicConstantNode) cond : null;
+    }
+
+    public static boolean isLiteralNode(ValueNode f) {
+        return f instanceof ConstantNode || f instanceof LogicConstantNode;
+    }
+
+    public static boolean isConstantTrue(LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && c.getValue();
+    }
+
+    public static boolean isConstantFalse(LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && !c.getValue();
+    }
+
+    public static boolean alwaysFails(boolean isNegated, LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && (c.getValue() == isNegated);
+    }
+
+    public static boolean alwaysSucceeds(boolean isNegated, LogicNode cond) {
+        LogicConstantNode c = asLogicConstantNode(cond);
+        return (c != null) && (c.getValue() != isNegated);
+    }
+
+    /**
+     * Returns (preserving order) the ValueNodes without duplicates found among the argument's
+     * direct inputs.
+     */
+    @SuppressWarnings("unchecked")
+    public static List<ValueNode> distinctValueAndConditionInputs(Node n) {
+        ArrayList<ValueNode> result = null;
+        NodeClass.NodeClassIterator iter = n.inputs().iterator();
+        while (iter.hasNext()) {
+            NodeClass.Position pos = iter.nextPosition();
+            InputType inputType = pos.getInputType(n);
+            boolean isReducibleInput = (inputType == InputType.Value || inputType == InputType.Condition);
+            if (isReducibleInput) {
+                ValueNode i = (ValueNode) pos.get(n);
+                if (!isLiteralNode(i)) {
+                    if (result == null) {
+                        result = new ArrayList<>();
+                    }
+                    if (!result.contains(i)) {
+                        result.add(i);
+                    }
+                }
+            }
+        }
+        return result == null ? Collections.EMPTY_LIST : result;
+    }
+
+    public static ObjectStamp asNonNullStamp(ObjectStamp stamp) {
+        ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.objectNonNull());
+        assert result.isLegal();
+        return result;
+    }
+
+    public static ObjectStamp asRefinedStamp(ObjectStamp stamp, ResolvedJavaType joinType) {
+        assert !joinType.isInterface();
+        ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.declared(joinType));
+        assert result.isLegal();
+        return result;
+    }
+
+    /**
+     * Start situation: the parent node has <code>oldInput</code> among its (direct) inputs. After
+     * this method has run, all such occurrences have been replaced with <code>newInput</code>. In
+     * case that makes <code>oldInput</code> disconnected, it is removed from the graph.
+     */
+    public static void replaceInPlace(Node parent, Node oldInput, Node newInput) {
+        assert parent != null;
+        assert parent.inputs().contains(oldInput);
+        if (oldInput == newInput) {
+            return;
+        }
+        assert oldInput != null && newInput != null;
+        assert !isLiteralNode((ValueNode) oldInput);
+        do {
+            parent.replaceFirstInput(oldInput, newInput);
+        } while (parent.inputs().contains(oldInput));
+        // `oldInput` if unused wil be removed in finished()
+    }
+
+    public static StructuredGraph visualize(StructuredGraph graph, String title) {
+        DebugConfig debugConfig = DebugScope.getConfig();
+        DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+        try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+            Debug.dump(graph, title);
+
+            return graph;
+        }
+    }
+
+    public static final String ANSI_RESET = "\u001B[0m";
+    public static final String ANSI_BLACK = "\u001B[30m";
+    public static final String ANSI_RED = "\u001B[31m";
+    public static final String ANSI_GREEN = "\u001B[32m";
+    public static final String ANSI_YELLOW = "\u001B[33m";
+    public static final String ANSI_BLUE = "\u001B[34m";
+    public static final String ANSI_PURPLE = "\u001B[35m";
+    public static final String ANSI_CYAN = "\u001B[36m";
+    public static final String ANSI_WHITE = "\u001B[37m";
+
+    public static void highlightInRed(String msg) {
+        System.out.println(ANSI_RED + msg + ANSI_RESET);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ * <p>
+ * This class implements control-flow sensitive reductions for
+ * {@link com.oracle.graal.nodes.GuardingPiNode}.
+ * </p>
+ * 
+ * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+ */
+public abstract class GuardingPiReduction extends BaseReduction {
+
+    public GuardingPiReduction(FixedNode start, State initialState, PhaseContext context) {
+        super(start, initialState, context);
+    }
+
+    /**
+     * <p>
+     * By the time a {@link com.oracle.graal.nodes.GuardingPiNode GuardingPiNode} is visited, the
+     * available type refinements may allow reductions similar to those performed for
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
+     * CheckCastNode}.
+     * </p>
+     * 
+     * <ol>
+     * <li>
+     * If the condition needs no reduction (ie, it's already a
+     * {@link com.oracle.graal.nodes.LogicConstantNode LogicConstantNode}), this method basically
+     * gives up (thus letting other phases take care of it).</li>
+     * <li>
+     * Otherwise, an attempt is made to find a {@link com.oracle.graal.nodes.extended.GuardingNode}
+     * that implies the combination of (negated, condition) of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode} being visited. Details in
+     * {@link #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}. If found, the node
+     * can be removed.</li>
+     * <li>
+     * Otherwise, the node is lowered to a {@link com.oracle.graal.nodes.FixedGuardNode} and its
+     * usages replaced with {@link com.oracle.graal.nodes.PiNode}. Details in
+     * {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}.</li>
+     * </ol>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     * 
+     */
+    protected final void visitGuardingPiNode(GuardingPiNode envelope) {
+
+        if (!FlowUtil.hasLegalObjectStamp(envelope)) {
+            // this situation exercised by com.oracle.graal.jtt.optimize.NCE_FlowSensitive02
+            return;
+        }
+        if (!FlowUtil.hasLegalObjectStamp(envelope.object())) {
+            return;
+        }
+
+        /*
+         * (1 of 3) Cover the case of GuardingPiNode(LogicConstantNode, ...)
+         */
+
+        if (envelope.condition() instanceof LogicConstantNode) {
+            if (FlowUtil.alwaysFails(envelope.isNegated(), envelope.condition())) {
+                state.impossiblePath();
+                // let GuardingPiNode(false).canonical() prune the dead-code control-path
+                return;
+            }
+            // if not always-fails and condition-constant, then it always-succeeds!
+            assert FlowUtil.alwaysSucceeds(envelope.isNegated(), envelope.condition());
+            // let GuardingPiNode(true).canonical() replaceAtUsages
+            return;
+        }
+
+        /*
+         * The trick used in visitFixedGuardNode to look up an equivalent GuardingNode for the
+         * combination of (negated, condition) at hand doesn't work for GuardingPiNode, because the
+         * condition showing up here (a ShortCircuitOrNode that can be detected by
+         * CastCheckExtractor) doesn't appear as key in trueFacts, falseFacts. Good thing we have
+         * CastCheckExtractor!
+         */
+
+        /*
+         * (2 of 3) Cover the case of the condition known-to-be-false or known-to-be-true, but not
+         * LogicConstantNode.
+         * 
+         * If deverbosify(condition) == falseConstant, it would be safe to set:
+         * `envelope.setCondition(falseConstant)` (only the API won't allow).
+         * 
+         * On the other hand, it's totally unsafe to do something like that for trueConstant. What
+         * we can do about that case is the province of `tryRemoveGuardingPiNode(envelope)`
+         */
+
+        if (tryRemoveGuardingPiNode(envelope)) {
+            return;
+        }
+
+        /*
+         * Experience has shown that an attempt to eliminate the current GuardingPiNode by using a
+         * GuardingNode already in scope and with equivalent condition (grabbed from `trueFacts`
+         * resp. `falseFacts`) proves futile. Therefore we're not even attempting that here.
+         */
+
+        /*
+         * (3 of 3) Neither always-succeeds nor always-fails, ie we don't known. Converting to
+         * FixedGuardNode allows tracking the condition via a GuardingNode, thus potentially
+         * triggering simplifications down the road.
+         */
+        FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(envelope.condition(), envelope.getReason(), envelope.getAction(), envelope.isNegated()));
+        graph.addBeforeFixed(envelope, fixedGuard);
+
+        if (!FlowUtil.lacksUsages(envelope)) {
+            // not calling wrapInPiNode() because we don't want to rememberSubstitution()
+            PiNode replacement = graph.unique(new PiNode(envelope.object(), envelope.stamp(), fixedGuard));
+            reasoner.added.add(replacement);
+            // before removing the GuardingPiNode replace its usages
+            envelope.replaceAtUsages(replacement);
+        }
+
+        graph.removeFixed(envelope);
+
+        state.addFact(!fixedGuard.isNegated(), fixedGuard.condition(), fixedGuard);
+
+    }
+
+    /**
+     * <p>
+     * Based on flow-sensitive knowledge, two pre-requisites have to be fulfilled in order to remove
+     * a {@link com.oracle.graal.nodes.GuardingPiNode}:
+     * 
+     * <ul>
+     * <li>the condition must refer only to the payload of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode}</li>
+     * <li>the condition must check properties about which the state tracks not only a true/false
+     * answer, but also an anchor witnessing that fact</li>
+     * <li>the condition may not check anything else beyond what's stated in the items above.</li>
+     * </ul>
+     * </p>
+     * 
+     * <p>
+     * Provided a condition as above can be reduced to a constant (and an anchor obtained in the
+     * process), this method replaces all usages of the
+     * {@link com.oracle.graal.nodes.GuardingPiNode} (necessarily of
+     * {@link com.oracle.graal.graph.InputType#Value}) with a {@link com.oracle.graal.nodes.PiNode}
+     * that wraps the payload and the anchor in question.
+     * </p>
+     * 
+     * <p>
+     * Precondition: the condition hasn't been deverbosified yet.
+     * </p>
+     * 
+     * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     * 
+     */
+    private boolean tryRemoveGuardingPiNode(GuardingPiNode envelope) {
+
+        LogicNode cond = envelope.condition();
+        ValueNode payload = envelope.object();
+
+        ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+        if (isNullCheckOn(cond, payload)) {
+            if (envelope.isNegated()) {
+                /*
+                 * GuardingPiNode succeeds if payload non-null
+                 */
+                if (!outgoingStamp.equals(FlowUtil.asNonNullStamp(payloadStamp))) {
+                    warnAboutOutOfTheBlueGuardingPiNode(envelope);
+                }
+                return tryRemoveGuardingPiNodeNonNullCond(envelope);
+            } else {
+                /*
+                 * GuardingPiNode succeeds if payload null
+                 */
+                ValueNode replacement = StampTool.isObjectAlwaysNull(payload) ? payload : reasoner.nonTrivialNull(payload);
+                if (replacement != null) {
+                    // replacement == null means !isKnownNull(payload)
+                    removeGuardingPiNode(envelope, replacement);
+                    return true;
+                }
+                return false;
+            }
+        } else if (CastCheckExtractor.isInstanceOfCheckOn(cond, payload)) {
+            if (envelope.isNegated()) {
+                return false;
+            }
+            /*
+             * GuardingPiNode succeeds if payload instanceof <something>
+             */
+            InstanceOfNode io = (InstanceOfNode) cond;
+            assert io.type() != null;
+            Witness w = state.typeInfo(payload);
+            if (w != null && w.isNonNull() && isEqualOrMorePrecise(w.type(), io.type())) {
+                ValueNode d = reasoner.downcast(payload);
+                removeGuardingPiNode(envelope, d);
+                return true;
+            }
+            return false;
+        } else if (cond instanceof ShortCircuitOrNode) {
+            if (envelope.isNegated()) {
+                return false;
+            }
+            CastCheckExtractor cce = CastCheckExtractor.extract(cond);
+            if (cce == null || cce.subject != payload) {
+                return false;
+            }
+            /*
+             * GuardingPiNode succeeds if payload check-casts toType
+             */
+            return tryRemoveGuardingPiNodeCheckCastCond(envelope, cce.type);
+        }
+
+        return false;
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * This method handles the case where the GuardingPiNode succeeds if payload known to be
+     * non-null.
+     * 
+     * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     */
+    private boolean tryRemoveGuardingPiNodeNonNullCond(GuardingPiNode envelope) {
+
+        ValueNode payload = envelope.object();
+
+        if (state.isNull(payload)) {
+            // the GuardingPiNode fails always
+            postponedDeopts.addDeoptBefore(envelope, envelope.getReason());
+            state.impossiblePath();
+            return true;
+        }
+
+        if (StampTool.isObjectNonNull(payload)) {
+            // payload needs no downcasting, it satisfies as-is the GuardingPiNode's condition.
+            if (precisionLoss(envelope, payload)) {
+                /*
+                 * TODO The GuardingPiNode has an outgoing stamp whose narrowing goes beyond what
+                 * the condition checks. That's suspicious.
+                 */
+                PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp()));
+                reasoner.added.add(replacement);
+                removeGuardingPiNode(envelope, replacement);
+                return true;
+            } else {
+                removeGuardingPiNode(envelope, payload);
+                return true;
+            }
+        }
+        // if a non-null witness available, the GuardingPiNode can be removed
+
+        Witness w = state.typeInfo(payload);
+        GuardingNode nonNullAnchor = (w != null && w.isNonNull()) ? w.guard() : null;
+        if (nonNullAnchor != null) {
+            PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp(), nonNullAnchor.asNode()));
+            reasoner.added.add(replacement);
+            removeGuardingPiNode(envelope, replacement);
+            return true;
+        }
+
+        /*
+         * TODO What about, nodes that always denote non-null values? (Even though their stamp
+         * forgot to make that clear) Candidates: ObjectGetClassNode, Parameter(0) on instance
+         */
+
+        return false;
+    }
+
+    /**
+     * Porcelain method.
+     * 
+     * This method handles the case where the GuardingPiNode succeeds if payload null or its actual
+     * type equal or subtype of `toType`
+     * 
+     * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
+     * 
+     */
+    private boolean tryRemoveGuardingPiNodeCheckCastCond(GuardingPiNode envelope, ResolvedJavaType toType) {
+        assert toType != null;
+        ValueNode payload = envelope.object();
+
+        ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp();
+        ObjectStamp payloadStamp = (ObjectStamp) payload.stamp();
+
+        if (!outgoingStamp.equals(FlowUtil.asRefinedStamp(payloadStamp, toType))) {
+            warnAboutOutOfTheBlueGuardingPiNode(envelope);
+        }
+
+        ValueNode d = reasoner.downcast(payload);
+        if (d == null) {
+            return false;
+        }
+
+        if (StampTool.isObjectAlwaysNull(d)) {
+            removeGuardingPiNode(envelope, d);
+            return true;
+        }
+        ObjectStamp dStamp = (ObjectStamp) d.stamp();
+        if (isEqualOrMorePrecise(dStamp.type(), toType)) {
+            removeGuardingPiNode(envelope, d);
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * TODO There should be an assert in GuardingPiNode to detect that as soon as it happens
+     * (constructor, setStamp).
+     */
+    private static void warnAboutOutOfTheBlueGuardingPiNode(GuardingPiNode envelope) {
+        Debug.log(String.format("GuardingPiNode has an outgoing stamp whose narrowing goes beyond what its condition checks: %s", envelope));
+    }
+
+    private static boolean isNullCheckOn(LogicNode cond, ValueNode subject) {
+        if (!(cond instanceof IsNullNode)) {
+            return false;
+        }
+        IsNullNode isNull = (IsNullNode) cond;
+        return isNull.object() == subject;
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private void removeGuardingPiNode(GuardingPiNode envelope, ValueNode replacement) {
+        assert !precisionLoss(envelope, replacement);
+        metricGuardingPiNodeRemoved.increment();
+        envelope.replaceAtUsages(replacement);
+        assert FlowUtil.lacksUsages(envelope);
+        graph.removeFixed(envelope);
+    }
+
+    public static boolean isEqualOrMorePrecise(ResolvedJavaType a, ResolvedJavaType b) {
+        return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+    }
+
+    public static boolean isEqualOrMorePrecise(ObjectStamp a, ObjectStamp b) {
+        return a.equals(b) || FlowUtil.isMorePrecise(a, b);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+public class Histogram extends TreeMap<Integer, Integer> {
+
+    private static final long serialVersionUID = 7188324319057387738L;
+
+    private final String prefix;
+
+    public Histogram(String prefix) {
+        this.prefix = prefix;
+    }
+
+    public void tick(int bucket) {
+        Integer entry = get(bucket);
+        put(bucket, entry == null ? 1 : entry + 1);
+    }
+
+    public void print() {
+
+        // printing takes time, allow concurrent updates during printing
+        Histogram histogram = clone();
+
+        float casesTotal = 0;
+        for (int i : histogram.values()) {
+            casesTotal += i;
+        }
+        for (Map.Entry<Integer, Integer> entry : histogram.entrySet()) {
+            int numCases = entry.getValue();
+            int percentOut = (int) (numCases / casesTotal * 100);
+            String msg = prefix + String.format("%d iters in %4d cases (%2d %%)", entry.getKey(), numCases, percentOut);
+            if (entry.getKey() > 3) {
+                FlowUtil.highlightInRed(msg);
+            } else {
+                System.out.println(msg);
+            }
+        }
+        System.out.println(prefix + "--------------------------");
+    }
+
+    @Override
+    public Histogram clone() {
+        return (Histogram) super.clone();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.util.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class IterativeFlowSensitiveReductionPhase extends BasePhase<PhaseContext> {
+
+    private static final int MAX_ITERATIONS = 256;
+
+    private final CanonicalizerPhase canonicalizer;
+
+    public IterativeFlowSensitiveReductionPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
+    }
+
+    public static class CountingListener extends HashSetNodeChangeListener {
+
+        public int count;
+
+        @Override
+        public void nodeChanged(Node node) {
+            super.nodeChanged(node);
+        }
+
+    }
+
+    // private Histogram histogram = new Histogram("FSR-");
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        FlowSensitiveReductionPhase eliminate = new FlowSensitiveReductionPhase(context.getMetaAccess());
+        CountingListener listener = new CountingListener();
+        int count = 1;
+        while (true) {
+            listener.count = count;
+            graph.trackInputChange(listener);
+            graph.trackUsagesDroppedZero(listener);
+            eliminate.apply(graph, context);
+            graph.stopTrackingInputChange();
+            graph.stopTrackingUsagesDroppedZero();
+            if (listener.getChangedNodes().isEmpty()) {
+                // histogram.tick(count);
+                break;
+            }
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Simplifiable) {
+                    listener.getChangedNodes().add(node);
+                }
+            }
+            canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
+            listener.getChangedNodes().clear();
+            if (++count > MAX_ITERATIONS) {
+                // System.out.println("Bailing out IterativeFlowSensitiveReductionPhase for graph: "
+                // + graph);
+                // FlowUtil.visualize(graph, "Bailout");
+                throw new BailoutException("Number of iterations in FlowSensitiveReductionPhase exceeds " + MAX_ITERATIONS);
+            }
+        }
+        // histogram.print();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.Kind;
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+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.*;
+
+/**
+ * A State instance is mutated in place as each FixedNode is visited in a basic block of
+ * instructions. Basic block: starts with a {@link com.oracle.graal.nodes.BeginNode BeginNode}, ends
+ * at an {@link com.oracle.graal.nodes.EndNode EndNode} or
+ * {@link com.oracle.graal.nodes.ControlSinkNode ControlSinkNode} and lacks intervening control
+ * splits or merges.
+ */
+public final class State extends MergeableState<State> implements Cloneable {
+
+    private static final DebugMetric metricTypeRegistered = Debug.metric("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");
+
+    /**
+     * <p>
+     * Each state update results in a higher {@link State#versionNr versionNr}. The
+     * {@link State#versionNr versionNr} of different State instances can't be meaningfully compared
+     * (ie, same {@link State#versionNr versionNr} just indicates they've gone through the same
+     * number of updates). In particular, the {@link State#versionNr versionNr} of a merged state
+     * doesn't guarantee any more than being different from those of the states being merged.
+     * </p>
+     *
+     * <p>
+     * Still, {@link State#versionNr versionNr} proves useful in two cases:
+     *
+     * <ul>
+     * <li>recording the {@link State#versionNr versionNr} right after {@link State State} cloning,
+     * allows finding out afterwards whether (a) both states have diverged, (b) just one of them, or
+     * (c) none of them.</li>
+     * <li>a {@link State State} may become {@link State#isUnreachable isUnreachable}. In such case,
+     * it may make a difference whether any updates were performed on the state from the time it was
+     * cloned. Those updates indicate information not available in the state is was cloned from. For
+     * the purposes of {@link FlowSensitiveReduction FlowSensitiveReduction} an unreachable state
+     * need not be merged with any other (because control-flow won't reach the merge point over the
+     * path of the unreachable state).</li>
+     * </ul>
+     * </p>
+     *
+     */
+    int versionNr = 0;
+
+    boolean isUnreachable = false;
+
+    /**
+     * Getting here implies an opportunity was detected for dead-code-elimination. A counterpoint
+     * argument goes as follows: perhaps we don't get here that often, in which case the effort to
+     * detect an "impossible path" could be shaved off.
+     *
+     * @see com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt
+     */
+    void impossiblePath() {
+        isUnreachable = true;
+        metricImpossiblePathDetected.increment();
+    }
+
+    /**
+     * <p>
+     * This map 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)}
+     * .
+     * </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()}
+     * </p>
+     *
+     */
+    private IdentityHashMap<ValueNode, Witness> typeRefinements;
+
+    IdentityHashMap<ValueNode, GuardingNode> knownNull;
+    IdentityHashMap<LogicNode, GuardingNode> trueFacts;
+    IdentityHashMap<LogicNode, GuardingNode> falseFacts;
+
+    public State() {
+        this.typeRefinements = new IdentityHashMap<>();
+        this.knownNull = new IdentityHashMap<>();
+        this.trueFacts = new IdentityHashMap<>();
+        this.falseFacts = new IdentityHashMap<>();
+    }
+
+    public State(State other) {
+        this.isUnreachable = other.isUnreachable;
+        this.versionNr = other.versionNr;
+        this.typeRefinements = new IdentityHashMap<>();
+        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);
+    }
+
+    /**
+     * @return A new list containing only those states that are reachable.
+     */
+    private static ArrayList<State> reachableStates(List<State> states) {
+        ArrayList<State> result = new ArrayList<>(states);
+        Iterator<State> iter = result.iterator();
+        while (iter.hasNext()) {
+            if (iter.next().isUnreachable) {
+                iter.remove();
+            }
+        }
+        return result;
+    }
+
+    private IdentityHashMap<ValueNode, Witness> mergeKnownTypes(MergeNode merge, ArrayList<State> withReachableStates) {
+        IdentityHashMap<ValueNode, Witness> newKnownTypes = new IdentityHashMap<>();
+
+        for (Map.Entry<ValueNode, Witness> entry : typeRefinements.entrySet()) {
+            ValueNode node = entry.getKey();
+            Witness type = new Witness(entry.getValue());
+
+            for (State other : withReachableStates) {
+                Witness otherType = other.typeInfo(node);
+                if (otherType == null) {
+                    type = null;
+                    break;
+                }
+                type.merge(otherType, merge);
+            }
+            if (type != null && type.knowsBetterThan(node)) {
+                assert node == GraphUtil.unproxify(node);
+                newKnownTypes.put(node, type);
+            }
+        }
+
+        return newKnownTypes;
+    }
+
+    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
+     * (about type-refinement and nullness) based on the data available at each of the incoming
+     * branches.
+     * </p>
+     *
+     * <p>
+     * In more detail, <code>FlowSensitiveReduction#visitAbstractEndNode()</code> has already
+     * deverbosified the phi-values contributed by each reachable branch. The paths that
+     * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction} determined to be
+     * unreachable will be eliminated by canonicalization and dead code elimination. For now they
+     * still exist, thus polluting the result of
+     * {@link com.oracle.graal.nodes.ValuePhiNode#inferPhiStamp()} but we are careful to skip them
+     * 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) {
+
+        if (merge instanceof LoopBeginNode) {
+            return;
+        }
+
+        for (PhiNode phi : merge.phis()) {
+            assert phi == GraphUtil.unproxify(phi);
+            if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) {
+                ArrayList<ValueNode> reachingValues = new ArrayList<>();
+                if (!isUnreachable) {
+                    reachingValues.add(phi.valueAt(0));
+                }
+                for (int i = 0; i < withStates.size(); i++) {
+                    State otherState = withStates.get(i);
+                    if (!otherState.isUnreachable) {
+                        reachingValues.add(phi.valueAt(i + 1));
+                    }
+                }
+                assert !reachingValues.isEmpty();
+                ObjectStamp phiStamp = (ObjectStamp) phi.stamp();
+                ObjectStamp nonPollutedStamp = (ObjectStamp) StampTool.meet(reachingValues);
+                Witness w = new Witness(nonPollutedStamp, merge);
+                if (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());
+                } else if (w.isNonNull() && !phiStamp.nonNull()) {
+                    // precision gain regarding nullness
+                    newKnownPhiTypes.put(phi, w);
+                    // confirm no precision loss regarding type
+                    assert !FlowUtil.isMorePrecise(phiStamp.type(), w.type());
+                }
+                if (nonPollutedStamp.alwaysNull()) {
+                    newKnownNullPhis.put(phi, merge);
+                }
+            }
+        }
+
+    }
+
+    private static boolean implies(boolean a, boolean b) {
+        return !a || b;
+    }
+
+    @Override
+    public boolean merge(MergeNode merge, List<State> withStates) {
+
+        ArrayList<State> withReachableStates = reachableStates(withStates);
+        if (withReachableStates.isEmpty()) {
+            return true;
+        }
+
+        for (State other : withReachableStates) {
+            versionNr = Math.max(versionNr, other.versionNr) + 1;
+            if (!other.isUnreachable) {
+                isUnreachable = false;
+            }
+        }
+
+        if (isUnreachable) {
+            typeRefinements.clear();
+            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);
+        // may also get updated in a moment, during processing of phi nodes.
+        IdentityHashMap<ValueNode, GuardingNode> newKnownNull = mergeKnownNull(merge, withReachableStates);
+        mergePhis(merge, withStates, newKnownTypes, newKnownNull);
+        this.typeRefinements = newKnownTypes;
+        this.knownNull = newKnownNull;
+
+        this.trueFacts = mergeTrueFacts(withReachableStates, merge);
+        this.falseFacts = mergeFalseFacts(withReachableStates, merge);
+        return true;
+    }
+
+    private IdentityHashMap<LogicNode, GuardingNode> mergeTrueFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
+        IdentityHashMap<LogicNode, GuardingNode> newTrueConditions = new IdentityHashMap<>();
+        for (Map.Entry<LogicNode, GuardingNode> entry : trueFacts.entrySet()) {
+            LogicNode check = entry.getKey();
+            GuardingNode guard = entry.getValue();
+
+            for (State other : withReachableStates) {
+                GuardingNode otherGuard = other.trueFacts.get(check);
+                if (otherGuard == null) {
+                    guard = null;
+                    break;
+                }
+                if (otherGuard != guard) {
+                    guard = merge;
+                }
+            }
+            if (guard != null) {
+                newTrueConditions.put(check, guard);
+            }
+        }
+        return newTrueConditions;
+    }
+
+    private IdentityHashMap<LogicNode, GuardingNode> mergeFalseFacts(ArrayList<State> withReachableStates, GuardingNode merge) {
+        IdentityHashMap<LogicNode, GuardingNode> newFalseConditions = new IdentityHashMap<>();
+        for (Map.Entry<LogicNode, GuardingNode> entry : falseFacts.entrySet()) {
+            LogicNode check = entry.getKey();
+            GuardingNode guard = entry.getValue();
+
+            for (State other : withReachableStates) {
+                GuardingNode otherGuard = other.falseFacts.get(check);
+                if (otherGuard == null) {
+                    guard = null;
+                    break;
+                }
+                if (otherGuard != guard) {
+                    guard = merge;
+                }
+            }
+            if (guard != null) {
+                newFalseConditions.put(check, guard);
+            }
+        }
+        return newFalseConditions;
+    }
+
+    /**
+     * @return null if no type-witness available for the argument, the witness otherwise.
+     */
+    public Witness typeInfo(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        return typeRefinements.get(GraphUtil.unproxify(object));
+    }
+
+    /**
+     * @return true iff the argument is known to stand for null.
+     */
+    public boolean isNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        return StampTool.isObjectAlwaysNull(object) || knownNull.containsKey(GraphUtil.unproxify(object));
+    }
+
+    /**
+     * <p>
+     * It makes a difference calling {@link Witness#isNonNull()} as opposed to
+     * {@link State#isNonNull(com.oracle.graal.nodes.ValueNode)}. The former guarantees the witness
+     * provides a guard certifying non-nullness. The latter just tells us there exists some guard
+     * that certifies the property we asked about.
+     * </p>
+     *
+     * <p>
+     * TODO improvement: isKnownNonNull could be made smarter by noticing some nodes always denote a
+     * non-null value (eg, ObjectGetClassNode). Similarly for isKnownNull. Code that looks at the
+     * stamp as well as code that looks for a non-null-witness would benefit from also checking such
+     * extended isKnownNonNull. Alternatively, the stamp of those nodes should always have
+     * is-non-null set.
+     * </p>
+     *
+     * @return true iff the argument is known to stand for non-null.
+     */
+    public boolean isNonNull(ValueNode object) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        if (StampTool.isObjectNonNull(object)) {
+            return true;
+        }
+        Witness w = typeInfo(object);
+        return w == null ? false : w.isNonNull();
+    }
+
+    /**
+     * @return true iff the argument is known to stand for an object conforming to the given type.
+     */
+    public boolean knownToConform(ValueNode object, ResolvedJavaType to) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        assert !to.isPrimitive();
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && to.isAssignableFrom(stampType)) {
+            return true;
+        }
+        final ValueNode scrutinee = GraphUtil.unproxify(object);
+        if (isNull(scrutinee)) {
+            return true;
+        }
+        Witness w = typeInfo(scrutinee);
+        boolean witnessAnswer = w != null && w.type() != null && to.isAssignableFrom(w.type());
+        if (witnessAnswer) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return true iff the argument is known to stand for an object that definitely does not
+     *         conform to the given type.
+     */
+    public boolean knownNotToConform(ValueNode object, ResolvedJavaType to) {
+        assert FlowUtil.hasLegalObjectStamp(object);
+        assert !to.isPrimitive();
+        final ValueNode scrutinee = GraphUtil.unproxify(object);
+        if (isNull(scrutinee)) {
+            return false;
+        }
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && knownNotToConform(stampType, to)) {
+            return true;
+        }
+        Witness w = typeInfo(scrutinee);
+        boolean witnessAnswer = w != null && !w.cluelessAboutType() && knownNotToConform(w.type(), to);
+        if (witnessAnswer) {
+            return true;
+        }
+        return false;
+    }
+
+    // @formatter:off
+    /**
+     *   \   |     |     |     |
+     *    \ b|     |     |     |
+     *   a \ |     |     |     |
+     *      \|iface|final|non-f|
+     *  -----+-----------------|
+     *  iface|  F  |  F  |  F  |
+     *  -----+-----------------|
+     *  final|  C  |  C  |  C  |
+     *  -----+-----------------|
+     *  non-f|  F  |  C  |  C  |
+     *  -----------------------+
+     *
+     *  where:
+     *    F:     false
+     *    C:     check
+     *    iface: interface
+     *    final: exact non-interface reference-type
+     *    non-f: non-exact non-interface reference-type
+     *
+     * @return true iff the first argument is known not to conform to the second argument.
+     */
+    // @formatter:on
+    public static boolean knownNotToConform(ResolvedJavaType a, ResolvedJavaType b) {
+        assert !a.isPrimitive();
+        assert !b.isPrimitive();
+        if (b.isAssignableFrom(a)) {
+            return false;
+        }
+        if (a.isInterface()) {
+            return false;
+        }
+        boolean aFinal = Modifier.isFinal(a.getModifiers());
+        if (b.isInterface() && !aFinal) {
+            return false;
+        }
+        if (a.isAssignableFrom(b)) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    @Override
+    public State clone() {
+        return new State(this);
+    }
+
+    /**
+     * Porcelain method.
+     */
+    private Witness getOrElseAddTypeInfo(ValueNode object) {
+        ValueNode scrutinee = GraphUtil.unproxify(object);
+        Witness w = typeRefinements.get(scrutinee);
+        if (w == null) {
+            w = new Witness();
+            typeRefinements.put(scrutinee, w);
+        }
+        return w;
+    }
+
+    /**
+     * <p>
+     * Updates this {@link State State} to account for an observation about the scrutinee being
+     * non-null. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     * </p>
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller takes care of that.
+     * </p>
+     *
+     * @return whether state was updated (iff the observation added any new information)
+     */
+    public boolean trackNN(ValueNode object, GuardingNode anchor) {
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        ResolvedJavaType stampType = StampTool.typeOrNull(object);
+        if (stampType != null && !stampType.isInterface()) {
+            return trackIO(object, stampType, anchor);
+        }
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackNN(anchor)) {
+            versionNr++;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link State State} to account for an observation about the scrutinee conforming
+     * to a type. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     * @return false iff the observed type is an interface, or doesn't provide any new information
+     *         not already known. Ie, this method returns true iff the observation resulted in
+     *         information gain.
+     */
+    public boolean trackCC(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+        if (observed.isInterface()) {
+            return false;
+        }
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackCC(observed, anchor)) {
+            versionNr++;
+            metricTypeRegistered.increment();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link State State} to account for an observation about the non-null scrutinee
+     * conforming to a type.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     * @return whether state was updated (iff the observation added any new information)
+     */
+    public boolean trackIO(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) {
+        assert !observed.isInterface() : "no infrastructure yet in State.Witness to support interfaces in general";
+        if (isDependencyTainted(object, anchor)) {
+            return false;
+        }
+        assert anchor instanceof FixedNode;
+        Witness w = getOrElseAddTypeInfo(object);
+        if (w.trackIO(observed, anchor)) {
+            versionNr++;
+            metricTypeRegistered.increment();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * This method increases {@link #versionNr} (thus potentially invalidating
+     * {@link EquationalReasoner EquationalReasoner}'s caches) only if the fact wasn't known
+     * already.
+     *
+     * <p>
+     * No check is made on whether a contradiction would be introduced into the factbase (in which
+     * case the state should be marked unreachable), the caller must take care of that.
+     * </p>
+     *
+     */
+    private void addFactPrimordial(LogicNode condition, IdentityHashMap<LogicNode, GuardingNode> to, GuardingNode anchor) {
+        assert condition != null;
+        if (!to.containsKey(condition)) {
+            versionNr++;
+            to.put(condition, anchor);
+        }
+    }
+
+    /**
+     * Ideas for the future:
+     * <ul>
+     * <li>track inferred less-than edges from (accumulated) CompareNode-s</li>
+     * <li>track set-representative for equality classes determined by (chained) IntegerTestNode</li>
+     * </ul>
+     *
+     */
+    public void addFact(boolean isTrue, LogicNode condition, GuardingNode anchor) {
+        assert anchor != null;
+        assert anchor instanceof FixedNode;
+        assert !isUnreachable;
+
+        if (condition instanceof LogicConstantNode) {
+            if (((LogicConstantNode) condition).getValue() != isTrue) {
+                impossiblePath();
+            }
+            return;
+        }
+
+        if (condition instanceof LogicNegationNode) {
+            addFact(!isTrue, ((LogicNegationNode) condition).getInput(), anchor);
+        } else if (condition instanceof ShortCircuitOrNode) {
+            /*
+             * We can register the conditions being or-ed as long as the anchor is a fixed node,
+             * because floating guards will be registered at a BeginNode but might be "valid" only
+             * later due to data flow dependencies. Therefore, registering both conditions of a
+             * ShortCircuitOrNode for a floating guard could lead to cycles in data flow, because
+             * the guard will be used as anchor for both conditions, and one condition could be
+             * depending on the other.
+             */
+            if (isTrue) {
+                CastCheckExtractor cce = CastCheckExtractor.extract(condition);
+                if (cce == null || isDependencyTainted(cce.subject, anchor)) {
+                    addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+                } else {
+                    trackCC(cce.subject, cce.type, anchor);
+                }
+            } else {
+                ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition;
+                addFact(disjunction.isXNegated(), disjunction.getX(), anchor);
+                // previous addFact might have resulted in impossiblePath()
+                if (isUnreachable) {
+                    return;
+                }
+                addFact(disjunction.isYNegated(), disjunction.getY(), anchor);
+            }
+        } else if (condition instanceof InstanceOfNode) {
+            addFactInstanceOf(isTrue, (InstanceOfNode) condition, anchor);
+        } else if (condition instanceof IsNullNode) {
+            IsNullNode nullCheck = (IsNullNode) condition;
+            addNullness(isTrue, nullCheck.object(), anchor);
+        } else if (condition instanceof ObjectEqualsNode) {
+            addFactObjectEqualsNode(isTrue, (ObjectEqualsNode) condition, anchor);
+        } else {
+            addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor);
+        }
+    }
+
+    /**
+     * An instanceof hint is tracked differently depending on whether it's an interface-test or not
+     * (because type-refinements currently lacks the ability to track interface types).
+     *
+     */
+    private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) {
+        ValueNode object = instanceOf.object();
+        if (isTrue) {
+            if (knownNotToConform(object, instanceOf.type())) {
+                impossiblePath();
+                return;
+            }
+            addNullness(false, object, anchor);
+            if (instanceOf.type().isInterface()) {
+                if (!knownToConform(object, instanceOf.type())) {
+                    addFactPrimordial(instanceOf, trueFacts, anchor);
+                }
+            } else {
+                trackIO(object, instanceOf.type(), anchor);
+            }
+        }
+    }
+
+    private void addFactObjectEqualsNode(boolean isTrue, ObjectEqualsNode equals, GuardingNode anchor) {
+        if (isDependencyTainted(equals.x(), anchor)) {
+            return;
+        }
+        if (isDependencyTainted(equals.y(), anchor)) {
+            return;
+        }
+        assert anchor instanceof FixedNode;
+        ValueNode x = GraphUtil.unproxify(equals.x());
+        ValueNode y = GraphUtil.unproxify(equals.y());
+        if (isTrue) {
+            if (isNull(x) && isNonNull(y)) {
+                impossiblePath();
+                return;
+            }
+            if (isNonNull(x) && isNull(y)) {
+                impossiblePath();
+                return;
+            }
+            if (isNull(x) || isNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(true, equals.x(), anchor);
+                addNullness(true, equals.y(), anchor);
+            } else if (isNonNull(x) || isNonNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.x(), anchor);
+                addNullness(false, equals.y(), anchor);
+            }
+            Witness wx = typeInfo(x);
+            Witness wy = typeInfo(y);
+            if (wx == null && wy == null) {
+                return;
+            } else if (wx != null && wy != null) {
+                // tighten their type-hints, provided at least one available
+                // both witnesses may have seen == null, ie they may be NN witnesses
+                ResolvedJavaType best = FlowUtil.tighten(wx.type(), wy.type());
+                if (best != null) {
+                    assert !best.isInterface();
+                    // type tightening is enough, nullness already taken care of
+                    trackCC(equals.x(), best, anchor);
+                    trackCC(equals.y(), best, anchor);
+                }
+            } else if (wx == null) {
+                typeRefinements.put(x, new Witness(wy));
+            } else if (wy == null) {
+                typeRefinements.put(y, new Witness(wx));
+            }
+        } else {
+            if (isNull(x) && !isNonNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.y(), anchor);
+            } else if (!isNonNull(x) && isNull(y)) {
+                metricObjectEqualsRegistered.increment();
+                addNullness(false, equals.x(), anchor);
+            }
+        }
+    }
+
+    /**
+     * Adds information about the nullness of a value. If isNull is true then the value is known to
+     * be null, otherwise the value is known to be non-null.
+     */
+    public void addNullness(boolean isNull, ValueNode value, GuardingNode anchor) {
+        if (isDependencyTainted(value, anchor)) {
+            return;
+        }
+        assert anchor instanceof FixedNode;
+        ValueNode original = GraphUtil.unproxify(value);
+        boolean wasNull = isNull(original);
+        boolean wasNonNull = isNonNull(original);
+        if (isNull) {
+            if (wasNonNull) {
+                impossiblePath();
+            } else {
+                metricNullnessRegistered.increment();
+                versionNr++;
+                knownNull.put(original, anchor);
+            }
+        } else {
+            if (wasNull) {
+                impossiblePath();
+            } else {
+                metricNullnessRegistered.increment();
+                trackNN(original, anchor);
+            }
+        }
+    }
+
+    /**
+     *
+     * @return true iff `value` may lose dependency not covered by `anchor`.
+     */
+    public static boolean isDependencyTainted(ValueNode value, GuardingNode anchor) {
+        assert anchor instanceof FixedNode;
+        if (value instanceof ValueProxy) {
+            if (value instanceof GuardedNode) {
+                GuardedNode gn = (GuardedNode) value;
+                GuardingNode guardian = gn.getGuard();
+                if (guardian != null) {
+                    boolean isGuardedByFixed = guardian instanceof FixedNode;
+                    if (!isGuardedByFixed) {
+                        return true;
+                    }
+                }
+            }
+            // if (value instanceof GuardingNode) {
+            // return true;
+            // }
+            ValueProxy proxy = (ValueProxy) value;
+            return isDependencyTainted(proxy.getOriginalNode(), anchor);
+        }
+        return false;
+    }
+
+    public void clear() {
+        versionNr = 0;
+        isUnreachable = false;
+        typeRefinements.clear();
+        knownNull.clear();
+        trueFacts.clear();
+        falseFacts.clear();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common.cfs;
+
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+
+/**
+ * <p>
+ * A witness progressively tracks more detailed properties about an object value (the scrutinee);
+ * the properties in question comprise whether the scrutinee has been observed:
+ *
+ * <ul>
+ * <li>as non-null,</li>
+ * <li>in a successful checkcast, or</li>
+ * <li>in a successful instanceof.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * A witness is updated only when doing so increases the information content of the witness. For
+ * example, upon visiting a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} the
+ * witness gets a chance to become updated.
+ * </p>
+ *
+ * <p>
+ * Therefore, at any given time, a witness represents the most detailed knowledge available so far
+ * about the scrutinee, which is the knowledge most relevant for upcoming program-points.
+ * </p>
+ *
+ * <p>
+ * The availability of witnesses about both non-nullness and checkcast (for a given scrutinee)
+ * promotes to an instanceof-style witness . The "levels" of knowledge a witness may exhibit are
+ * captured by {@link com.oracle.graal.phases.common.cfs.Witness.LEVEL}. For conciseness, the
+ * following query methods are available for a {@link com.oracle.graal.phases.common.cfs.Witness}:
+ * <ul>
+ * <li>{@link #atNonNull()}</li>
+ * <li>{@link #atCheckCast()}</li>
+ * <li>{@link #atInstanceOf()}</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Only non-interface object types (ie, class and array types) are tracked. Small extensions are
+ * required to track interfaces, extensions that might be added after the current scheme proves
+ * itself.
+ * </p>
+ *
+ * <p>
+ * Some useful facts about the Statechart implemented by {@link Witness Witness}:
+ *
+ * <ul>
+ * <li>the start-state is "clueless"</li>
+ * <li>
+ * A self-transition via trackCC from whichever the current state is to itself, without information
+ * gain, is always possible. Just give {@link Object java.lang.Object} as observed type.</li>
+ * </ul>
+ * </p>
+ *
+ */
+public class Witness implements Cloneable {
+
+    private static enum LEVEL {
+        CLUELESS,
+        NN,
+        CC,
+        IO
+    }
+
+    private boolean atNonNull() {
+        return level == LEVEL.NN;
+    }
+
+    private boolean atCheckCast() {
+        return level == LEVEL.CC;
+    }
+
+    private boolean atInstanceOf() {
+        return level == LEVEL.IO;
+    }
+
+    private void transition(LEVEL to, GuardingNode newAnchor) {
+        this.level = to;
+        this.gn = newAnchor;
+        assert repOK();
+    }
+
+    public Witness() {
+    }
+
+    public Witness(Witness other) {
+        level = other.level;
+        seen = other.seen;
+        gn = other.gn;
+    }
+
+    /**
+     * Counterpart to {@link #asStamp()}
+     */
+    public Witness(ObjectStamp stamp, GuardingNode anchor) {
+        assert stamp.isLegal();
+        assert anchor != null;
+        boolean isNonIface = (stamp.type() != null && !stamp.type().isInterface());
+        if (stamp.nonNull()) {
+            if (isNonIface) {
+                seen = stamp.type();
+                transition(LEVEL.IO, anchor);
+            } else {
+                seen = null;
+                transition(LEVEL.NN, anchor);
+            }
+        } else {
+            if (isNonIface) {
+                seen = stamp.type();
+                transition(LEVEL.CC, anchor);
+            } else {
+                seen = null;
+                transition(LEVEL.CLUELESS, null);
+                assert clueless();
+            }
+        }
+        assert repOK();
+    }
+
+    /**
+     * 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();
+    }
+
+    /**
+     * The most precise type known so far about the scrutinee. (Please notice that nothing can be
+     * deduced about the non-nullness-status of the scrutinee from invoking this method alone).
+     */
+    public ResolvedJavaType type() {
+        return seen;
+    }
+
+    public ObjectStamp asStamp() {
+        boolean isKnownExact = (seen != null && seen.equals(seen.asExactType()));
+        return new ObjectStamp(seen, isKnownExact, isNonNull(), false);
+    }
+
+    private LEVEL level = LEVEL.CLUELESS;
+    private ResolvedJavaType seen = null;
+
+    /**
+     * Evidence (ie, a {@link com.oracle.graal.nodes.extended.GuardingNode}) attesting to the status
+     * reported by this witness.
+     *
+     * May be one of:
+     *
+     * <ul>
+     * <li>
+     * {@link com.oracle.graal.nodes.BeginNode BeginNode},</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.LoopExitNode LoopExitNode},</li>
+     * <li>
+     * {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}</li>
+     * <li>{@link com.oracle.graal.nodes.MergeNode MergeNode}, resulting from merging two witnesses
+     * with different values for this anchor</li>
+     * </ul>
+     *
+     * <p>
+     * An {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} test results in the
+     * more-clueless of both scrutinees having its witness upgraded to that of the other (both
+     * scrutinees share the same {@link Witness Witness} instance from then on). For this reason,
+     * this field may also hold the anchors associated to an
+     * {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} occurrence, ie nodes
+     * that can serve as {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} for the
+     * purposes of building a {@link com.oracle.graal.nodes.PiNode PiNode}.
+     * </p>
+     *
+     */
+    private GuardingNode gn = null;
+
+    /**
+     * Invariants of this class:
+     * <ul>
+     * <li>All fields holding null is ok, the hallmark of a {@link #clueless() clueless} witness.
+     * Another way for a witness to be clueless is by recording <code>java.lang.Object</code> as the
+     * seen type and nothing more.</li>
+     * <li>{@link #seen seen} may be null as long as the only hint being recorded is non-nullness</li>
+     * <li>A non-null value for {@link #seen seen} can't be tracked with NN, that combination
+     * amounts to IO and is tracked as such</li>
+     * <li>At most one of NN, CC, IO may be tracked at any given time</li>
+     * <li>A non-null CC or a non-null IO force {@link #seen seen} to be non-null</li>
+     * <li>{@link #seen seen} must be null or denote a non-interface reference type (ie, either a
+     * class-type or an array-type)</li>
+     * </ul>
+     */
+    private boolean repOK() {
+        if (clueless()) {
+            assert level == LEVEL.CLUELESS;
+            return true;
+        }
+        if (level == LEVEL.NN) {
+            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;
+        return true;
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean clueless() {
+        return cluelessAboutType() && cluelessAboutNonNullness();
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean cluelessAboutType() {
+        // TODO also clueless when `seen` is `java.lang.Object`
+        return seen == null;
+    }
+
+    /**
+     * Helper method for readability in complex conditions.
+     */
+    public boolean cluelessAboutNonNullness() {
+        return !atNonNull() && !atInstanceOf();
+    }
+
+    /**
+     * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+     * the given {@link com.oracle.graal.compiler.common.type.ObjectStamp}.
+     */
+    boolean knowsBetterThan(ObjectStamp other) {
+        return FlowUtil.isMorePrecise(asStamp(), other);
+    }
+
+    /**
+     * Whether this {@link Witness Witness} tracks information strictly more precise than that in
+     * the {@link com.oracle.graal.compiler.common.type.ObjectStamp} of the given argument.
+     */
+    boolean knowsBetterThan(ValueNode other) {
+        return knowsBetterThan((ObjectStamp) other.stamp());
+    }
+
+    /**
+     * Porcelain method for internal use only, invoked upon a Facade method being notified about
+     * checkcast or instanceof.
+     *
+     * @return whether the state was updated (iff the observation adds any new information)
+     */
+    private boolean refinesSeenType(ResolvedJavaType observed) {
+        if (cluelessAboutType() || FlowUtil.isMorePrecise(observed, seen)) {
+            seen = observed;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the scrutinee being
+     * non-null. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead
+     *
+     * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+     *         information)
+     */
+    public boolean trackNN(GuardingNode anchor) {
+        assert repOK();
+        try {
+            if (atInstanceOf()) {
+                return false;
+            }
+            if (atCheckCast()) {
+                transition(LEVEL.IO, anchor);
+                return true;
+            }
+            if (!atNonNull()) {
+                transition(LEVEL.NN, anchor);
+                return true;
+            }
+            return false;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the scrutinee
+     * conforming to the provided type. In case instanceof was observed,
+     * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode)
+     * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead.
+     *
+     * @return true iff information was gained.
+     */
+    public boolean trackCC(ResolvedJavaType observed, GuardingNode anchor) {
+        assert !observed.isInterface();
+        assert anchor != null;
+        assert repOK();
+        try {
+            boolean anchorObsolete = refinesSeenType(observed);
+            if (atInstanceOf()) {
+                /*
+                 * Statechart: self-transition at IO, potential information gain.
+                 */
+                if (anchorObsolete) {
+                    transition(LEVEL.IO, anchor);
+                    return true;
+                }
+                return false;
+            }
+            if (anchorObsolete) {
+                if (!atNonNull()) {
+                    /* Statechart: transition from clueless to CC. */
+                    transition(LEVEL.CC, anchor);
+                    return true;
+                } else {
+                    /* Statechart: transition from NN to IO. */
+                    transition(LEVEL.IO, anchor);
+                    return true;
+                }
+            }
+            /*
+             * Statechart: self-transition from whichever the current state is to itself, without
+             * information gain.
+             */
+            return false;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Updates this {@link Witness Witness} to account for an observation about the non-null
+     * scrutinee conforming to a type.
+     *
+     * @return whether this {@link Witness Witness} was updated (iff the observation adds any new
+     *         information)
+     */
+    public boolean trackIO(ResolvedJavaType observed, GuardingNode anchor) {
+        assert repOK();
+        try {
+            boolean gotMorePreciseType = refinesSeenType(observed);
+            if (!atInstanceOf() || gotMorePreciseType) {
+                transition(LEVEL.IO, anchor);
+                return true;
+            }
+            return gotMorePreciseType;
+        } finally {
+            assert repOK();
+        }
+    }
+
+    /**
+     * Shallow cloning is enough because what's reachable from {@link Witness} is primitive or used
+     * read-only when merging states.
+     */
+    @Override
+    public Witness clone() {
+        return new Witness(this);
+    }
+
+    /**
+     * @return null for a clueless method, non-null otherwise.
+     */
+    GuardingNode guard() {
+        return gn;
+    }
+
+    /**
+     * Merges another state into this one, by mutating this object, the other is left as is.
+     */
+    public void merge(Witness that, MergeNode merge) {
+        assert this.repOK();
+        assert that.repOK();
+
+        if (clueless()) {
+            return;
+        }
+
+        // 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
+         */
+        final boolean resultIO = atInstanceOf() && that.atInstanceOf();
+        /* failing that, attempt to rescue type-conformance */
+        final boolean resultCC = !resultIO && (!cluelessAboutType() && !that.cluelessAboutType());
+        /* if all else fails, attempt to rescue non-nullness */
+        final boolean resultNN = !resultIO && !resultCC && (isNonNull() && that.isNonNull());
+
+        seen = newSeen;
+        level = resultIO ? LEVEL.IO : resultCC ? LEVEL.CC : resultNN ? LEVEL.NN : LEVEL.CLUELESS;
+        gn = resultGuard;
+
+        assert repOK();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(cluelessAboutType() ? "seen=?" : "seen=" + seen);
+        sb.append(";");
+        sb.append("gn=" + gn);
+        return sb.toString();
+    }
+
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Fri May 02 11:33:47 2014 +0200
@@ -72,7 +72,7 @@
         try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this)) {
             BasePhase.this.run(graph, context);
             phaseMetric.increment();
-            if (dumpGraph) {
+            if (dumpGraph && Debug.isDumpEnabled()) {
                 Debug.dump(graph, "After phase %s", getName());
             }
             assert graph.verify();
@@ -81,13 +81,17 @@
         }
     }
 
+    protected CharSequence createName() {
+        String s = BasePhase.this.getClass().getSimpleName();
+        if (s.endsWith("Phase")) {
+            s = s.substring(0, s.length() - "Phase".length());
+        }
+        return s;
+    }
+
     public final CharSequence getName() {
         if (name == null) {
-            String s = BasePhase.this.getClass().getSimpleName();
-            if (s.endsWith("Phase")) {
-                s = s.substring(0, s.length() - "Phase".length());
-            }
-            name = s;
+            name = createName();
         }
         return name;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri May 02 11:33:47 2014 +0200
@@ -888,37 +888,114 @@
         return true;
     }
 
+    private static class SortState {
+        private Block block;
+        private NodeBitMap visited;
+        private NodeBitMap beforeLastLocation;
+        private List<ScheduledNode> sortedInstructions;
+        private List<FloatingReadNode> reads;
+
+        SortState(Block block, NodeBitMap visited, NodeBitMap beforeLastLocation, List<ScheduledNode> sortedInstructions) {
+            this.block = block;
+            this.visited = visited;
+            this.beforeLastLocation = beforeLastLocation;
+            this.sortedInstructions = sortedInstructions;
+            this.reads = null;
+        }
+
+        public Block currentBlock() {
+            return block;
+        }
+
+        void markVisited(Node n) {
+            visited.mark(n);
+        }
+
+        boolean isVisited(Node n) {
+            return visited.isMarked(n);
+        }
+
+        void markBeforeLastLocation(FloatingReadNode n) {
+            beforeLastLocation.mark(n);
+        }
+
+        void clearBeforeLastLocation(FloatingReadNode frn) {
+            beforeLastLocation.clear(frn);
+        }
+
+        boolean isBeforeLastLocation(FloatingReadNode n) {
+            return beforeLastLocation.isMarked(n);
+        }
+
+        void addRead(FloatingReadNode n) {
+            if (reads == null) {
+                reads = new ArrayList<>();
+            }
+            reads.add(n);
+        }
+
+        int readsSize() {
+            if (reads == null) {
+                return 0;
+            }
+            return reads.size();
+        }
+
+        void removeRead(ScheduledNode i) {
+            assert reads != null;
+            reads.remove(i);
+        }
+
+        List<FloatingReadNode> readsSnapshot() {
+            assert reads != null;
+            return new ArrayList<>(reads);
+        }
+
+        List<ScheduledNode> getSortedInstructions() {
+            return sortedInstructions;
+        }
+
+        boolean containsInstruction(ScheduledNode i) {
+            return sortedInstructions.contains(i);
+        }
+
+        void addInstruction(ScheduledNode i) {
+            sortedInstructions.add(i);
+        }
+    }
+
     /**
      * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over
      * all inputs. This means that a node is added to the list after all its inputs have been
      * processed.
      */
     private List<ScheduledNode> sortNodesWithinBlockLatest(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation) {
+        SortState state = new SortState(b, visited, beforeLastLocation, new ArrayList<>(blockToNodesMap.get(b).size() + 2));
         List<ScheduledNode> instructions = blockToNodesMap.get(b);
-        List<ScheduledNode> sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2);
-        List<FloatingReadNode> reads = new ArrayList<>();
 
         if (memsched == MemoryScheduling.OPTIMAL) {
             for (ScheduledNode i : instructions) {
                 if (i instanceof FloatingReadNode) {
                     FloatingReadNode frn = (FloatingReadNode) i;
                     if (frn.location().getLocationIdentity() != FINAL_LOCATION) {
-                        reads.add(frn);
+                        state.addRead(frn);
                         if (nodesFor(b).contains(frn.getLastLocationAccess())) {
-                            assert !beforeLastLocation.isMarked(frn);
-                            beforeLastLocation.mark(frn);
+                            assert !state.isBeforeLastLocation(frn);
+                            state.markBeforeLastLocation(frn);
                         }
                     }
                 }
             }
         }
+
         for (ScheduledNode i : instructions) {
-            addToLatestSorting(b, i, sortedInstructions, visited, reads, beforeLastLocation);
+            addToLatestSorting(i, state);
         }
-        assert reads.size() == 0 : "not all reads are scheduled";
+        assert state.readsSize() == 0 : "not all reads are scheduled";
 
         // Make sure that last node gets really last (i.e. when a frame state successor hangs off
         // it).
+        List<ScheduledNode> sortedInstructions = state.getSortedInstructions();
         Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1);
         if (lastSorted != b.getEndNode()) {
             int idx = sortedInstructions.indexOf(b.getEndNode());
@@ -944,40 +1021,39 @@
         return sortedInstructions;
     }
 
-    private void processKillLocation(Block b, Node node, LocationIdentity identity, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads,
-                    NodeBitMap beforeLastLocation) {
-        for (FloatingReadNode frn : new ArrayList<>(reads)) { // TODO: change to iterator?
+    private void processKillLocation(Node node, LocationIdentity identity, SortState state) {
+        for (FloatingReadNode frn : state.readsSnapshot()) {
             LocationIdentity readLocation = frn.location().getLocationIdentity();
             assert readLocation != FINAL_LOCATION;
             if (frn.getLastLocationAccess() == node) {
                 assert identity == ANY_LOCATION || readLocation == identity : "location doesn't match: " + readLocation + ", " + identity;
-                beforeLastLocation.clear(frn);
-            } else if (!beforeLastLocation.isMarked(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
-                reads.remove(frn);
-                addToLatestSorting(b, frn, sortedInstructions, visited, reads, beforeLastLocation);
+                state.clearBeforeLastLocation(frn);
+            } else if (!state.isBeforeLastLocation(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) {
+                state.removeRead(frn);
+                addToLatestSorting(frn, state);
             }
         }
     }
 
-    private void addUnscheduledToLatestSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) {
+    private void addUnscheduledToLatestSorting(VirtualState state, SortState sortState) {
         if (state != null) {
             // UnscheduledNodes should never be marked as visited.
-            if (visited.isMarked(state)) {
+            if (sortState.isVisited(state)) {
                 throw new SchedulingError();
             }
 
             for (Node input : state.inputs()) {
                 if (input instanceof VirtualState) {
-                    addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addUnscheduledToLatestSorting((VirtualState) input, sortState);
                 } else {
-                    addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addToLatestSorting((ScheduledNode) input, sortState);
                 }
             }
         }
     }
 
-    private void addToLatestSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) {
-        if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode) {
+    private void addToLatestSorting(ScheduledNode i, SortState state) {
+        if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) {
             return;
         }
 
@@ -988,45 +1064,45 @@
 
         if (i instanceof LoopExitNode) {
             for (ProxyNode proxy : ((LoopExitNode) i).proxies()) {
-                addToLatestSorting(b, proxy, sortedInstructions, visited, reads, beforeLastLocation);
+                addToLatestSorting(proxy, state);
             }
         }
 
         for (Node input : i.inputs()) {
             if (input instanceof FrameState) {
                 if (input != stateAfter) {
-                    addUnscheduledToLatestSorting(b, (FrameState) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addUnscheduledToLatestSorting((FrameState) input, state);
                 }
             } else {
                 if (!(i instanceof ProxyNode && input instanceof LoopExitNode)) {
-                    addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+                    addToLatestSorting((ScheduledNode) input, state);
                 }
             }
         }
 
-        if (memsched == MemoryScheduling.OPTIMAL && reads.size() != 0) {
+        if (memsched == MemoryScheduling.OPTIMAL && state.readsSize() != 0) {
             if (i instanceof MemoryCheckpoint.Single) {
                 LocationIdentity identity = ((MemoryCheckpoint.Single) i).getLocationIdentity();
-                processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+                processKillLocation(i, identity, state);
             } else if (i instanceof MemoryCheckpoint.Multi) {
                 for (LocationIdentity identity : ((MemoryCheckpoint.Multi) i).getLocationIdentities()) {
-                    processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation);
+                    processKillLocation(i, identity, state);
                 }
             }
             assert MemoryCheckpoint.TypeAssertion.correctType(i);
         }
 
-        addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited, reads, beforeLastLocation);
-        visited.mark(i);
-        addUnscheduledToLatestSorting(b, stateAfter, sortedInstructions, visited, reads, beforeLastLocation);
+        addToLatestSorting((ScheduledNode) i.predecessor(), state);
+        state.markVisited(i);
+        addUnscheduledToLatestSorting(stateAfter, state);
 
         // Now predecessors and inputs are scheduled => we can add this node.
-        if (!sortedInstructions.contains(i)) {
-            sortedInstructions.add(i);
+        if (!state.containsInstruction(i)) {
+            state.addInstruction(i);
         }
 
-        if (i instanceof FloatingReadNode) {
-            reads.remove(i);
+        if (state.readsSize() != 0 && i instanceof FloatingReadNode) {
+            state.removeRead(i);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java	Fri May 02 11:33:47 2014 +0200
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
@@ -37,7 +38,7 @@
 @ServiceProvider(ReplacementsProvider.class)
 public class AMD64Substitutions implements ReplacementsProvider {
 
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         if (Intrinsify.getValue()) {
             replacements.registerSubstitutions(ArraysSubstitutions.class);
             replacements.registerSubstitutions(StringSubstitutions.class);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Fri May 02 11:33:47 2014 +0200
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.replacements.test;
 
+import org.junit.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of checkcast, allowing profiling information to be manually specified.
@@ -41,7 +42,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("asNumber", profile(), 111);
         test("asNumber", profile(Integer.class), 111);
@@ -51,7 +52,7 @@
         test("asNumberExt", profile(Long.class, Short.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("asString", profile(), "111");
         test("asString", profile(String.class), "111");
@@ -67,27 +68,27 @@
         test("asStringExt", profile(String.class), "111");
     }
 
-    @LongTest
+    @Test
     public void test3() {
         test("asNumber", profile(), "111");
     }
 
-    @LongTest
+    @Test
     public void test4() {
         test("asString", profile(String.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test5() {
         test("asNumberExt", profile(), "111");
     }
 
-    @LongTest
+    @Test
     public void test6() {
         test("asStringExt", profile(String.class), 111);
     }
 
-    @LongTest
+    @Test
     public void test7() {
         Throwable throwable = new Exception();
         test("asThrowable", profile(), throwable);
@@ -95,12 +96,12 @@
         test("asThrowable", profile(Exception.class, Error.class), throwable);
     }
 
-    @LongTest
+    @Test
     public void test8() {
         test("arrayStore", new Object[100], "111");
     }
 
-    @LongTest
+    @Test
     public void test801() {
         test("arrayFill", new Object[100], "111");
     }
@@ -197,7 +198,7 @@
         return (Cloneable) o;
     }
 
-    @LongTest
+    @Test
     public void test9() {
         Object o = new Depth13();
         test("asDepth12", profile(), o);
@@ -205,7 +206,7 @@
         test("asDepth12", profile(Depth13.class, Depth14.class), o);
     }
 
-    @LongTest
+    @Test
     public void test10() {
         Object o = new Depth13[3][];
         test("asDepth12Arr", o);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java	Fri May 02 11:33:47 2014 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.replacements.test;
 
+import org.junit.*;
+
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests for {@link InstanceOfDynamicNode}.
@@ -35,7 +36,7 @@
         return value;
     }
 
-    @LongTest
+    @Test
     public void test100() {
         final Object nul = null;
         test("isStringDynamic", nul);
@@ -43,7 +44,7 @@
         test("isStringDynamic", Object.class);
     }
 
-    @LongTest
+    @Test
     public void test101() {
         final Object nul = null;
         test("isStringIntDynamic", nul);
@@ -51,7 +52,7 @@
         test("isStringIntDynamic", Object.class);
     }
 
-    @LongTest
+    @Test
     public void test103() {
         test("isInstanceDynamic", String.class, null);
         test("isInstanceDynamic", String.class, "object");
@@ -61,7 +62,7 @@
         test("isInstanceDynamic", int.class, Object.class);
     }
 
-    @LongTest
+    @Test
     public void test104() {
         test("isInstanceIntDynamic", String.class, null);
         test("isInstanceIntDynamic", String.class, "object");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Fri May 02 11:33:47 2014 +0200
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.Mark;
 import com.oracle.graal.api.code.CompilationResult.Site;
@@ -34,7 +36,6 @@
 import com.oracle.graal.replacements.test.CheckCastTest.Depth12;
 import com.oracle.graal.replacements.test.CheckCastTest.Depth13;
 import com.oracle.graal.replacements.test.CheckCastTest.Depth14;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of instanceof, allowing profiling information to be manually specified.
@@ -54,7 +55,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("isString", profile(), "object");
         test("isString", profile(String.class), "object");
@@ -63,7 +64,7 @@
         test("isString", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("isStringInt", profile(), "object");
         test("isStringInt", profile(String.class), "object");
@@ -72,7 +73,7 @@
         test("isStringInt", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test201() {
         test("isStringIntComplex", profile(), "object");
         test("isStringIntComplex", profile(String.class), "object");
@@ -81,7 +82,7 @@
         test("isStringIntComplex", profile(String.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test3() {
         Throwable throwable = new Exception();
         test("isThrowable", profile(), throwable);
@@ -93,7 +94,7 @@
         test("isThrowable", profile(Exception.class, Error.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test301() {
         onlyFirstIsException(new Exception(), new Error());
         test("onlyFirstIsException", profile(), new Exception(), new Error());
@@ -102,7 +103,7 @@
         test("onlyFirstIsException", profile(), new Error(), new Error());
     }
 
-    @LongTest
+    @Test
     public void test4() {
         Throwable throwable = new Exception();
         test("isThrowableInt", profile(), throwable);
@@ -114,7 +115,7 @@
         test("isThrowableInt", profile(Exception.class, Error.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test5() {
         Map<?, ?> map = new HashMap<>();
         test("isMap", profile(), map);
@@ -127,7 +128,7 @@
         test("isMap", profile(String.class, HashMap.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test6() {
         Map<?, ?> map = new HashMap<>();
         test("isMapInt", profile(), map);
@@ -139,7 +140,7 @@
         test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class);
     }
 
-    @LongTest
+    @Test
     public void test7() {
         Object o = new Depth13();
         test("isDepth12", profile(), o);
@@ -153,7 +154,7 @@
         test("isDepth12", profile(String.class, HashMap.class), o);
     }
 
-    @LongTest
+    @Test
     public void test8() {
         Object o = new Depth13();
         test("isDepth12Int", profile(), o);
@@ -259,7 +260,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test9() {
         MyCall callAt63 = new MyCall(63);
         MyMark markAt63 = new MyMark(63);
@@ -276,11 +277,10 @@
         return s1.offset - s2.offset;
     }
 
-    @LongTest
+    @Test
     public void test10() {
-        Mark[] noMarks = {};
         Call callAt63 = new Call(null, 63, 5, true, null);
-        Mark markAt63 = new Mark(63, "1", noMarks);
+        Mark markAt63 = new Mark(63, "1");
         test("compareSites", callAt63, callAt63);
         test("compareSites", callAt63, markAt63);
         test("compareSites", markAt63, callAt63);
@@ -301,7 +301,7 @@
      * The test exists in this source file as the transformation was originally motivated by the
      * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}.
      */
-    @LongTest
+    @Test
     public void testRemoveIntermediateMaterialization() {
         List<String> list = Arrays.asList("1", "2", "3", "4");
         test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no");
@@ -356,7 +356,7 @@
         return o instanceof D[];
     }
 
-    @LongTest
+    @Test
     public void testArray() {
         Object aArray = new A[10];
         test("isArrayOfA", aArray);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java	Fri May 02 11:33:47 2014 +0200
@@ -25,7 +25,6 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of {@code [A]NEWARRAY}.
@@ -58,7 +57,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) {
             test("new" + type + "Array7");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java	Fri May 02 11:33:47 2014 +0200
@@ -27,7 +27,6 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the implementation of {@code NEW}.
@@ -57,12 +56,12 @@
         }
     }
 
-    @LongTest
+    @Test
     public void test1() {
         test("newObject");
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("newObjectTwice");
     }
@@ -71,37 +70,37 @@
         return new Object();
     }
 
-    @LongTest
+    @Test
     public void test3() {
         test("newObjectLoop", 100);
     }
 
-    @LongTest
+    @Test
     public void test4() {
         test("newBigObject");
     }
 
-    @LongTest
+    @Test
     public void test5() {
         test("newSomeObject");
     }
 
-    @LongTest
+    @Test
     public void test6() {
         test("newEmptyString");
     }
 
-    @LongTest
+    @Test
     public void test7() {
         test("newString", "value");
     }
 
-    @LongTest
+    @Test
     public void test8() {
         test("newHashMap", 31);
     }
 
-    @LongTest
+    @Test
     public void test9() {
         test("newRegression", true);
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Fri May 02 11:33:47 2014 +0200
@@ -25,12 +25,13 @@
 import java.lang.reflect.*;
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.test.*;
 
 /**
  * Tests the lowering of the MULTIANEWARRAY instruction.
@@ -86,7 +87,7 @@
     Class<?> bottomClass;
     int[] dimensions;
 
-    @LongTest
+    @Test
     public void test1() {
         for (Class<?> clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) {
             bottomClass = clazz;
@@ -117,7 +118,7 @@
         return new Object[10][9][8];
     }
 
-    @LongTest
+    @Test
     public void test2() {
         test("newMultiArrayException");
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Fri May 02 11:33:47 2014 +0200
@@ -24,6 +24,8 @@
 
 import java.lang.reflect.*;
 
+import org.junit.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
@@ -31,7 +33,6 @@
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
-import com.oracle.graal.test.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -53,7 +54,7 @@
         return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
-    @LongTest
+    @Test
     public void construction() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
                         Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -65,7 +66,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void testArithmetic() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L,
                         Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L};
@@ -102,7 +103,7 @@
         }
     }
 
-    @LongTest
+    @Test
     public void testCompare() {
         long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE};
         for (long word1 : words) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Fri May 02 11:33:47 2014 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -35,7 +36,7 @@
 @ServiceProvider(ReplacementsProvider.class)
 public class GraalMethodSubstitutions implements ReplacementsProvider {
 
-    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) {
+    public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         for (Class<?> clazz : BoxingSubstitutions.getClasses()) {
             replacements.registerSubstitutions(clazz);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java	Fri May 02 11:33:47 2014 +0200
@@ -32,15 +32,13 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.replacements.Snippet.Fold;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
 
 /**
  * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering
  * snippet specific metrics.
  */
 public class SnippetCounter implements Comparable<SnippetCounter> {
-    private static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
-
     /**
      * A group of related counters.
      */
@@ -107,7 +105,7 @@
 
     /**
      * Creates a counter.
-     * 
+     *
      * @param group the group to which the counter belongs. If this is null, the newly created
      *            counter is disabled and {@linkplain #inc() incrementing} is a no-op.
      * @param name the name of the counter
@@ -130,12 +128,20 @@
     }
 
     /**
+     * We do not want to use the {@link LocationIdentity} of the {@link #value} field, so that the
+     * usage in snippets is always possible. If a method accesses the counter via the field and the
+     * snippet, the result might not be correct though.
+     */
+    protected static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter");
+
+    /**
      * Increments the value of this counter. This method can be safely used in a snippet if it is
      * invoked on a compile-time constant {@link SnippetCounter} object.
      */
     public void inc() {
         if (group != null) {
-            DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, SNIPPET_COUNTER_LOCATION);
+            long loadedValue = ObjectAccess.readLong(this, countOffset(), SNIPPET_COUNTER_LOCATION);
+            ObjectAccess.writeLong(this, countOffset(), loadedValue + 1, SNIPPET_COUNTER_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri May 02 11:33:47 2014 +0200
@@ -23,9 +23,11 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
+
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.debug.Debug.*;
 import static java.util.FormattableFlags.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -40,8 +42,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -965,7 +967,15 @@
          * if no FloatingReadNode is reading from this location, the kill to this location is fine.
          */
         for (FloatingReadNode frn : replacee.graph().getNodes(FloatingReadNode.class)) {
-            assert !(kills.contains(frn.location().getLocationIdentity())) : frn + " reads from " + frn.location().getLocationIdentity() + " but " + replacee + " does not kill this location";
+            LocationIdentity locationIdentity = frn.location().getLocationIdentity();
+            if (SnippetCounters.getValue()) {
+                // accesses to snippet counters are artificially introduced and violate the memory
+                // semantics.
+                if (locationIdentity == SnippetCounter.SNIPPET_COUNTER_LOCATION) {
+                    continue;
+                }
+            }
+            assert !kills.contains(locationIdentity) : frn + " reads from location \"" + locationIdentity + "\" but " + replacee + " does not kill this location";
         }
         return true;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
@@ -36,7 +34,7 @@
 /**
  * Compares two arrays with the same length.
  */
-public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable {
+public class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable {
 
     /** {@link Kind} of the arrays to compare. */
     private final Kind kind;
@@ -131,7 +129,7 @@
     public static native boolean equals(double[] array1, double[] array2, int length);
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitCountNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -65,7 +64,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitCount(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanForwardNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -72,7 +71,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.emitBitScanForward(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class BitScanReverseNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -79,7 +78,7 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(Kind.Int);
         gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value));
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Fri May 02 11:33:47 2014 +0200
@@ -24,15 +24,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable {
+public class ReverseBytesNode extends FloatingNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode value;
 
@@ -66,9 +65,9 @@
     }
 
     @Override
-    public void generate(NodeLIRBuilder gen) {
+    public void generate(NodeLIRBuilderTool gen) {
         Variable result = gen.newVariable(value.getKind());
-        gen.getLIRGenerator().emitByteSwap(result, gen.operand(value));
+        gen.getLIRGeneratorTool().emitByteSwap(result, gen.operand(value));
         gen.setResult(this, result);
     }
 }
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,28 +35,28 @@
  */
 public class SPARC extends Architecture {
 
-    // @formatter:off
-
     public static final RegisterCategory CPU = new RegisterCategory("CPU");
     public static final RegisterCategory FPU = new RegisterCategory("FPU");
 
     // General purpose registers
-    public static final Register r0  = new Register(0, 0, "g0", CPU);
-    public static final Register r1  = new Register(1, 1, "g1", CPU);
-    public static final Register r2  = new Register(2, 2, "g2", CPU);
-    public static final Register r3  = new Register(3, 3, "g3", CPU);
-    public static final Register r4  = new Register(4, 4, "g4", CPU);
-    public static final Register r5  = new Register(5, 5, "g5", CPU);
-    public static final Register r6  = new Register(6, 6, "g6", CPU);
-    public static final Register r7  = new Register(7, 7, "g7", CPU);
-    public static final Register r8  = new Register(8, 8, "o0", CPU);
-    public static final Register r9  = new Register(9, 9, "o1", CPU);
+    public static final Register r0 = new Register(0, 0, "g0", CPU);
+    public static final Register r1 = new Register(1, 1, "g1", CPU);
+    public static final Register r2 = new Register(2, 2, "g2", CPU);
+    public static final Register r3 = new Register(3, 3, "g3", CPU);
+    public static final Register r4 = new Register(4, 4, "g4", CPU);
+    public static final Register r5 = new Register(5, 5, "g5", CPU);
+    public static final Register r6 = new Register(6, 6, "g6", CPU);
+    public static final Register r7 = new Register(7, 7, "g7", CPU);
+
+    public static final Register r8 = new Register(8, 8, "o0", CPU);
+    public static final Register r9 = new Register(9, 9, "o1", CPU);
     public static final Register r10 = new Register(10, 10, "o2", CPU);
     public static final Register r11 = new Register(11, 11, "o3", CPU);
     public static final Register r12 = new Register(12, 12, "o4", CPU);
     public static final Register r13 = new Register(13, 13, "o5", CPU);
     public static final Register r14 = new Register(14, 14, "o6", CPU);
     public static final Register r15 = new Register(15, 15, "o7", CPU);
+
     public static final Register r16 = new Register(16, 16, "l0", CPU);
     public static final Register r17 = new Register(17, 17, "l1", CPU);
     public static final Register r18 = new Register(18, 18, "l2", CPU);
@@ -65,6 +65,7 @@
     public static final Register r21 = new Register(21, 21, "l5", CPU);
     public static final Register r22 = new Register(22, 22, "l6", CPU);
     public static final Register r23 = new Register(23, 23, "l7", CPU);
+
     public static final Register r24 = new Register(24, 24, "i0", CPU);
     public static final Register r25 = new Register(25, 25, "i1", CPU);
     public static final Register r26 = new Register(26, 26, "i2", CPU);
@@ -113,12 +114,14 @@
     public static final Register sp = o6;
     public static final Register fp = i6;
 
+    // @formatter:off
     public static final Register[] cpuRegisters = {
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
         r8,  r9,  r10, r11, r12, r13, r14, r15,
         r16, r17, r18, r19, r20, r21, r22, r23,
         r24, r25, r26, r27, r28, r29, r30, r31
     };
+    // @formatter:on
 
     // Floating point registers
     public static final Register f0 = new Register(32, 0, "f0", FPU);
@@ -130,6 +133,43 @@
     public static final Register f6 = new Register(38, 6, "f6", FPU);
     public static final Register f7 = new Register(39, 7, "f7", FPU);
 
+    public static final Register f8 = new Register(40, 8, "f8", FPU);
+    public static final Register f9 = new Register(41, 9, "f9", FPU);
+    public static final Register f10 = new Register(42, 10, "f10", FPU);
+    public static final Register f11 = new Register(43, 11, "f11", FPU);
+    public static final Register f12 = new Register(44, 12, "f12", FPU);
+    public static final Register f13 = new Register(45, 13, "f13", FPU);
+    public static final Register f14 = new Register(46, 14, "f14", FPU);
+    public static final Register f15 = new Register(47, 15, "f15", FPU);
+
+    public static final Register f16 = new Register(48, 16, "f16", FPU);
+    public static final Register f17 = new Register(49, 17, "f17", FPU);
+    public static final Register f18 = new Register(50, 18, "f18", FPU);
+    public static final Register f19 = new Register(51, 19, "f19", FPU);
+    public static final Register f20 = new Register(52, 20, "f20", FPU);
+    public static final Register f21 = new Register(53, 21, "f21", FPU);
+    public static final Register f22 = new Register(54, 22, "f22", FPU);
+    public static final Register f23 = new Register(55, 23, "f23", FPU);
+
+    public static final Register f24 = new Register(56, 24, "f24", FPU);
+    public static final Register f25 = new Register(57, 25, "f25", FPU);
+    public static final Register f26 = new Register(58, 26, "f26", FPU);
+    public static final Register f27 = new Register(59, 27, "f27", FPU);
+    public static final Register f28 = new Register(60, 28, "f28", FPU);
+    public static final Register f29 = new Register(61, 29, "f29", FPU);
+    public static final Register f30 = new Register(62, 30, "f30", FPU);
+    public static final Register f31 = new Register(63, 31, "f31", FPU);
+
+    // @formatter:off
+    public static final Register[] fpuRegisters = {
+        f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+        f8,  f9,  f10, f11, f12, f13, f14, f15,
+        f16, f17, f18, f19, f20, f21, f22, f23,
+        f24, f25, f26, f27, f28, f29, f30, f31
+    };
+    // @formatter:on
+
+    // @formatter:off
     public static final Register[] allRegisters = {
         // CPU
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
@@ -138,9 +178,16 @@
         r24, r25, r26, r27, r28, r29, r30, r31,
         // FPU
         f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
+        f8,  f9,  f10, f11, f12, f13, f14, f15,
+        f16, f17, f18, f19, f20, f21, f22, f23,
+        f24, f25, f26, f27, f28, f29, f30, f31
     };
+    // @formatter:on
 
-    // @formatter:on
+    /**
+     * Stack bias for stack and frame pointer loads.
+     */
+    public static final int STACK_BIAS = 0x7ff;
 
     public SPARC() {
         super("SPARC", 8, ByteOrder.BIG_ENDIAN, false, allRegisters, LOAD_STORE | STORE_STORE, 1, r31.encoding + 1, 8);
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.test;
-
-import java.util.*;
-
-import org.junit.*;
-import org.junit.runners.*;
-import org.junit.runners.model.*;
-
-public class GraalLongUnitTest extends BlockJUnit4ClassRunner {
-
-    public GraalLongUnitTest(Class<?> klass) throws InitializationError {
-        super(klass);
-    }
-
-    @Override
-    protected List<FrameworkMethod> computeTestMethods() {
-        List<FrameworkMethod> methods = new ArrayList<>(5);
-        methods.addAll(getTestClass().getAnnotatedMethods(Test.class));
-        methods.addAll(getTestClass().getAnnotatedMethods(LongTest.class));
-        return methods;
-    }
-}
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java	Fri May 02 11:33:47 2014 +0200
@@ -26,14 +26,12 @@
 import java.util.*;
 
 import org.junit.*;
-import org.junit.runner.*;
 
 /**
  * Base class for Graal tests.
  * <p>
  * This contains common utility methods that are used in multiple test projects.
  */
-@RunWith(GraalLongUnitTest.class)
 public class GraalTest {
 
     protected Method getMethod(String methodName) {
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.test;
-
-import java.lang.annotation.*;
-
-/* copy of org.junit.Test */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface LongTest {
-
-    static final class None extends Throwable {
-
-        private static final long serialVersionUID = 1L;
-
-        private None() {
-        }
-    }
-
-    Class<? extends Throwable> expected() default None.class;
-
-    long timeout() default 0L;
-}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Fri May 02 11:33:47 2014 +0200
@@ -88,13 +88,12 @@
 
     public abstract CallTarget getTargetCallTarget();
 
-    public DirectCallNode getCallNode() {
+    public Node getCallNode() {
         Object receiver = stackFrame.getLocal(getNotifyIndex());
-        if (receiver instanceof DirectCallNode) {
-            return (DirectCallNode) receiver;
-        } else {
-            return null;
+        if (receiver instanceof DirectCallNode || receiver instanceof IndirectCallNode) {
+            return (Node) receiver;
         }
+        return null;
     }
 
     /**
@@ -146,10 +145,9 @@
     }
 
     /**
-     * This class represents a frame that is taken from the
-     * {@link RootCallTarget#callProxy(VirtualFrame)} method.
+     * This class represents a frame that is taken from the {@link OptimizedCallTarget#callProxy}
+     * method.
      */
-    @SuppressWarnings("javadoc")
     public static final class CallTargetFrame extends HotSpotFrameInstance {
         public static final Method METHOD;
         static {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Fri May 02 11:33:47 2014 +0200
@@ -241,7 +241,6 @@
         if (inliningPerformed) {
             return;
         }
-        inliningPerformed = true;
         TruffleInliningHandler handler = new TruffleInliningHandler(new DefaultInliningPolicy());
         TruffleInliningResult result = handler.decideInlining(this, 0);
         performInlining(result);
@@ -249,6 +248,10 @@
     }
 
     private static void performInlining(TruffleInliningResult result) {
+        if (result.getCallTarget().inliningPerformed) {
+            return;
+        }
+        result.getCallTarget().inliningPerformed = true;
         for (TruffleInliningProfile profile : result) {
             profile.getCallNode().inline();
             TruffleInliningResult recursiveResult = profile.getRecursiveResult();
@@ -272,7 +275,7 @@
         if (profiledReturnTypeAssumption == null) {
             if (TruffleReturnTypeSpeculation.getValue()) {
                 CompilerDirectives.transferToInterpreter();
-                profiledReturnType = result.getClass();
+                profiledReturnType = (result == null ? null : result.getClass());
                 profiledReturnTypeAssumption = Truffle.getRuntime().createAssumption("Profiled Return Type");
             }
         } else if (profiledReturnType != null) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri May 02 11:33:47 2014 +0200
@@ -63,7 +63,7 @@
     private final RuntimeProvider runtime;
     private final TruffleCache truffleCache;
 
-    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class};
+    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class};
 
     public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
                     OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri May 02 11:33:47 2014 +0200
@@ -54,7 +54,7 @@
     @Option(help = "Enable automatic inlining of call targets")
     public static final OptionValue<Boolean> TruffleFunctionInlining = new OptionValue<>(true);
     @Option(help = "Maximum number of Graal IR nodes during partial evaluation")
-    public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(45000);
+    public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(200000);
     @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit")
     public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2250);
     @Option(help = "Skip inlining candidate if its tree size exceeds this limit")
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Fri May 02 11:33:47 2014 +0200
@@ -94,7 +94,7 @@
         int deepNodeCount;
         TruffleInliningResult recursiveResult;
         boolean recursiveCall = false;
-        if (depth > MAXIMUM_RECURSIVE_DEPTH) {
+        if (target.inliningPerformed || depth > MAXIMUM_RECURSIVE_DEPTH) {
             deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true);
             recursiveResult = null;
         } else {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Fri May 02 11:33:47 2014 +0200
@@ -23,11 +23,10 @@
 package com.oracle.graal.truffle.nodes.frame;
 
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 
-public class ForceMaterializeNode extends FixedWithNextNode implements LIRGenLowerable {
+public class ForceMaterializeNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input private ValueNode object;
 
@@ -36,7 +35,7 @@
         this.object = object;
     }
 
-    public void generate(NodeLIRBuilder generator) {
+    public void generate(NodeLIRBuilderTool generator) {
         // nothing to do
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri May 02 11:33:47 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.truffle.nodes.asserts.*;
 import com.oracle.truffle.api.*;
 
@@ -62,7 +61,7 @@
             }
             Stamp stamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0);
             ConditionAnchorNode valueAnchorNode = graph().add(new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
-            UnsafeCastNode piCast = graph().unique(new UnsafeCastNode(objectArgument, stamp, valueAnchorNode));
+            PiNode piCast = graph().unique(new PiNode(objectArgument, stamp, valueAnchorNode));
             this.replaceAtUsages(piCast);
             return valueAnchorNode;
         }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Fri May 02 11:33:47 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
 import com.oracle.graal.phases.tiers.*;
 
 public class IterativeInliningPhase extends AbstractInliningPhase {
@@ -70,9 +71,14 @@
 
                 new DeadCodeEliminationPhase().apply(graph);
 
-                if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+                boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue();
+                if (reduceOrEliminate && OptCanonicalizer.getValue()) {
                     canonicalizer.apply(graph, context);
-                    new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+                    if (FlowSensitiveReduction.getValue()) {
+                        new IterativeFlowSensitiveReductionPhase(canonicalizer).apply(graph, context);
+                    } else {
+                        new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
+                    }
                 }
                 if (!progress) {
                     break;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri May 02 11:33:47 2014 +0200
@@ -579,15 +579,29 @@
                 } else {
                     // all inputs are virtual: check if they're compatible and without identity
                     boolean compatible = true;
+                    boolean hasIdentity = false;
                     ObjectState firstObj = objStates[0];
                     for (int i = 0; i < objStates.length; i++) {
                         ObjectState obj = objStates[i];
-                        boolean hasIdentity = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
-                        if (hasIdentity || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
+                        hasIdentity |= obj.virtual.hasIdentity();
+                        boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual);
+                        if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) {
                             compatible = false;
                             break;
                         }
                     }
+                    if (compatible && hasIdentity) {
+                        // we still need to check whether this value is referenced by any other phi
+                        outer: for (PhiNode otherPhi : merge.phis().filter(otherPhi -> otherPhi != phi)) {
+                            for (int i = 0; i < objStates.length; i++) {
+                                ObjectState otherPhiValueState = getObjectState(states.get(i), otherPhi.valueAt(i));
+                                if (Arrays.asList(objStates).contains(otherPhiValueState)) {
+                                    compatible = false;
+                                    break outer;
+                                }
+                            }
+                        }
+                    }
 
                     if (compatible) {
                         VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Inserting Extra Nodes into the AST Transparently</h3>
+ * 
+ * <p>
+ * The {@link Node} class provides a callback that is invoked whenever a node is adopted in an AST
+ * by insertion or replacement. Node classes can override the {@code onAdopt()} method to run extra
+ * functionality upon adoption.
+ * </p>
+ * 
+ * <p>
+ * This test demonstrates how node instances of a specific class can be automatically wrapped in
+ * extra nodes when they are inserted into the AST.
+ * </p>
+ */
+public class OnAdoptTest {
+
+    static class Root extends RootNode {
+
+        @Child private Base child1;
+        @Child private Base child2;
+
+        public Root(Base child1, Base child2) {
+            super(null);
+            this.child1 = child1;
+            this.child2 = child2;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return child1.executeInt(frame) + child2.executeInt(frame);
+        }
+
+    }
+
+    abstract static class Base extends Node {
+        public abstract int executeInt(VirtualFrame frame);
+    }
+
+    static class Wrapper extends Base {
+
+        @Child private Base wrappee;
+
+        public Wrapper(Base wrappee) {
+            this.wrappee = wrappee;
+        }
+
+        @Override
+        public int executeInt(VirtualFrame frame) {
+            return 1 + wrappee.executeInt(frame);
+        }
+
+    }
+
+    abstract static class GenBase extends Base {
+
+        private final int k;
+
+        public GenBase(int k) {
+            this.k = k;
+        }
+
+        @Override
+        public int executeInt(VirtualFrame frame) {
+            return k;
+        }
+
+    }
+
+    static class Gen extends GenBase {
+        public Gen(int k) {
+            super(k);
+        }
+    }
+
+    static class GenWrapped extends GenBase {
+
+        public GenWrapped(int k) {
+            super(k);
+        }
+
+        @Override
+        protected void onAdopt() {
+            Wrapper w = new Wrapper(this);
+            this.replace(w);
+        }
+
+    }
+
+    @Test
+    public void testOnInsert() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        Base b1 = new Gen(11);
+        Base b2 = new GenWrapped(11);
+        Root r = new Root(b1, b2);
+        CallTarget ct = runtime.createCallTarget(r);
+        Object result = ct.call();
+        Assert.assertEquals(23, result);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Fri May 02 11:33:47 2014 +0200
@@ -49,12 +49,12 @@
     /**
      * Gets access to AST instrumentation services.
      */
-    Instrumentation instrumentation();
+    Instrumentation getInstrumentation();
 
     /**
      * Access to information visualization services for the specific language.
      */
-    Visualizer visualizer();
+    Visualizer getVisualizer();
 
     /**
      * Add instrumentation to subsequently constructed Truffle ASTs for the guest language; every
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java	Fri May 02 11:33:47 2014 +0200
@@ -34,12 +34,21 @@
     /**
      * Returns the name of this resource holding a guest language program. An example would be the
      * name of a guest language source code file.
-     * 
+     *
      * @return the name of the guest language program
      */
     String getName();
 
     /**
+     * Returns a short version of the name of the resource holding a guest language program (as
+     * described in @getName). For example, this could be just the name of the file, rather than a
+     * full path.
+     *
+     * @return the short name of the guest language program
+     */
+    String getShortName();
+
+    /**
      * The normalized, canonical name of the file.
      */
     String getPath();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Fri May 02 11:33:47 2014 +0200
@@ -31,21 +31,21 @@
 
     /**
      * Returns the object representing the source program that contains this section.
-     * 
+     *
      * @return the source object
      */
     Source getSource();
 
     /**
      * Returns 1-based line number of the first character in this source section (inclusive).
-     * 
+     *
      * @return the starting line number
      */
     int getStartLine();
 
     /**
      * Returns the 1-based column number of the first character in this source section (inclusive).
-     * 
+     *
      * @return the starting column number
      */
     int getStartColumn();
@@ -55,7 +55,7 @@
      * <p>
      * The complete text of the source that contains this section can be retrieved via
      * {@link Source#getCode()}.
-     * 
+     *
      * @return the starting character index
      */
     int getCharIndex();
@@ -65,7 +65,7 @@
      * <p>
      * The complete text of the source that contains this section can be retrieved via
      * {@link Source#getCode()}.
-     * 
+     *
      * @return the number of characters in the section
      */
     int getCharLength();
@@ -73,42 +73,54 @@
     /**
      * Returns the index of the text position immediately following the last character in the
      * section.
-     * 
+     *
      * @return the end position of the section
      */
     int getCharEndIndex();
 
     /**
      * Returns the identifier of this source section that is used for printing the section.
-     * 
+     *
      * @return the identifier of the section
      */
     String getIdentifier();
 
     /**
      * Returns text of the code represented by this source section.
-     * 
+     *
      * @return the code as a String object
      */
     String getCode();
 
     /**
+     * Returns a short description of the source section, using just the file name, rather than its
+     * full path.
+     *
+     * @return a short description of the source section
+     */
+    String getShortDescription();
+
+    /**
      * Singleton instance with no content.
      */
     SourceSection NULL = new NullSourceSection() {
 
+        @Override
         public Source getSource() {
             return null;
         }
 
+        @Override
         public int getStartLine() {
             return 0;
         }
 
+        @Override
         public int getStartColumn() {
             return 0;
         }
 
+        @Override
         public int getCharIndex() {
             return 0;
         }
@@ -118,18 +130,26 @@
             return 0;
         }
 
+        @Override
         public int getCharEndIndex() {
             return 0;
         }
 
+        @Override
         public String getIdentifier() {
             return null;
         }
 
+        @Override
         public String getCode() {
             return null;
         }
 
+        @Override
+        public String getShortDescription() {
+            return "short";
+        }
+
     };
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java	Fri May 02 11:33:47 2014 +0200
@@ -40,9 +40,7 @@
 
     boolean isVirtualFrame();
 
-    DirectCallNode getCallNode();
+    Node getCallNode();
 
     CallTarget getCallTarget();
-
-    CallTarget getTargetCallTarget();
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java	Fri May 02 11:33:47 2014 +0200
@@ -44,11 +44,11 @@
         return sourceManager;
     }
 
-    public final Instrumentation instrumentation() {
+    public final Instrumentation getInstrumentation() {
         return instrumentation;
     }
 
-    public Visualizer visualizer() {
+    public Visualizer getVisualizer() {
         return visualizer;
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java	Fri May 02 11:33:47 2014 +0200
@@ -53,7 +53,7 @@
      * a character index. The (row,column) coordinates of a newline character should never appear in
      * a text section.
      * <p>
-     * 
+     *
      * @param source object representing the complete source program that contains this section
      * @param identifier an identifier used when printing the section
      * @param startLine the 1-based number of the start line of the section
@@ -102,6 +102,10 @@
         return getSource().getCode().substring(charIndex, charIndex + charLength);
     }
 
+    public final String getShortDescription() {
+        return String.format("%s:%d", source.getShortName(), startLine);
+    }
+
     @Override
     public String toString() {
         return String.format("%s:%d", source.getName(), startLine);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri May 02 11:33:47 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,17 +24,103 @@
  */
 package com.oracle.truffle.api.instrument;
 
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+
 /**
  * A receiver of Truffle AST {@link ExecutionEvents}, propagated from a {@link Probe} to which the
- * instrument is attached.
+ * instrument is attached, for the benefit of associated <em>tools</em>.
  * <p>
- * <strong>Disclaimer:</strong> experimental interface under development.
+ * Guidelines for implementing Instruments, with particular attention to avoiding undesired runtime
+ * performance overhead:
+ * <ol>
+ * <li>Extend {@link Instrument} and override only the event handling methods for which some action
+ * is needed.</li>
+ * <li>Instruments are Truffle {@link Node}s and should be coded as much as possible in the desired
+ * <em>Truffle style</em>, documented more thoroughly elsewhere.</li>
+ * <li>Maintain as little state as possible.</li>
+ * <li>If state is necessary, make it {@code final} if possible.</li>
+ * <li>If non-final state is necessary, annotate it as {@link CompilationFinal} and call
+ * {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.</li>
+ * <li>Never store a {@link Frame} value in a field.</li>
+ * <li>Minimize computation in standard execution paths.</li>
+ * <li>Callbacks to tools should be made via callbacks provided at construction and stored in
+ * {@code final} fields.</li>
+ * <li>Tool callback methods should usually be annotated as {@link SlowPath} to prevent them from
+ * being inlined into fast execution paths.</li>
+ * <li>If computation is needed, and if performance is important, then the computation is best
+ * expressed as a guest language AST and evaluated using standard Truffle mechanisms so that
+ * standard Truffle optimizations can be applied.</li>
+ * </ol>
+ * <p>
+ * Guidelines for attachment to a {@link Probe}:
+ * <ol>
+ * <li>An Instrument instance must only attached to a single {@link Probe}, each of which is
+ * associated uniquely with a specific syntactic unit of a guest language program, and thus
+ * (initially) to a specific {@linkplain Node Truffle AST node}.</li>
+ * <li>When the AST containing such a node is copied at runtime, the {@link Probe} will be shared by
+ * every copy, and so the Instrument will receive events corresponding to the intended syntactic
+ * unit of code, independent of which AST copy is being executed.</li>
+ * </ol>
+ *
+ * <p>
+ * <strong>Disclaimer:</strong> experimental; under development.
+ *
+ * @see Instrumentation
+ * @see Probe
+ * @see Instrument
+ * @see ASTNodeProber
  */
-public interface Instrument extends ExecutionEvents {
+public class Instrument extends InstrumentationNode {
+
+    protected Instrument() {
+    }
+
+    public void enter(Node astNode, VirtualFrame frame) {
+    }
+
+    public void leave(Node astNode, VirtualFrame frame) {
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, boolean result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, byte result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, short result) {
+        leave(astNode, frame, (Object) result);
+    }
 
-    /**
-     * @return the {@link Probe} to which this instrument is attached.
-     */
-    Probe getProbe();
+    public void leave(Node astNode, VirtualFrame frame, int result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, long result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, char result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, float result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, double result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, Object result) {
+    }
+
+    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+    }
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java	Fri May 02 11:33:47 2014 +0200
@@ -24,10 +24,18 @@
  */
 package com.oracle.truffle.api.instrument;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 
 /**
- * Visualization services for guest language and Truffle information.
+ * Visualization services for the benefit of {@link Instrumentation}-based tools, possibly
+ * specialized for each guest language and possibly specialized for relevant information from the
+ * underlying Truffle implementation.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ *
+ * @See Instrumentation
  */
 public interface Visualizer {
 
@@ -38,6 +46,21 @@
     ASTPrinter getASTPrinter();
 
     /**
+     * A short description of a source location in terms of source + line number.
+     */
+    String displaySourceLocation(Node node);
+
+    /**
+     * Describes the name of the method containing a node.
+     */
+    String displayMethodName(Node node);
+
+    /**
+     * The name of the method.
+     */
+    String displayCallTargetName(CallTarget callTarget);
+
+    /**
      * Converts a value in the guest language to a display string.
      */
     String displayValue(Object value);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrument.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument.impl;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * An {@link Instrument} that implements all {@link ExecutionEvents} notifications with empty
- * methods.
- */
-public class DefaultInstrument extends InstrumentationNodeImpl implements Instrument {
-
-    protected DefaultInstrument() {
-    }
-
-    public void enter(Node astNode, VirtualFrame frame) {
-    }
-
-    public void leave(Node astNode, VirtualFrame frame) {
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, boolean result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, byte result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, short result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, int result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, long result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, char result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, float result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, double result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, Object result) {
-    }
-
-    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java	Fri May 02 11:33:47 2014 +0200
@@ -24,8 +24,12 @@
  */
 package com.oracle.truffle.api.instrument.impl;
 
+import java.io.*;
+
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
 
 public class DefaultVisualizer implements Visualizer {
 
@@ -39,6 +43,43 @@
         return astPrinter;
     }
 
+    public String displaySourceLocation(Node node) {
+        if (node == null) {
+            return "<unknown>";
+        }
+        SourceSection section = node.getSourceSection();
+        boolean estimated = false;
+        if (section == null) {
+            section = node.getEncapsulatingSourceSection();
+            estimated = true;
+        }
+
+        String sourceString;
+        if (section == null || section.getSource() == null) {
+            sourceString = "<unknown source>";
+        } else {
+            String sourceName = new File(section.getSource().getName()).getName();
+            int startLine = section.getStartLine();
+            sourceString = String.format("%s:%d%s", sourceName, startLine, estimated ? "~" : "");
+        }
+        return sourceString;
+    }
+
+    public String displayMethodName(Node node) {
+        if (node == null) {
+            return null;
+        }
+        RootNode root = node.getRootNode();
+        if (root == null) {
+            return "unknown";
+        }
+        return root.getCallTarget().toString();
+    }
+
+    public String displayCallTargetName(CallTarget callTarget) {
+        return callTarget.toString();
+    }
+
     public String displayValue(Object value) {
         return value.toString();
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java	Fri May 02 11:33:47 2014 +0200
@@ -30,10 +30,6 @@
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.source.*;
 
-/**
- * @author mlvdv
- *
- */
 public final class InstrumentationImpl implements Instrumentation {
 
     private final ExecutionContext context;
@@ -80,7 +76,7 @@
         if (probe != null) {
             return probe;
         }
-        probe = InstrumentationNodeImpl.createProbe(this, sourceSection, eventListener);
+        probe = InstrumentationNode.createProbe(this, sourceSection, eventListener);
 
         // Register new probe by unique SourceSection
         srcToProbe.put(sourceSection, probe);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
+ * <p>
+ * Coordinates propagation of Truffle AST {@link ExecutionEvents}.
+ */
+public abstract class InstrumentationNode extends Node implements ExecutionEvents {
+
+    // TODO (mlvdv) This is a pretty awkward design; it is a priority to revise it.
+
+    /**
+     * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection}
+     * extent of guest language source code.
+     *
+     * @param eventListener an optional listener for certain instrumentation-related events.
+     * @return a new probe
+     */
+    static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
+        return new ProbeImpl(instrumentation, sourceSection, eventListener);
+    }
+
+    /**
+     * Next in chain.
+     */
+    @Child protected InstrumentationNode next;
+
+    protected InstrumentationNode() {
+    }
+
+    /**
+     * @return the instance of {@link Probe} to which this instrument is attached.
+     */
+    public Probe getProbe() {
+        final InstrumentationNode parent = (InstrumentationNode) getParent();
+        return parent == null ? null : parent.getProbe();
+    }
+
+    /**
+     * Add a probe to the end of this probe chain.
+     */
+    private void internalAddInstrument(Instrument newInstrument) {
+        if (next == null) {
+            this.next = insert(newInstrument);
+        } else {
+            next.internalAddInstrument(newInstrument);
+        }
+    }
+
+    private void internalRemoveInstrument(Instrument oldInstrument) {
+        if (next == null) {
+            throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument);
+        } else if (next == oldInstrument) {
+            if (oldInstrument.next == null) {
+                this.next = null;
+            } else {
+                this.next = insert(oldInstrument.next);
+                oldInstrument.next = null;
+            }
+        } else {
+            next.internalRemoveInstrument(oldInstrument);
+        }
+    }
+
+    /**
+     * Reports to the instance of {@link Probe} holding this instrument that some essential state
+     * has changed that requires deoptimization.
+     */
+    @CompilerDirectives.SlowPath
+    protected void notifyProbeChanged(Instrument instrument) {
+        final ProbeImpl probe = (ProbeImpl) getProbe();
+        probe.notifyProbeChanged(instrument);
+    }
+
+    private void internalEnter(Node astNode, VirtualFrame frame) {
+        enter(astNode, frame);
+        if (next != null) {
+            next.internalEnter(astNode, frame);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame) {
+        leave(astNode, frame);
+        if (next != null) {
+            next.internalLeave(astNode, frame);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, boolean result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, byte result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, short result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, int result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, long result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, char result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, float result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, double result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, Object result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+        leaveExceptional(astNode, frame, null);
+        if (next != null) {
+            next.internalLeaveExceptional(astNode, frame, e);
+        }
+    }
+
+    /**
+     * Holder of a chain of {@linkplain InstrumentationNode instruments}: manages the
+     * {@link Assumption} that none of the instruments have changed since last checked.
+     * <p>
+     * An instance is intended to be shared by every clone of the AST node with which it is
+     * originally attached, so it holds no parent pointer.
+     * <p>
+     * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful
+     * for instrumentation about its AST location(s).
+     */
+    private static final class ProbeImpl extends InstrumentationNode implements Probe {
+
+        final InstrumentationImpl instrumentation;
+
+        final InstrumentEventListener eventListener;
+
+        @CompilerDirectives.CompilationFinal private Assumption probeUnchanged;
+
+        /**
+         * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line
+         * will cause a halt.
+         */
+        @CompilerDirectives.CompilationFinal private boolean stepping;
+
+        /**
+         * Source information about the AST node to which this instrumentation is attached.
+         */
+        private final SourceSection probedSourceSection;
+
+        private final Set<PhylumTag> tags = EnumSet.noneOf(PhylumTag.class);
+
+        private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
+            this.instrumentation = instrumentation;
+            this.probedSourceSection = sourceSection;
+            this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener;
+            this.probeUnchanged = Truffle.getRuntime().createAssumption();
+            this.next = null;
+        }
+
+        @Override
+        public Probe getProbe() {
+            return this;
+        }
+
+        @Override
+        protected void notifyProbeChanged(Instrument instrument) {
+            probeUnchanged.invalidate();
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        public SourceSection getSourceLocation() {
+            return probedSourceSection;
+        }
+
+        public void tagAs(PhylumTag tag) {
+            assert tag != null;
+            if (!tags.contains(tag)) {
+                tags.add(tag);
+                instrumentation.newTagAdded(this, tag);
+            }
+        }
+
+        public boolean isTaggedAs(PhylumTag tag) {
+            assert tag != null;
+            return tags.contains(tag);
+        }
+
+        public Set<PhylumTag> getPhylumTags() {
+            return tags;
+        }
+
+        public void setStepping(boolean stepping) {
+            if (this.stepping != stepping) {
+                this.stepping = stepping;
+                probeUnchanged.invalidate();
+                probeUnchanged = Truffle.getRuntime().createAssumption();
+            }
+        }
+
+        public boolean isStepping() {
+            return stepping;
+        }
+
+        @CompilerDirectives.SlowPath
+        public void addInstrument(Instrument instrument) {
+            probeUnchanged.invalidate();
+            super.internalAddInstrument(instrument);
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        @CompilerDirectives.SlowPath
+        public void removeInstrument(Instrument instrument) {
+            probeUnchanged.invalidate();
+            super.internalRemoveInstrument(instrument);
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        public void notifyEnter(Node astNode, VirtualFrame frame) {
+            if (stepping || next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                if (stepping) {
+                    eventListener.haltedAt(astNode, frame.materialize());
+                }
+                if (next != null) {
+                    next.internalEnter(astNode, frame);
+                }
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, byte result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, short result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, int result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, long result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, char result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, float result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, double result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, Object result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeaveExceptional(astNode, frame, e);
+            }
+        }
+
+        public void enter(Node astNode, VirtualFrame frame) {
+        }
+
+        public void leave(Node astNode, VirtualFrame frame) {
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, boolean result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, byte result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, short result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, int result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, long result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, char result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, float result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, double result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, Object result) {
+        }
+
+        public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNodeImpl.java	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,448 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument.impl;
-
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
- * <p>
- * Coordinates propagation of Truffle AST {@link ExecutionEvents}.
- */
-public abstract class InstrumentationNodeImpl extends Node implements ExecutionEvents {
-
-    // TODO (mlvdv) This is a pretty awkward design.
-
-    /**
-     * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection}
-     * extent of guest language source code.
-     *
-     * @param eventListener an optional listener for certain instrumentation-related events.
-     * @return a new probe
-     */
-    static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
-        return new ProbeImpl(instrumentation, sourceSection, eventListener);
-    }
-
-    /**
-     * Next in chain.
-     */
-    @Child protected InstrumentationNodeImpl next;
-
-    protected InstrumentationNodeImpl() {
-    }
-
-    /**
-     * @return the instance of {@link Probe} to which this instrument is attached.
-     */
-    public Probe getProbe() {
-        final InstrumentationNodeImpl parent = (InstrumentationNodeImpl) getParent();
-        return parent == null ? null : parent.getProbe();
-    }
-
-    /**
-     * Add a probe to the end of this probe chain.
-     */
-    void internalAddInstrument(InstrumentationNodeImpl newInstrument) {
-        if (next == null) {
-            this.next = insert(newInstrument);
-        } else {
-            next.internalAddInstrument(newInstrument);
-        }
-    }
-
-    void internalRemoveInstrument(InstrumentationNodeImpl oldInstrument) {
-        if (next == null) {
-            throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument);
-        } else if (next == oldInstrument) {
-            if (oldInstrument.next == null) {
-                this.next = null;
-            } else {
-                this.next = insert(oldInstrument.next);
-                oldInstrument.next = null;
-            }
-        } else {
-            next.internalRemoveInstrument(oldInstrument);
-        }
-    }
-
-    /**
-     * Reports to the instance of {@link Probe} holding this instrument that some essential state
-     * has changed that requires deoptimization.
-     */
-    @CompilerDirectives.SlowPath
-    protected void notifyProbeChanged(InstrumentationNodeImpl instrument) {
-        final ProbeImpl probe = (ProbeImpl) getProbe();
-        probe.notifyProbeChanged(instrument);
-    }
-
-    private void internalEnter(Node astNode, VirtualFrame frame) {
-        enter(astNode, frame);
-        if (next != null) {
-            next.internalEnter(astNode, frame);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame) {
-        leave(astNode, frame);
-        if (next != null) {
-            next.internalLeave(astNode, frame);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, boolean result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, byte result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, short result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, int result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, long result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, char result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, float result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, double result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, Object result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-        leaveExceptional(astNode, frame, null);
-        if (next != null) {
-            next.internalLeaveExceptional(astNode, frame, e);
-        }
-    }
-
-    /**
-     * Holder of a chain of {@linkplain InstrumentationNodeImpl instruments}: manages the
-     * {@link Assumption} that none of the instruments have changed since last checked.
-     * <p>
-     * An instance is intended to be shared by every clone of the AST node with which it is
-     * originally attached, so it holds no parent pointer.
-     * <p>
-     * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful
-     * for instrumentation about its AST location(s).
-     */
-    private static final class ProbeImpl extends InstrumentationNodeImpl implements Probe {
-
-        final InstrumentationImpl instrumentation;
-
-        final InstrumentEventListener eventListener;
-
-        @CompilerDirectives.CompilationFinal private Assumption probeUnchanged;
-
-        /**
-         * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line
-         * will cause a halt.
-         */
-        @CompilerDirectives.CompilationFinal private boolean stepping;
-
-        /**
-         * Source information about the AST node to which this instrumentation is attached.
-         */
-        private final SourceSection probedSourceSection;
-
-        private final Set<PhylumTag> tags = EnumSet.noneOf(PhylumTag.class);
-
-        private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
-            this.instrumentation = instrumentation;
-            this.probedSourceSection = sourceSection;
-            this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener;
-            this.probeUnchanged = Truffle.getRuntime().createAssumption();
-            this.next = null;
-        }
-
-        @Override
-        public Probe getProbe() {
-            return this;
-        }
-
-        @Override
-        protected void notifyProbeChanged(InstrumentationNodeImpl instrument) {
-            probeUnchanged.invalidate();
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        public SourceSection getSourceLocation() {
-            return probedSourceSection;
-        }
-
-        public void tagAs(PhylumTag tag) {
-            assert tag != null;
-            if (!tags.contains(tag)) {
-                tags.add(tag);
-                instrumentation.newTagAdded(this, tag);
-            }
-        }
-
-        public boolean isTaggedAs(PhylumTag tag) {
-            assert tag != null;
-            return tags.contains(tag);
-        }
-
-        public Set<PhylumTag> getPhylumTags() {
-            return tags;
-        }
-
-        public void setStepping(boolean stepping) {
-            if (this.stepping != stepping) {
-                this.stepping = stepping;
-                probeUnchanged.invalidate();
-                probeUnchanged = Truffle.getRuntime().createAssumption();
-            }
-        }
-
-        public boolean isStepping() {
-            return stepping;
-        }
-
-        @CompilerDirectives.SlowPath
-        public void addInstrument(Instrument instrument) {
-            probeUnchanged.invalidate();
-            final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument;
-            super.internalAddInstrument(instrumentImpl);
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        @CompilerDirectives.SlowPath
-        public void removeInstrument(Instrument instrument) {
-            probeUnchanged.invalidate();
-            final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument;
-            super.internalRemoveInstrument(instrumentImpl);
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        public void notifyEnter(Node astNode, VirtualFrame frame) {
-            if (stepping || next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                if (stepping) {
-                    eventListener.haltedAt(astNode, frame.materialize());
-                }
-                if (next != null) {
-                    next.internalEnter(astNode, frame);
-                }
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, byte result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, short result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, int result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, long result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, char result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, float result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, double result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, Object result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeaveExceptional(astNode, frame, e);
-            }
-        }
-
-        public void enter(Node astNode, VirtualFrame frame) {
-        }
-
-        public void leave(Node astNode, VirtualFrame frame) {
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, boolean result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, byte result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, short result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, int result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, long result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, char result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, float result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, double result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, Object result) {
-        }
-
-        public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-        }
-
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Fri May 02 11:33:47 2014 +0200
@@ -191,8 +191,12 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
+        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         newChild.adoptHelper();
+        if (isInserted) {
+            newChild.onAdopt();
+        }
     }
 
     private void adoptHelper() {
@@ -209,8 +213,12 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
+        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         newChild.adoptUnadoptedHelper();
+        if (isInserted) {
+            newChild.onAdopt();
+        }
     }
 
     private void adoptUnadoptedHelper() {
@@ -332,7 +340,6 @@
     }
 
     private void traceRewrite(Node newNode, CharSequence reason) {
-
         if (TruffleOptions.TraceRewritesFilterFromCost != null) {
             if (filterByKind(this, TruffleOptions.TraceRewritesFilterFromCost)) {
                 return;
@@ -352,8 +359,21 @@
             return;
         }
 
+        final SourceSection reportedSourceSection = getEncapsulatingSourceSection();
+
         PrintStream out = System.out;
-        out.printf("[truffle]   rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason);
+        out.printf("[truffle]   rewrite %-50s |From %-40s |To %-40s |Reason %s%s%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason != null && reason.length() > 0 ? reason
+                        : "unknown", reportedSourceSection != null ? " at " + reportedSourceSection.getShortDescription() : "");
+    }
+
+    /**
+     * Subclasses of {@link Node} can implement this method to execute extra functionality when a
+     * node is effectively inserted into the AST. The {@code onAdopt} callback is called after the
+     * node has been effectively inserted, and it is guaranteed to be called only once for any given
+     * node.
+     */
+    protected void onAdopt() {
+        // empty default
     }
 
     private static String formatNodeInfo(Node node) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java	Fri May 02 11:33:47 2014 +0200
@@ -70,7 +70,7 @@
     /**
      * Gets the canonical representation of a source file, whose contents will be read lazily and
      * then cached.
-     * 
+     *
      * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
      */
     public Source get(String fileName, boolean reset) {
@@ -227,6 +227,11 @@
         }
 
         @Override
+        public String getShortName() {
+            return name;
+        }
+
+        @Override
         public String getCode() {
             return code;
         }
@@ -292,6 +297,11 @@
         }
 
         @Override
+        public String getShortName() {
+            return file.getName();
+        }
+
+        @Override
         public String getCode() {
             if (code == null || timeStamp != file.lastModified()) {
                 try {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri May 02 11:33:47 2014 +0200
@@ -317,16 +317,16 @@
     /**
      * <pre>
      * variant1 $condition != null
-     * 
+     *
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     * 
+     *
      * variant2 $condition != null
      * $type $name = $value;
      * </pre>
-     * 
+     *
      * .
      */
     private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) {
@@ -978,9 +978,8 @@
 
         private List<CodeExecutableElement> createImplicitChildrenAccessors() {
             NodeData node = getModel().getNode();
-            // Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>();
-            @SuppressWarnings("unchecked")
-            List<Set<TypeData>> expectTypes = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
+            List<Set<TypeData>> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null);
+            List<Set<TypeData>> expectTypes = new ArrayList<>(prototype);
 
             for (ExecutableTypeData executableType : node.getExecutableTypes()) {
                 for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
@@ -998,8 +997,7 @@
             }
 
             List<CodeExecutableElement> methods = new ArrayList<>();
-            @SuppressWarnings("unchecked")
-            List<Set<TypeData>> visitedList = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
+            List<Set<TypeData>> visitedList = new ArrayList<>(prototype);
             for (SpecializationData spec : node.getSpecializations()) {
                 int signatureIndex = -1;
                 for (ActualParameter param : spec.getParameters()) {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Fri May 02 11:33:47 2014 +0200
@@ -44,7 +44,7 @@
  * <li>After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U}
  * <li>After execution of function {@code f3}: {@code I->G}
  * </ol>
- * */
+ */
 public abstract class SLAbstractDispatchNode extends Node {
 
     protected static final int INLINE_CACHE_SIZE = 2;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Fri May 02 10:46:52 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Fri May 02 11:33:47 2014 +0200
@@ -29,7 +29,7 @@
  * there is always the danger of a spurious {@link NullPointerException}. Representing the guest
  * language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended
  * practice.
- * */
+ */
 public final class SLNull {
 
     /**
--- a/mx.cmd	Fri May 02 10:46:52 2014 +0200
+++ b/mx.cmd	Fri May 02 11:33:47 2014 +0200
@@ -1,1 +1,1 @@
-python mxtool/mx.py %*
+python %~dp0/mxtool/mx.py %*
--- a/mx/mx_graal.py	Fri May 02 10:46:52 2014 +0200
+++ b/mx/mx_graal.py	Fri May 02 11:33:47 2014 +0200
@@ -26,7 +26,7 @@
 #
 # ----------------------------------------------------------------------------------------------------
 
-import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO
+import os, 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
@@ -35,6 +35,7 @@
 import sanitycheck
 import itertools
 import json, textwrap
+import fnmatch
 
 # This works because when mx loads this file, it makes sure __file__ gets an absolute path
 _graal_home = dirname(dirname(__file__))
@@ -162,49 +163,124 @@
         rmIfExists(mx.distribution('GRAAL').path)
 
 def export(args):
-    """create a GraalVM zip file for distribution"""
+    """create archives of builds split by vmbuild and vm"""
 
     parser = ArgumentParser(prog='mx export')
-    parser.add_argument('--omit-vm-build', action='store_false', dest='vmbuild', help='omit VM build step')
-    parser.add_argument('--omit-dist-init', action='store_false', dest='distInit', help='omit class files and IDE configurations from distribution')
-    parser.add_argument('zipfile', nargs=REMAINDER, metavar='zipfile')
-
     args = parser.parse_args(args)
 
-    tmp = tempfile.mkdtemp(prefix='tmp', dir=_graal_home)
-    if args.vmbuild:
-        # Make sure the product VM binary is up to date
-        with VM(vmbuild='product'):
-            build([])
+    # collect data about export
+    infos = dict()
+    infos['timestamp'] = time.time()
+
+    hgcfg = mx.HgConfig()
+    hgcfg.check()
+    infos['revision'] = hgcfg.tip('.') + ('+' if hgcfg.isDirty('.') else '')
+    # TODO: infos['repository']
+
+    infos['jdkversion'] = str(mx.java().version)
+
+    infos['architecture'] = _arch()
+    infos['platform'] = mx.get_os()
+
+    if mx.get_os != 'windows':
+        pass
+        # infos['ccompiler']
+        # infos['linker']
+
+    infos['hostname'] = socket.gethostname()
 
-    mx.log('Copying Java sources and mx files...')
-    mx.run(('hg archive -I graal -I mx -I mxtool -I mx.sh ' + tmp).split())
+    def _writeJson(suffix, properties):
+        d = infos.copy()
+        for k, v in properties.iteritems():
+            assert not d.has_key(k)
+            d[k] = v
+
+        jsonFileName = 'export-' + suffix + '.json'
+        with open(jsonFileName, 'w') as f:
+            print >> f, json.dumps(d)
+        return jsonFileName
+
+
+    def _genFileName(archivtype, middle):
+        idPrefix = infos['revision'] + '_'
+        idSuffix = '.tar.gz'
+        return join(_graal_home, "graalvm_" + archivtype + "_"  + idPrefix + middle + idSuffix)
+
+    def _genFileArchPlatformName(archivtype, middle):
+        return _genFileName(archivtype, infos['platform'] + '_' + infos['architecture'] + '_' + middle)
+
+
+    # archive different build types of hotspot
+    for vmBuild in _vmbuildChoices:
+        jdkpath = join(_jdksDir(), vmBuild)
+        if not exists(jdkpath):
+            mx.logv("skipping " + vmBuild)
+            continue
 
-    # Copy the GraalVM JDK
-    mx.log('Copying GraalVM JDK...')
-    src = _jdk()
-    dst = join(tmp, basename(src))
-    shutil.copytree(src, dst)
-    zfName = join(_graal_home, 'graalvm-' + mx.get_os() + '.zip')
-    zf = zipfile.ZipFile(zfName, 'w')
-    for root, _, files in os.walk(tmp):
-        for f in files:
-            name = join(root, f)
-            arcname = name[len(tmp) + 1:]
-            zf.write(join(tmp, name), arcname)
+        tarName = _genFileArchPlatformName('basejdk', vmBuild)
+        mx.logv("creating basejdk " + tarName)
+        vmSet = set()
+        with tarfile.open(tarName, 'w:gz') as tar:
+            for root, _, files in os.walk(jdkpath):
+                if basename(root) in _vmChoices.keys():
+                    # TODO: add some assert to check path assumption
+                    vmSet.add(root)
+                    continue
+
+                for f in files:
+                    name = join(root, f)
+                    # print name
+                    tar.add(name, name)
+
+            n = _writeJson("basejdk-" + vmBuild, {'vmbuild' : vmBuild})
+            tar.add(n, n)
+
+        # create a separate archive for each VM
+        for vm in vmSet:
+            bVm = basename(vm)
+            vmTarName = _genFileArchPlatformName('vm', vmBuild + '_' + bVm)
+            mx.logv("creating vm " + vmTarName)
 
-    # create class files and IDE configurations
-    if args.distInit:
-        mx.log('Creating class files...')
-        mx.run('mx build'.split(), cwd=tmp)
-        mx.log('Creating IDE configurations...')
-        mx.run('mx ideinit'.split(), cwd=tmp)
+            debugFiles = set()
+            with tarfile.open(vmTarName, 'w:gz') as tar:
+                for root, _, files in os.walk(vm):
+                    for f in files:
+                        # TODO: mac, windows, solaris?
+                        if any(map(f.endswith, [".debuginfo"])):
+                            debugFiles.add(f)
+                        else:
+                            name = join(root, f)
+                            # print name
+                            tar.add(name, name)
+
+                n = _writeJson("vm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+                tar.add(n, n)
 
-    # clean up temp directory
-    mx.log('Cleaning up...')
-    shutil.rmtree(tmp)
+            if len(debugFiles) > 0:
+                debugTarName = _genFileArchPlatformName('debugfilesvm', vmBuild + '_' + bVm)
+                mx.logv("creating debugfilesvm " + debugTarName)
+                with tarfile.open(debugTarName, 'w:gz') as tar:
+                    for f in debugFiles:
+                        name = join(root, f)
+                        # print name
+                        tar.add(name, name)
+
+                    n = _writeJson("debugfilesvm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm})
+                    tar.add(n, n)
 
-    mx.log('Created distribution in ' + zfName)
+    # graal directory
+    graalDirTarName = _genFileName('classfiles', 'javac')
+    mx.logv("creating graal " + graalDirTarName)
+    with tarfile.open(graalDirTarName, 'w:gz') as tar:
+        for root, _, files in os.walk("graal"):
+            for f in [f for f in files if not f.endswith('.java')]:
+                name = join(root, f)
+                # print name
+                tar.add(name, name)
+
+        n = _writeJson("graal", {'javacompiler' : 'javac'})
+        tar.add(n, n)
+
 
 def _run_benchmark(args, availableBenchmarks, runBenchmark):
 
@@ -861,7 +937,7 @@
         projectscp = mx.classpath(projs)
 
     if whitelist:
-        classes = list(set(classes) & set(whitelist))
+        classes = [c for c in classes if any((glob.match(c) for glob in whitelist))]
 
     if len(classes) != 0:
         f_testfile = open(testfile, 'w')
@@ -905,10 +981,8 @@
 _unittestHelpSuffix = """
     Unittest options:
 
-      --short-only           run short testcases only
-      --long-only            run long testcases only
-      --baseline-whitelist   run only testcases which are known to
-                             work with the baseline compiler
+      --whitelist            run only testcases which are included
+                             in the given whitelist
 
     To avoid conflicts with VM options '--' can be used as delimiter.
 
@@ -945,10 +1019,7 @@
           formatter_class=RawDescriptionHelpFormatter,
           epilog=_unittestHelpSuffix,
         )
-    group = parser.add_mutually_exclusive_group()
-    group.add_argument('--short-only', action='store_true', help='run short testcases only')
-    group.add_argument('--long-only', action='store_true', help='run long testcases only')
-    parser.add_argument('--baseline-whitelist', action='store_true', help='run baseline testcases only')
+    parser.add_argument('--whitelist', help='run testcases specified in whitelist only', metavar='<path>')
 
     ut_args = []
     delimiter = False
@@ -968,33 +1039,19 @@
         parsed_args, args = parser.parse_known_args(ut_args)
 
     whitelist = None
-    if parsed_args.baseline_whitelist:
-        baseline_whitelist_file = 'test/baseline_whitelist.txt'
+    if parsed_args.whitelist:
         try:
-            with open(join(_graal_home, baseline_whitelist_file)) as fp:
-                whitelist = [l.rstrip() for l in fp.readlines()]
+            with open(join(_graal_home, parsed_args.whitelist)) as fp:
+                whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
         except IOError:
-            mx.log('warning: could not read baseline whitelist: ' + baseline_whitelist_file)
+            mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
 
-    if parsed_args.long_only:
-        annotations = ['@LongTest', '@Parameters']
-    elif parsed_args.short_only:
-        annotations = ['@Test']
-    else:
-        annotations = ['@Test', '@LongTest', '@Parameters']
-
-    _unittest(args, annotations, whitelist=whitelist)
+    _unittest(args, ['@Test', '@Parameters'], whitelist=whitelist)
 
 def shortunittest(args):
-    """alias for 'unittest --short-only'{0}"""
-
-    args.insert(0, '--short-only')
-    unittest(args)
+    """alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}"""
 
-def longunittest(args):
-    """alias for 'unittest --long-only'{0}"""
-
-    args.insert(0, '--long-only')
+    args = ['--whitelist', 'test/whitelist_shortunittest.txt'] + args
     unittest(args)
 
 def buildvms(args):
@@ -1104,6 +1161,11 @@
         unittest([])
         tasks.append(t.stop())
 
+    with VM('server', 'product'):  # hosted mode
+        t = Task('UnitTests-BaselineCompiler:hosted-product')
+        unittest(['--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler'])
+        tasks.append(t.stop())
+
     for vmbuild in ['fastdebug', 'product']:
         for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
             t = Task(str(test) + ':' + vmbuild)
@@ -1199,13 +1261,13 @@
 
         if mx.get_env('JDT'):
             t = Task('BuildJavaWithEcj')
-            build(['--no-native', '--jdt-warning-as-error'])
+            build(['-p', '--no-native', '--jdt-warning-as-error'])
             tasks.append(t.stop())
 
             _clean('CleanAfterEcjBuild')
 
         t = Task('BuildJavaWithJavac')
-        build(['--no-native', '--force-javac'])
+        build(['-p', '--no-native', '--force-javac'])
         tasks.append(t.stop())
 
         t = Task('Checkheaders')
@@ -1723,14 +1785,14 @@
     """make truffle.jar"""
 
     # Test with the built classes
-    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'])
+    _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', '@LongTest', '@Parameters'], "truffle.jar:")
+    _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@Parameters'], "truffle.jar:")
 
 
 def isGraalEnabled(vm):
@@ -1953,7 +2015,6 @@
         'gate' : [gate, '[-options]'],
         'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'],
         'unittest' : [unittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
-        'longunittest' : [longunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
         'makejmhdeps' : [makejmhdeps, ''],
         'shortunittest' : [shortunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
         'jacocoreport' : [jacocoreport, '[output directory]'],
--- a/mx/projects	Fri May 02 10:46:52 2014 +0200
+++ b/mx/projects	Fri May 02 11:33:47 2014 +0200
@@ -42,19 +42,19 @@
 library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
 library@DACAPO_SCALA@sha1=59b64c974662b5cf9dbd3cf9045d293853dd7a51
 
-library@OKRA@path=lib/okra-1.8.jar
-library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8.jar
-library@OKRA@sourcePath=lib/okra-1.8-src.jar
-library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-src.jar
+library@OKRA@path=lib/okra-1.9.jar
+library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar
+library@OKRA@sourcePath=lib/okra-1.9-src.jar
+library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar
 
-library@OKRA_WITH_SIM@path=lib/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim.jar
-library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar
-library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar
+library@OKRA_WITH_SIM@path=lib/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar
+library@OKRA_WITH_SIM@sourcePath=lib/okra-1.9-with-sim-src.jar
+library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar
 
 library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar
-library@JAVA_ALLOCATION_INSTRUMENTER@sha1=64c0a5329fbcb8284640e58d83252e0a3b08c23e
+library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-c7e3525a6b90.jar
+library@JAVA_ALLOCATION_INSTRUMENTER@sha1=128eb20a4cd3362a4d8b94614e66647808a2e37c
 
 library@VECMATH@path=lib/vecmath-1.3.1.jar
 library@VECMATH@urls=http://mirrors.ibiblio.org/pub/mirrors/maven/java3d/jars/vecmath-1.3.1.jar
@@ -426,6 +426,7 @@
 project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler@javaCompliance=1.8
 project@com.oracle.graal.compiler@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.compiler@annotationProcessorForDependents=true
 project@com.oracle.graal.compiler@workingSets=Graal
 
 # graal.compiler.amd64
--- a/mxtool/mx.py	Fri May 02 10:46:52 2014 +0200
+++ b/mxtool/mx.py	Fri May 02 11:33:47 2014 +0200
@@ -608,6 +608,17 @@
             else:
                 return None
 
+    def isDirty(self, sDir, abortOnError=True):
+        try:
+            return len(subprocess.check_output(['hg', 'status', '-R', sDir])) > 0
+        except OSError:
+            warn(self.missing)
+        except subprocess.CalledProcessError:
+            if abortOnError:
+                abort('failed to get status')
+            else:
+                return None
+
 class Suite:
     def __init__(self, mxDir, primary, load=True):
         self.dir = dirname(mxDir)
@@ -1542,9 +1553,13 @@
 
     def _init_classpaths(self):
         myDir = dirname(__file__)
+        outDir = join(dirname(__file__), '.jdk' + str(self.version))
+        if not exists(outDir):
+            os.makedirs(outDir)
         javaSource = join(myDir, 'ClasspathDump.java')
-        subprocess.check_call([self.javac, '-d', myDir, javaSource])
-        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', myDir, 'ClasspathDump']).split('|')]
+        if not exists(join(outDir, 'ClasspathDump.class')):
+            subprocess.check_call([self.javac, '-d', outDir, javaSource])
+        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', outDir, 'ClasspathDump']).split('|')]
         if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
             warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
         self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
@@ -1779,6 +1794,131 @@
 
 # Builtin commands
 
+def _defaultEcjPath():
+    return get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar'))
+
+class JavaCompileTask:
+    def __init__(self, args, proj, reason, javafilelist, jdk, outputDir, deps):
+        self.proj = proj
+        self.reason = reason
+        self.javafilelist = javafilelist
+        self.deps = deps
+        self.jdk = jdk
+        self.outputDir = outputDir
+        self.done = False
+        self.args = args
+
+    def __str__(self):
+        return self.proj.name
+
+    def logCompilation(self, compiler):
+        log('Compiling Java sources for {} with {}... [{}]'.format(self.proj.name, compiler, self.reason))
+
+    def execute(self):
+        argfileName = join(self.proj.dir, 'javafilelist.txt')
+        argfile = open(argfileName, 'wb')
+        argfile.write('\n'.join(self.javafilelist))
+        argfile.close()
+
+        processorArgs = []
+
+        aps = self.proj.annotation_processors()
+        if len(aps) > 0:
+            processorPath = classpath(aps, resolve=True)
+            genDir = self.proj.source_gen_dir()
+            if exists(genDir):
+                shutil.rmtree(genDir)
+            os.mkdir(genDir)
+            processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
+        else:
+            processorArgs += ['-proc:none']
+
+        args = self.args
+        jdk = self.jdk
+        outputDir = self.outputDir
+        compliance = str(jdk.javaCompliance)
+        cp = classpath(self.proj.name, includeSelf=True)
+        toBeDeleted = [argfileName]
+
+        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:
+                mainJava = java()
+                if not args.error_prone:
+                    self.logCompilation('javac')
+                    javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    if jdk.debug_port is not None:
+                        javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
+                    javacCmd += processorArgs
+                    javacCmd += ['@' + argfile.name]
+
+                    if not args.warnAPI:
+                        javacCmd.append('-XDignore.symbol.file')
+                    run(javacCmd)
+                else:
+                    self.logCompilation('javac (with error-prone)')
+                    javaArgs = ['-Xmx1g']
+                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    javacArgs += processorArgs
+                    javacArgs += ['@' + argfile.name]
+                    if not args.warnAPI:
+                        javacArgs.append('-XDignore.symbol.file')
+                    run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
+            else:
+                self.logCompilation('JDT')
+
+                jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
+
+                jdtArgs = ['-' + compliance,
+                         '-cp', cp, '-g', '-enableJavadoc',
+                         '-d', outputDir,
+                         '-bootclasspath', jdk.bootclasspath(),
+                         '-endorseddirs', jdk.endorseddirs(),
+                         '-extdirs', jdk.extdirs()]
+                jdtArgs += processorArgs
+
+                jdtProperties = join(self.proj.dir, '.settings', 'org.eclipse.jdt.core.prefs')
+                rootJdtProperties = join(self.proj.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs')
+                if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties):
+                    # Try to fix a missing properties file by running eclipseinit
+                    eclipseinit([], buildProcessorJars=False)
+                if not exists(jdtProperties):
+                    log('JDT properties file {0} not found'.format(jdtProperties))
+                else:
+                    with open(jdtProperties) as fp:
+                        origContent = fp.read()
+                        content = origContent
+                        if args.jdt_warning_as_error:
+                            content = content.replace('=warning', '=error')
+                        if not args.jdt_show_task_tags:
+                            content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore'
+                    if origContent != content:
+                        jdtPropertiesTmp = jdtProperties + '.tmp'
+                        with open(jdtPropertiesTmp, 'w') as fp:
+                            fp.write(content)
+                        toBeDeleted.append(jdtPropertiesTmp)
+                        jdtArgs += ['-properties', jdtPropertiesTmp]
+                    else:
+                        jdtArgs += ['-properties', jdtProperties]
+                jdtArgs.append('@' + argfile.name)
+
+                run_java(jdtVmArgs + jdtArgs)
+        finally:
+            for n in toBeDeleted:
+                os.remove(n)
+            self.done = True
+
 def build(args, parser=None):
     """compile the Java and C sources, linking the latter
 
@@ -1789,42 +1929,29 @@
     if not suppliedParser:
         parser = ArgumentParser(prog='mx build')
 
-    defaultEcjPath = get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar'))
-
     parser = parser if parser is not None else ArgumentParser(prog='mx build')
     parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
     parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
+    parser.add_argument('-p', action='store_true', dest='parallelize', help='parallelizes Java compilation')
     parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one')
     parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs')
     parser.add_argument('--projects', action='store', help='comma separated projects to build (omit to build all projects)')
     parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)')
     parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects')
     parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects')
-    parser.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
-    parser.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='<path>')
     parser.add_argument('--jdt-warning-as-error', action='store_true', help='convert all Eclipse batch compiler warnings to errors')
     parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings')
-    parser.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
+    compilerSelect = parser.add_mutually_exclusive_group()
+    compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
+    compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler', default=_defaultEcjPath(), metavar='<path>')
+    compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
+
 
     if suppliedParser:
         parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
 
     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)
-
-    built = set()
-
     if args.only is not None:
         # N.B. This build will not include dependencies including annotation processor dependencies
         sortedProjects = [project(name) for name in args.only.split(',')]
@@ -1857,6 +1984,7 @@
                 shutil.rmtree(join(genDir, f))
         return outputDir
 
+    tasks = {}
     for p in sortedProjects:
         if p.native:
             if args.native:
@@ -1866,7 +1994,6 @@
                     run([gmake_cmd(), 'clean'], cwd=p.dir)
 
                 run([gmake_cmd()], cwd=p.dir)
-                built.add(p.name)
             continue
         else:
             if not args.java:
@@ -1880,18 +2007,19 @@
         if not jdk:
             log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, requiredCompliance))
             continue
-        compliance = str(jdk.javaCompliance)
 
         outputDir = prepareOutputDirs(p, args.clean)
 
-        cp = classpath(p.name, includeSelf=True)
         sourceDirs = p.source_dirs()
-        mustBuild = args.force
-        if not mustBuild:
-            for dep in p.all_deps([], False):
-                if dep.name in built:
-                    mustBuild = True
-
+        buildReason = 'forced build' if args.force else None
+        taskDeps = []
+        if not buildReason:
+            for dep in p.all_deps([], includeLibs=False, includeAnnotationProcessors=True):
+                taskDep = tasks.get(dep.name)
+                if taskDep:
+                    if not buildReason:
+                        buildReason = dep.name + ' rebuilt'
+                    taskDeps.append(taskDep)
 
         jasminAvailable = None
         javafilelist = []
@@ -1940,20 +2068,18 @@
                         if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) < os.path.getmtime(src)):
                             shutil.copyfile(src, dst)
 
-                if not mustBuild:
+                if not buildReason:
                     for javafile in javafiles:
                         classfile = TimeStampFile(outputDir + javafile[len(sourceDir):-len('java')] + 'class')
                         if not classfile.exists() or classfile.isOlderThan(javafile):
-                            mustBuild = True
+                            buildReason = 'class file(s) out of date'
                             break
 
-        aps = p.annotation_processors()
         apsOutOfDate = p.update_current_annotation_processors_file()
         if apsOutOfDate:
-            logv('[annotation processors for {0} changed]'.format(p.name))
-            mustBuild = True
-
-        if not mustBuild:
+            buildReason = 'annotation processor(s) changed'
+
+        if not buildReason:
             logv('[all class files for {0} are up to date - skipping]'.format(p.name))
             continue
 
@@ -1961,95 +2087,86 @@
             logv('[no Java sources for {0} - skipping]'.format(p.name))
             continue
 
-        # Ensure that the output directories are clean
-        # prepareOutputDirs(p, True)
-
-        built.add(p.name)
-
-        argfileName = join(p.dir, 'javafilelist.txt')
-        argfile = open(argfileName, 'wb')
-        argfile.write('\n'.join(javafilelist))
-        argfile.close()
-
-        processorArgs = []
-
-        if len(aps) > 0:
-            processorPath = classpath(aps, resolve=True)
-            genDir = p.source_gen_dir()
-            if exists(genDir):
-                shutil.rmtree(genDir)
-            os.mkdir(genDir)
-            processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
+        task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, taskDeps)
+
+        if args.parallelize:
+            # Best to initialize class paths on main process
+            jdk.bootclasspath()
+            task.proc = None
+            tasks[p.name] = task
         else:
-            processorArgs += ['-proc:none']
-
-        toBeDeleted = [argfileName]
-        try:
-            if not jdtJar:
-                mainJava = java()
-                if not args.error_prone:
-                    log('Compiling Java sources for {0} with javac...'.format(p.name))
-                    javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
-                    if jdk.debug_port is not None:
-                        javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
-                    javacCmd += processorArgs
-                    javacCmd += ['@' + argfile.name]
-
-                    if not args.warnAPI:
-                        javacCmd.append('-XDignore.symbol.file')
-                    run(javacCmd)
+            task.execute()
+
+    if args.parallelize:
+
+        def joinTasks(tasks):
+            failed = []
+            for t in tasks:
+                t.proc.join()
+                if t.proc.exitcode != 0:
+                    failed.append(t)
+            return failed
+
+        def checkTasks(tasks):
+            active = []
+            for t in tasks:
+                if t.proc.is_alive():
+                    active.append(t)
+                else:
+                    if t.proc.exitcode != 0:
+                        return ([], joinTasks(tasks))
+            return (active, [])
+
+        def remainingDepsDepth(task):
+            if task._d is None:
+                incompleteDeps = [d for d in task.deps if d.proc is None or d.proc.is_alive()]
+                if len(incompleteDeps) == 0:
+                    task._d = 0
                 else:
-                    log('Compiling Java sources for {0} with javac (with error-prone)...'.format(p.name))
-                    javaArgs = ['-Xmx1g']
-                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
-                    javacArgs += processorArgs
-                    javacArgs += ['@' + argfile.name]
-                    if not args.warnAPI:
-                        javacArgs.append('-XDignore.symbol.file')
-                    run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
-            else:
-                log('Compiling Java sources for {0} with JDT...'.format(p.name))
-
-                jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
-
-                jdtArgs = ['-' + compliance,
-                         '-cp', cp, '-g', '-enableJavadoc',
-                         '-d', outputDir,
-                         '-bootclasspath', jdk.bootclasspath(),
-                         '-endorseddirs', jdk.endorseddirs(),
-                         '-extdirs', jdk.extdirs()]
-                jdtArgs += processorArgs
-
-
-                jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs')
-                rootJdtProperties = join(p.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs')
-                if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties):
-                    # Try to fix a missing properties file by running eclipseinit
-                    eclipseinit([], buildProcessorJars=False)
-                if not exists(jdtProperties):
-                    log('JDT properties file {0} not found'.format(jdtProperties))
+                    task._d = max([remainingDepsDepth(t) for t in incompleteDeps]) + 1
+            return task._d
+
+        def sortWorklist(tasks):
+            for t in tasks:
+                t._d = None
+            return sorted(tasks, lambda x, y: remainingDepsDepth(x) - remainingDepsDepth(y))
+
+        import multiprocessing
+        cpus = multiprocessing.cpu_count()
+        worklist = sortWorklist(tasks.values())
+        active = []
+        while len(worklist) != 0:
+            while True:
+                active, failed = checkTasks(active)
+                if len(failed) != 0:
+                    assert not active, active
+                    break
+                if len(active) == cpus:
+                    # Sleep for 1 second
+                    time.sleep(1)
                 else:
-                    with open(jdtProperties) as fp:
-                        origContent = fp.read()
-                        content = origContent
-                        if args.jdt_warning_as_error:
-                            content = content.replace('=warning', '=error')
-                        if not args.jdt_show_task_tags:
-                            content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore'
-                    if origContent != content:
-                        jdtPropertiesTmp = jdtProperties + '.tmp'
-                        with open(jdtPropertiesTmp, 'w') as fp:
-                            fp.write(content)
-                        toBeDeleted.append(jdtPropertiesTmp)
-                        jdtArgs += ['-properties', jdtPropertiesTmp]
-                    else:
-                        jdtArgs += ['-properties', jdtProperties]
-                jdtArgs.append('@' + argfile.name)
-
-                run_java(jdtVmArgs + jdtArgs)
-        finally:
-            for n in toBeDeleted:
-                os.remove(n)
+                    break
+
+            def executeTask(task):
+                task.execute()
+
+            def depsDone(task):
+                for d in task.deps:
+                    if d.proc is None or d.proc.exitcode is None:
+                        return False
+                return True
+
+            for task in worklist:
+                if depsDone(task):
+                    worklist.remove(task)
+                    task.proc = multiprocessing.Process(target=executeTask, args=(task,))
+                    task.proc.start()
+                    active.append(task)
+                if len(active) == cpus:
+                    break
+
+            worklist = sortWorklist(worklist)
+        joinTasks(active)
 
     for dist in _dists.values():
         archive(['@' + dist.name])
@@ -2243,7 +2360,7 @@
         return []
 
     pnames = [p.name for p in projs]
-    build(['--projects', ",".join(pnames)])
+    build(['--jdt-warning-as-error', '--projects', ",".join(pnames)])
     return archive(pnames)
 
 def pylint(args):
@@ -3843,7 +3960,7 @@
 
 
 def ideinit(args, refreshOnly=False, buildProcessorJars=True):
-    """(re)generate Eclipse and NetBeans project configurations"""
+    """(re)generate Eclipse, NetBeans and Intellij project configurations"""
     eclipseinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
     netbeansinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars)
     intellijinit(args, refreshOnly=refreshOnly)
@@ -3981,7 +4098,13 @@
             try:
                 log('Generating {2} for {0} in {1}'.format(p.name, out, docDir))
                 projectJava = java(p.javaCompliance)
-                run([java().javadoc, memory,
+
+                # Once https://bugs.openjdk.java.net/browse/JDK-8041628 is fixed,
+                # this should be reverted to:
+                # javadocExe = java().javadoc
+                javadocExe = projectJava.javadoc
+
+                run([javadocExe, memory,
                      '-XDignore.symbol.file',
                      '-classpath', cp,
                      '-quiet',
@@ -3991,6 +4114,7 @@
                      '-source', str(projectJava.javaCompliance),
                      '-bootclasspath', projectJava.bootclasspath(),
                      '-extdirs', projectJava.extdirs()] +
+                     ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
                      links +
                      extraArgs +
                      nowarnAPI +
@@ -4028,115 +4152,19 @@
              '-quiet',
              '-d', out,
              '-sourcepath', sp] +
+             ([] if java().javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
              links +
              extraArgs +
              nowarnAPI +
              list(pkgs))
         log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
 
-class Chunk:
-    def __init__(self, content, ldelim, rdelim=None):
-        lindex = content.find(ldelim)
-        if rdelim is not None:
-            rindex = content.find(rdelim)
-        else:
-            rindex = lindex + len(ldelim)
-        self.ldelim = ldelim
-        self.rdelim = rdelim
-        if lindex != -1 and rindex != -1 and rindex > lindex:
-            self.text = content[lindex + len(ldelim):rindex]
-        else:
-            self.text = None
-
-    def replace(self, content, repl):
-        lindex = content.find(self.ldelim)
-        if self.rdelim is not None:
-            rindex = content.find(self.rdelim)
-            rdelimLen = len(self.rdelim)
-        else:
-            rindex = lindex + len(self.ldelim)
-            rdelimLen = 0
-        old = content[lindex:rindex + rdelimLen]
-        return content.replace(old, repl)
-
-# Post-process an overview-summary.html file to move the
-# complete overview to the top of the page
-def _fix_overview_summary(path, topLink):
-    """
-    Processes an "overview-summary.html" generated by javadoc to put the complete
-    summary text above the Packages table.
-    """
-
-    # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
-    with open(path) as fp:
-        content = fp.read()
-
-    chunk1 = Chunk(content, """<div class="header">
-<div class="subTitle">
-<div class="block">""", """</div>
-</div>
-<p>See: <a href="#overview.description">Description</a></p>
-</div>""")
-
-    chunk2 = Chunk(content, """<div class="contentContainer"><a name="overview.description">
-<!--   -->
-</a>
-<div class="block">""", """</div>
-</div>
-<!-- ======= START OF BOTTOM NAVBAR ====== -->""")
-
-    assert chunk1.text, 'Could not find header section in ' + path
-    assert chunk2.text, 'Could not find footer section in ' + path
-
-    content = chunk1.replace(content, '<div class="header"><div class="subTitle"><div class="block">' + topLink + chunk2.text + '</div></div></div>')
-    content = chunk2.replace(content, '')
-
-    with open(path, 'w') as fp:
-        fp.write(content)
-
-
-# Post-process a package-summary.html file to move the
-# complete package description to the top of the page
-def _fix_package_summary(path):
-    """
-    Processes an "overview-summary.html" generated by javadoc to put the complete
-    summary text above the Packages table.
-    """
-
-    # This uses scraping and so will break if the relevant content produced by javadoc changes in any way!
-    with open(path) as fp:
-        content = fp.read()
-
-    chunk1 = Chunk(content, """<div class="header">
-<h1 title="Package" class="title">Package""", """<p>See:&nbsp;<a href="#package.description">Description</a></p>
-</div>""")
-
-    chunk2 = Chunk(content, """<a name="package.description">
-<!--   -->
-</a>""", """</div>
-</div>
-<!-- ======= START OF BOTTOM NAVBAR ====== -->""")
-
-    if chunk1.text:
-        if chunk2.text:
-            repl = re.sub(r'<h2 title=(.*) Description</h2>', r'<h1 title=\1</h1>', chunk2.text, 1)
-            content = chunk1.replace(content, '<div class="header">' + repl + '</div></div>')
-            content = chunk2.replace(content, '')
-
-            with open(path, 'w') as fp:
-                fp.write(content)
-        else:
-            log('warning: Could not find package description detail section in ' + path)
-
-    else:
-        # no package description given
-        pass
-
 def site(args):
     """creates a website containing javadoc and the project dependency graph"""
 
     parser = ArgumentParser(prog='site')
     parser.add_argument('-d', '--base', action='store', help='directory for generated site', required=True, metavar='<dir>')
+    parser.add_argument('--tmp', action='store', help='directory to use for intermediate results', metavar='<dir>')
     parser.add_argument('--name', action='store', help='name of overall documentation', required=True, metavar='<name>')
     parser.add_argument('--overview', action='store', help='path to the overview content for overall documentation', required=True, metavar='<path>')
     parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)')
@@ -4147,7 +4175,7 @@
     args = parser.parse_args(args)
 
     args.base = os.path.abspath(args.base)
-    tmpbase = tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base))
+    tmpbase = args.tmp if args.tmp else  tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base))
     unified = join(tmpbase, 'all')
 
     exclude_packages_arg = []
@@ -4196,6 +4224,9 @@
                  '--arg', '@-windowtitle', '--arg', '@' + title,
                  '--arg', '@-doctitle', '--arg', '@' + title,
                  '--arg', '@-overview', '--arg', '@' + args.overview] + exclude_packages_arg + projects_arg + extra_javadoc_args)
+
+        if exists(unified):
+            shutil.rmtree(unified)
         os.rename(join(tmpbase, 'javadoc'), unified)
 
         # Generate dependency graph with Graphviz
@@ -4249,29 +4280,17 @@
             with open(html, 'w') as fp:
                 print >> fp, '<html><body><object data="{}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base)
 
-        top = join(tmpbase, 'all', 'overview-summary.html')
-        for root, _, files in os.walk(tmpbase):
-            for f in files:
-                if f == 'overview-summary.html':
-                    path = join(root, f)
-                    topLink = ''
-                    if top != path:
-                        link = os.path.relpath(join(tmpbase, 'all', 'index.html'), dirname(path))
-                        topLink = '<p><a href="' + link + '", target="_top"><b>[return to the overall ' + args.name + ' documentation]</b></a></p>'
-                    _fix_overview_summary(path, topLink)
-                elif f == 'package-summary.html':
-                    path = join(root, f)
-                    _fix_package_summary(path)
-
-
         if exists(args.base):
             shutil.rmtree(args.base)
-        shutil.move(tmpbase, args.base)
+        if args.tmp:
+            shutil.copytree(tmpbase, args.base)
+        else:
+            shutil.move(tmpbase, args.base)
 
         print 'Created website - root is ' + join(args.base, 'all', 'index.html')
 
     finally:
-        if exists(tmpbase):
+        if not args.tmp and exists(tmpbase):
             shutil.rmtree(tmpbase)
 
 def _kwArg(kwargs):
@@ -4345,6 +4364,7 @@
 
     parser = ArgumentParser(prog='exportlibs')
     parser.add_argument('-b', '--base', action='store', help='base name of archive (default: libs)', default='libs', metavar='<path>')
+    parser.add_argument('-a', '--include-all', action='store_true', help="include all defined libaries")
     parser.add_argument('--arc', action='store', choices=['tgz', 'tbz2', 'tar', 'zip'], default='tgz', help='the type of the archive to create')
     parser.add_argument('--no-sha1', action='store_false', dest='sha1', help='do not create SHA1 signature of archive')
     parser.add_argument('--no-md5', action='store_false', dest='md5', help='do not create MD5 signature of archive')
@@ -4365,9 +4385,44 @@
             else:
                 logv('[already added ' + path + ']')
 
-        for lib in _libs.itervalues():
-            if len(lib.urls) != 0 or args.include_system_libs:
-                add(lib.get_path(resolve=True), lib.path)
+        libsToExport = set()
+        if args.include_all:
+            for lib in _libs.itervalues():
+                libsToExport.add(lib)
+        else:
+            def isValidLibrary(dep):
+                if dep in _libs.iterkeys():
+                    lib = _libs[dep]
+                    if len(lib.urls) != 0 or args.include_system_libs:
+                        return lib
+                return None
+
+            # iterate over all project dependencies and find used libraries
+            for p in _projects.itervalues():
+                for dep in p.deps:
+                    r = isValidLibrary(dep)
+                    if r:
+                        libsToExport.add(r)
+
+            # a library can have other libraries as dependency
+            size = 0
+            while size != len(libsToExport):
+                size = len(libsToExport)
+                for lib in libsToExport.copy():
+                    for dep in lib.deps:
+                        r = isValidLibrary(dep)
+                        if r:
+                            libsToExport.add(r)
+
+        for lib in libsToExport:
+            add(lib.get_path(resolve=True), lib.path)
+            if lib.sha1:
+                add(lib.get_path(resolve=True) + ".sha1", lib.path + ".sha1")
+            if lib.sourcePath:
+                add(lib.get_source_path(resolve=True), lib.sourcePath)
+                if lib.sourceSha1:
+                    add(lib.get_source_path(resolve=True) + ".sha1", lib.sourcePath + ".sha1")
+
         if args.extras:
             for e in args.extras:
                 if os.path.isdir(e):
--- a/src/share/vm/classfile/systemDictionary.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/classfile/systemDictionary.cpp	Fri May 02 11:33:47 2014 +0200
@@ -216,7 +216,7 @@
 // Forwards to resolve_instance_class_or_null
 
 Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
-  assert(!THREAD->is_Compiler_thread(),
+  assert(THREAD->can_call_java(),
          err_msg("can not load classes with compiler thread: class=%s, classloader=%s",
                  class_name->as_C_string(),
                  class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string()));
@@ -2347,7 +2347,7 @@
                                                           TRAPS) {
   methodHandle empty;
   assert(EnableInvokeDynamic, "");
-  assert(!THREAD->is_Compiler_thread(), "");
+  assert(THREAD->can_call_java() ,"");
   Handle method_type =
     SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty));
   if (false) {  // FIXME: Decide if the Java upcall should resolve signatures.
@@ -2400,7 +2400,7 @@
   if (spe != NULL && spe->method_type() != NULL) {
     assert(java_lang_invoke_MethodType::is_instance(spe->method_type()), "");
     return Handle(THREAD, spe->method_type());
-  } else if (THREAD->is_Compiler_thread()) {
+  } else if (!THREAD->can_call_java()) {
     warning("SystemDictionary::find_method_handle_type called from compiler thread");  // FIXME
     return Handle();  // do not attempt from within compiler, unless it was cached
   }
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri May 02 11:33:47 2014 +0200
@@ -367,7 +367,7 @@
   template(compileTheWorld_name,                  "compileTheWorld")                                                                  \
   template(shutdownCompiler_name,                 "shutdownCompiler")                                                                 \
   template(compileMethod_name,                    "compileMethod")                                                                    \
-  template(compileMethod_signature,               "(JIZ)V")                                                                           \
+  template(compileMethod_signature,               "(JIJZ)V")                                                                          \
   template(setOption_name,                        "setOption")                                                                        \
   template(setOption_signature,                   "(Ljava/lang/String;)Z")                                                            \
   template(finalizeOptions_name,                  "finalizeOptions")                                                                  \
--- a/src/share/vm/code/debugInfoRec.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/code/debugInfoRec.cpp	Fri May 02 11:33:47 2014 +0200
@@ -235,16 +235,13 @@
 
 
 int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) {
-  // It's always a space win to share and Graal generates quite a bit
-  // of scopes data so always enable the sharing logic with Graal.
-  // Presumably this is disabled in regular HotSpot because it makes
-  // recording more expensive?
-#ifndef GRAAL
-  // Only pull this trick if non-safepoint recording
-  // is enabled, for now.
-  if (!recording_non_safepoints())
+  if (FLAG_IS_DEFAULT(ShareDebugInfo)) {
+    if (!ShareDebugInfo && !recording_non_safepoints()) {
+      return serialized_null;
+    }
+  } else if (!ShareDebugInfo) {
     return serialized_null;
-#endif
+  }
 
   NOT_PRODUCT(++dir_stats.chunks_queried);
   int stream_length = stream()->position() - stream_offset;
--- a/src/share/vm/code/nmethod.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/code/nmethod.cpp	Fri May 02 11:33:47 2014 +0200
@@ -142,6 +142,7 @@
   int handler_table_size;
   int nul_chk_table_size;
   int oops_size;
+  int metadata_size;
 
   void note_nmethod(nmethod* nm) {
     nmethod_count += 1;
@@ -151,6 +152,7 @@
     insts_size          += nm->insts_size();
     stub_size           += nm->stub_size();
     oops_size           += nm->oops_size();
+    metadata_size       += nm->metadata_size();
     scopes_data_size    += nm->scopes_data_size();
     scopes_pcs_size     += nm->scopes_pcs_size();
     dependencies_size   += nm->dependencies_size();
@@ -161,11 +163,13 @@
     if (nmethod_count == 0)  return;
     tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name);
     if (total_size != 0)          tty->print_cr(" total in heap  = %d", total_size);
+    if (nmethod_count != 0)       tty->print_cr(" header         = %d", nmethod_count * sizeof(nmethod));
     if (relocation_size != 0)     tty->print_cr(" relocation     = %d", relocation_size);
     if (consts_size != 0)         tty->print_cr(" constants      = %d", consts_size);
     if (insts_size != 0)          tty->print_cr(" main code      = %d", insts_size);
     if (stub_size != 0)           tty->print_cr(" stub code      = %d", stub_size);
     if (oops_size != 0)           tty->print_cr(" oops           = %d", oops_size);
+    if (metadata_size != 0)       tty->print_cr(" metadata       = %d", metadata_size);
     if (scopes_data_size != 0)    tty->print_cr(" scopes data    = %d", scopes_data_size);
     if (scopes_pcs_size != 0)     tty->print_cr(" scopes pcs     = %d", scopes_pcs_size);
     if (dependencies_size != 0)   tty->print_cr(" dependencies   = %d", dependencies_size);
@@ -180,12 +184,14 @@
   int native_relocation_size;
   int native_insts_size;
   int native_oops_size;
+  int native_metadata_size;
   void note_native_nmethod(nmethod* nm) {
     native_nmethod_count += 1;
     native_total_size       += nm->size();
     native_relocation_size  += nm->relocation_size();
     native_insts_size       += nm->insts_size();
     native_oops_size        += nm->oops_size();
+    native_metadata_size    += nm->metadata_size();
   }
   void print_native_nmethod_stats() {
     if (native_nmethod_count == 0)  return;
@@ -194,6 +200,7 @@
     if (native_relocation_size != 0)  tty->print_cr(" N. relocation  = %d", native_relocation_size);
     if (native_insts_size != 0)       tty->print_cr(" N. main code   = %d", native_insts_size);
     if (native_oops_size != 0)        tty->print_cr(" N. oops        = %d", native_oops_size);
+    if (native_metadata_size != 0)    tty->print_cr(" N. metadata    = %d", native_metadata_size);
   }
 };
 
@@ -229,11 +236,18 @@
 #ifdef GRAAL
 static java_nmethod_stats_struct graal_java_nmethod_stats;
 #endif
+#ifdef SHARK
+static java_nmethod_stats_struct shark_java_nmethod_stats;
+#endif
 static java_nmethod_stats_struct unknown_java_nmethod_stats;
 
 static native_nmethod_stats_struct native_nmethod_stats;
 static pc_nmethod_stats_struct pc_nmethod_stats;
 
+static void note_native_wrapper_nmethod(nmethod* nm) {
+  native_nmethod_stats.note_native_nmethod(nm);
+}
+
 static void note_java_nmethod(nmethod* nm) {
 #ifdef COMPILER1
   if (nm->is_compiled_by_c1()) {
@@ -250,6 +264,11 @@
     graal_java_nmethod_stats.note_nmethod(nm);
   } else
 #endif
+#ifdef SHARK
+  if (nm->is_compiled_by_shark()) {
+    shark_java_nmethod_stats.note_nmethod(nm);
+  } else
+#endif
   {
     unknown_java_nmethod_stats.note_nmethod(nm);
   }
@@ -556,7 +575,7 @@
                                             code_buffer, frame_size,
                                             basic_lock_owner_sp_offset,
                                             basic_lock_sp_offset, oop_maps);
-    if (nm != NULL)  note_java_nmethod(nm);
+    if (nm != NULL)  note_native_wrapper_nmethod(nm);
     if (PrintAssembly && nm != NULL) {
       Disassembler::decode(nm);
     }
@@ -3083,9 +3102,14 @@
 #ifdef GRAAL
   graal_java_nmethod_stats.print_nmethod_stats("Graal");
 #endif
+#ifdef SHARK
+  shark_java_nmethod_stats.print_nmethod_stats("Shark");
+#endif
   unknown_java_nmethod_stats.print_nmethod_stats("Unknown");
   DebugInformationRecorder::print_statistics();
+#ifndef PRODUCT
   pc_nmethod_stats.print_pc_stats();
+#endif
   Dependencies::print_statistics();
   if (xtty != NULL)  xtty->tail("statistics");
 }
--- a/src/share/vm/compiler/compileBroker.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.cpp	Fri May 02 11:33:47 2014 +0200
@@ -804,7 +804,7 @@
 
 #if defined(COMPILERGRAAL)
   _compilers[1] = graal;
-  c2_count = 0;
+  c2_count = UseGraalCompilationQueue ? 0 : c2_count;
 #endif // COMPILERGRAAL
 
 #ifdef COMPILER2
@@ -1143,22 +1143,24 @@
     return;
   }
 
-#if defined(COMPILERGRAAL)
-  // In tiered mode we want to only handle highest tier compiles and
-  // in non-tiered mode the default level should be
-  // CompLevel_full_optimization which equals CompLevel_highest_tier.
-  assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level");
-  assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition");
-  if (comp_level == CompLevel_full_optimization) {
-    if (!JavaThread::current()->is_graal_compiling()) {
-      bool blockingCompilation = is_compile_blocking(method, osr_bci);
-      GraalCompiler::instance()->compile_method(method, osr_bci, blockingCompilation);
-    } else {
-      // Can't enqueue this request because there would be no one to service it, so simply return.
+#ifdef COMPILERGRAAL
+  if (UseGraalCompilationQueue) {
+    // In tiered mode we want to only handle highest tier compiles and
+    // in non-tiered mode the default level should be
+    // CompLevel_full_optimization which equals CompLevel_highest_tier.
+    assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level");
+    assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition");
+    if (comp_level == CompLevel_full_optimization) {
+      if (!JavaThread::current()->is_graal_compiling()) {
+        bool blockingCompilation = is_compile_blocking(method, osr_bci);
+        GraalCompiler::instance()->compile_method(method, osr_bci, NULL, blockingCompilation);
+      } else {
+        // Can't enqueue this request because there would be no one to service it, so simply return.
+      }
+      return;
     }
-    return;
+    assert(TieredCompilation, "should only reach here in tiered mode");
   }
-  assert(TieredCompilation, "should only reach here in tiered mode");
 #endif // COMPILERGRAAL
 
   // Outputs from the following MutexLocker block:
@@ -1881,6 +1883,35 @@
   tty->print(s.as_string());
 }
 
+void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) {
+
+  if (success) {
+    task->mark_success();
+    if (ci_env != NULL) {
+      task->set_num_inlined_bytecodes(ci_env->num_inlined_bytecodes());
+    }
+    if (_compilation_log != NULL) {
+      nmethod* code = task->code();
+      if (code != NULL) {
+        _compilation_log->log_nmethod(thread, code);
+      }
+    }
+  }
+
+  // simulate crash during compilation
+  assert(task->compile_id() != CICrashAt, "just as planned");
+  if (event.should_commit()) {
+    event.set_method(task->method());
+    event.set_compileID(task->compile_id());
+    event.set_compileLevel(task->comp_level());
+    event.set_succeded(task->is_success());
+    event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
+    event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
+    event.set_inlinedBytes(task->num_inlined_bytecodes());
+    event.commit();
+  }
+}
+
 // ------------------------------------------------------------------
 // CompileBroker::invoke_compiler_on_method
 //
@@ -1929,6 +1960,21 @@
   push_jni_handle_block();
   Method* target_handle = task->method();
   int compilable = ciEnv::MethodCompilable;
+  AbstractCompiler *comp = compiler(task_level);
+
+#ifdef COMPILERGRAAL
+  if (comp != NULL && comp->is_graal()) {
+    assert(!UseGraalCompilationQueue, "should not reach here");
+    GraalCompiler* graal = (GraalCompiler*) comp;
+
+    TraceTime t1("compilation", &time);
+    EventCompilation event;
+
+    graal->compile_method(target_handle, osr_bci, task, false);
+
+    post_compile(thread, task, event, task->code() != NULL, NULL);
+  } else
+#endif // COMPILERGRAAL
   {
     int system_dictionary_modification_counter;
     {
@@ -1960,7 +2006,6 @@
     TraceTime t1("compilation", &time);
     EventCompilation event;
 
-    AbstractCompiler *comp = compiler(task_level);
     if (comp == NULL) {
       ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
     } else {
@@ -1988,28 +2033,9 @@
             err_msg_res("COMPILE SKIPPED: %s",      ci_env.failure_reason());
         task->print_compilation(tty, msg);
       }
-    } else {
-      task->mark_success();
-      task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes());
-      if (_compilation_log != NULL) {
-        nmethod* code = task->code();
-        if (code != NULL) {
-          _compilation_log->log_nmethod(thread, code);
-        }
-      }
     }
-    // simulate crash during compilation
-    assert(task->compile_id() != CICrashAt, "just as planned");
-    if (event.should_commit()) {
-      event.set_method(target->get_Method());
-      event.set_compileID(compile_id);
-      event.set_compileLevel(task->comp_level());
-      event.set_succeded(task->is_success());
-      event.set_isOsr(is_osr);
-      event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
-      event.set_inlinedBytes(task->num_inlined_bytecodes());
-      event.commit();
-    }
+
+    post_compile(thread, task, event, !ci_env.failing(), &ci_env);
   }
   pop_jni_handle_block();
 
--- a/src/share/vm/compiler/compileBroker.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.hpp	Fri May 02 11:33:47 2014 +0200
@@ -28,6 +28,7 @@
 #include "ci/compilerInterface.hpp"
 #include "compiler/abstractCompiler.hpp"
 #include "runtime/perfData.hpp"
+#include "trace/tracing.hpp"
 
 class nmethod;
 class nmethodLocker;
@@ -339,6 +340,7 @@
   static void wait_for_completion(CompileTask* task);
 
   static void invoke_compiler_on_method(CompileTask* task);
+  static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
   static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level);
   static void push_jni_handle_block();
   static void pop_jni_handle_block();
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Fri May 02 11:33:47 2014 +0200
@@ -422,12 +422,13 @@
     methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code));
     jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code);
     jint id = HotSpotCompiledNmethod::id(compiled_code);
+    CompileTask* task = (CompileTask*) (address) HotSpotCompiledNmethod::ctask(compiled_code);
     if (id == -1) {
       // Make sure a valid compile_id is associated with every compile
       id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci);
     }
     result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
-        GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, id, false, installed_code, speculation_log);
+        GraalCompiler::instance(), _debug_recorder, _dependencies, task, id, false, installed_code, speculation_log);
     cb = nm;
   }
 
--- a/src/share/vm/graal/graalCompiler.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Fri May 02 11:33:47 2014 +0200
@@ -44,7 +44,10 @@
 
 // Initialization
 void GraalCompiler::initialize() {
-  
+  if (!should_perform_init()) {
+    return;
+  }
+
   ThreadToNativeFromVM trans(JavaThread::current());
   JavaThread* THREAD = JavaThread::current();
   TRACE_graal_1("GraalCompiler::initialize");
@@ -100,7 +103,7 @@
     if (UseCompiler) {
       _external_deopt_i2c_entry = create_external_deopt_i2c();
 #ifdef COMPILERGRAAL
-      bool bootstrap = FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal;
+      bool bootstrap = UseGraalCompilationQueue && (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal);
 #else
       bool bootstrap = false;
 #endif
@@ -172,7 +175,7 @@
   return buffer_blob;
 }
 
-void GraalCompiler::compile_method(methodHandle method, int entry_bci, jboolean blocking) {
+void GraalCompiler::compile_method(methodHandle method, int entry_bci, CompileTask* task, jboolean blocking) {
   GRAAL_EXCEPTION_CONTEXT
   if (!_initialized) {
     CompilationPolicy::policy()->delay_compilation(method());
@@ -182,7 +185,7 @@
   assert(_initialized, "must already be initialized");
   ResourceMark rm;
   thread->set_is_graal_compiling(true);
-  VMToCompiler::compileMethod(method(), entry_bci, blocking);
+  VMToCompiler::compileMethod(method(), entry_bci, (jlong) (address) task, blocking);
   thread->set_is_graal_compiling(false);
 }
 
--- a/src/share/vm/graal/graalCompiler.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.hpp	Fri May 02 11:33:47 2014 +0200
@@ -60,7 +60,7 @@
   // Compilation entry point for methods
   virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
 
-  void compile_method(methodHandle target, int entry_bci, jboolean blocking);
+  void compile_method(methodHandle target, int entry_bci, CompileTask* task, jboolean blocking);
 
   // Print compilation timers and statistics
   virtual void print_timers();
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri May 02 11:33:47 2014 +0200
@@ -156,8 +156,6 @@
 
   //------------------------------------------------------------------------------------------------
 
-  set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
-
   set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
   set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address);
   set_address("osrMigrationEndAddress", SharedRuntime::OSR_migration_end);
--- a/src/share/vm/graal/graalGlobals.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalGlobals.hpp	Fri May 02 11:33:47 2014 +0200
@@ -52,6 +52,12 @@
   COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true,                 \
           "Bootstrap Graal before running Java main method"))               \
                                                                             \
+  COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, true,       \
+          "Use non-native compilation queue for Graal"))                    \
+                                                                            \
+  product(bool, ForceGraalInitialization, false,                            \
+          "Force VM to initialize the compiler even if not used")           \
+                                                                            \
   product(intx, TraceGraal, 0,                                              \
           "Trace level for Graal")                                          \
                                                                             \
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri May 02 11:33:47 2014 +0200
@@ -88,6 +88,7 @@
     oop_field(HotSpotCompiledNmethod, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                     \
     int_field(HotSpotCompiledNmethod, entryBCI)                                                                                                                \
     int_field(HotSpotCompiledNmethod, id)                                                                                                                      \
+    long_field(HotSpotCompiledNmethod, ctask)                                                                                                                  \
   end_class                                                                                                                                                    \
   start_class(HotSpotCompiledRuntimeStub)                                                                                                                      \
     oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;")                                                                                      \
--- a/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 02 11:33:47 2014 +0200
@@ -111,7 +111,7 @@
   check_pending_exception("Error while calling finalizeOptions");
 }
 
-void VMToCompiler::compileMethod(Method* method, int entry_bci, jboolean blocking) {
+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);
@@ -119,6 +119,7 @@
   args.push_oop(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);
   check_pending_exception("Error while calling compileMethod");
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 02 11:33:47 2014 +0200
@@ -60,8 +60,8 @@
   // public static void HotSpotOptions.finalizeOptions(boolean ciTime);
   static void finalizeOptions(jboolean ciTime);
 
-  // public abstract boolean compileMethod(long vmId, int entry_bci, boolean blocking);
-  static void compileMethod(Method* method, int entry_bci, jboolean blocking);
+  // 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();
--- a/src/share/vm/interpreter/linkResolver.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/interpreter/linkResolver.cpp	Fri May 02 11:33:47 2014 +0200
@@ -113,7 +113,7 @@
     // Note: with several active threads, the must_be_compiled may be true
     //       while can_be_compiled is false; remove assert
     // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile");
-    if (THREAD->is_Compiler_thread()) {
+    if (!THREAD->can_call_java()) {
       // don't force compilation, resolve was on behalf of compiler
       return;
     }
@@ -364,7 +364,7 @@
         return;
       }
     } else if (iid == vmIntrinsics::_invokeGeneric
-               && !THREAD->is_Compiler_thread()
+               && THREAD->can_call_java()
                && appendix_result_or_null != NULL) {
       // This is a method with type-checking semantics.
       // We will ask Java code to spin an adapter method for it.
--- a/src/share/vm/oops/method.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/oops/method.cpp	Fri May 02 11:33:47 2014 +0200
@@ -1314,7 +1314,7 @@
 
 // These two methods are static since a GC may move the Method
 bool Method::load_signature_classes(methodHandle m, TRAPS) {
-  if (THREAD->is_Compiler_thread()) {
+  if (!THREAD->can_call_java()) {
     // There is nothing useful this routine can do from within the Compile thread.
     // Hopefully, the signature contains only well-known classes.
     // We could scan for this and return true/false, but the caller won't care.
--- a/src/share/vm/prims/jni.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/prims/jni.cpp	Fri May 02 11:33:47 2014 +0200
@@ -5174,12 +5174,19 @@
     *(JNIEnv**)penv = thread->jni_environment();
 
 #ifdef GRAAL
-    // GraalCompiler needs to have been created in compileBroker.cpp
-    GraalCompiler* graal_compiler = GraalCompiler::instance();
-    if (graal_compiler != NULL) {
-      graal_compiler->initialize();
+    if (COMPILERGRAAL_PRESENT(UseGraalCompilationQueue) NOT_COMPILERGRAAL(true)) {
+      // GraalCompiler needs to have been created in compileBroker.cpp
+      GraalCompiler* graal_compiler = GraalCompiler::instance();
+      if (ForceGraalInitialization && graal_compiler == NULL) {
+        graal_compiler = new GraalCompiler();
+      }
+      if (graal_compiler != NULL) {
+        graal_compiler->initialize();
+      } else {
+        assert(!UseCompiler, "why isn't there any compiler?");
+      }
     } else {
-      assert(!UseCompiler, "why isn't there any compiler?");
+      // Graal is initialized on a CompilerThread
     }
 #endif
 
--- a/src/share/vm/runtime/deoptimization.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp	Fri May 02 11:33:47 2014 +0200
@@ -359,7 +359,8 @@
 #ifdef ASSERT
   assert(cb->is_deoptimization_stub() ||
          cb->is_uncommon_trap_stub() ||
-         strcmp("Stub<DeoptimizationStub.uncommonTrapHandler>", cb->name()) == 0,
+         strcmp("Stub<DeoptimizationStub.deoptimizationHandler>", cb->name()) == 0 ||
+         strcmp("Stub<UncommonTrapStub.uncommonTrapHandler>", cb->name()) == 0,
          err_msg("unexpected code blob: %s", cb->name()));
 #endif
 #else
--- a/src/share/vm/runtime/globals.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/runtime/globals.hpp	Fri May 02 11:33:47 2014 +0200
@@ -980,6 +980,9 @@
   product(bool, PrintNMethodStatistics, false,                              \
           "Print a summary statistic for the generated nmethods")           \
                                                                             \
+  product(bool, ShareDebugInfo, IS_GRAAL_DEFINED,                           \
+          "Always tries to share similar debug info inside a nmethod")      \
+                                                                            \
   diagnostic(bool, PrintNMethods, false,                                    \
           "Print assembly code for nmethods when generated")                \
                                                                             \
--- a/src/share/vm/runtime/javaCalls.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/runtime/javaCalls.cpp	Fri May 02 11:33:47 2014 +0200
@@ -52,7 +52,7 @@
 
   guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code");
   assert(!thread->owns_locks(), "must release all locks when leaving VM");
-  guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler");
+  guarantee(thread->can_call_java(), "cannot make java calls from the compiler");
   _result   = result;
 
   // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub,
@@ -366,7 +366,7 @@
 #endif
 
 
-  assert(!thread->is_Compiler_thread(), "cannot compile from the compiler");
+  assert(thread->can_call_java(), "cannot compile from the compiler");
   if (CompilationPolicy::must_be_compiled(method)) {
     CompileBroker::compile_method(method, InvocationEntryBci,
                                   CompilationPolicy::policy()->initial_compile_level(),
--- a/src/share/vm/runtime/thread.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/runtime/thread.cpp	Fri May 02 11:33:47 2014 +0200
@@ -1680,9 +1680,11 @@
   if (_thread_stat != NULL) delete _thread_stat;
 
 #ifdef GRAAL
-  if (GraalCounterSize > 0 && graal_counters_include(threadObj())) {
-    for (int i = 0; i < GraalCounterSize; i++) {
-      _graal_old_thread_counters[i] += _graal_counters[i];
+  if (GraalCounterSize > 0) {
+    if (graal_counters_include(threadObj())) {
+      for (int i = 0; i < GraalCounterSize; i++) {
+        _graal_old_thread_counters[i] += _graal_counters[i];
+      }
     }
     FREE_C_HEAP_ARRAY(jlong, _graal_counters, mtInternal);
   }
@@ -2251,7 +2253,7 @@
 
   // Do not throw asynchronous exceptions against the compiler thread
   // (the compiler thread should not be a Java thread -- fix in 1.4.2)
-  if (is_Compiler_thread()) return;
+  if (!can_call_java()) return;
 
   {
     // Actually throw the Throwable against the target Thread - however
@@ -3309,6 +3311,12 @@
 #endif
 }
 
+#ifdef COMPILERGRAAL
+bool CompilerThread::can_call_java() const {
+  return _compiler != NULL && _compiler->is_graal();
+}
+#endif
+
 void CompilerThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
   JavaThread::oops_do(f, cld_f, cf);
   if (_scanned_nmethod != NULL && cf != NULL) {
@@ -4332,7 +4340,7 @@
   {
     MutexLockerEx ml(doLock ? Threads_lock : NULL);
     ALL_JAVA_THREADS(p) {
-      if (p->is_Compiler_thread()) continue;
+      if (!p->can_call_java()) continue;
 
       address pending = (address)p->current_pending_monitor();
       if (pending == monitor) {             // found a match
--- a/src/share/vm/runtime/thread.hpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/runtime/thread.hpp	Fri May 02 11:33:47 2014 +0200
@@ -321,6 +321,9 @@
   virtual bool is_Named_thread() const               { return false; }
   virtual bool is_Worker_thread() const              { return false; }
 
+  // Can this thread make Java upcalls
+  virtual bool can_call_java() const                 { return true;  }
+
   // Casts
   virtual WorkerThread* as_Worker_thread() const     { return NULL; }
 
@@ -1876,8 +1879,13 @@
   CompilerThread(CompileQueue* queue, CompilerCounters* counters);
 
   bool is_Compiler_thread() const                { return true; }
+
+#ifdef COMPILERGRAAL
+  virtual bool can_call_java() const;
+#endif
+
   // Hide this compiler thread from external view.
-  bool is_hidden_from_external_view() const      { return true; }
+  bool is_hidden_from_external_view() const      { return !can_call_java(); }
 
   void set_compiler(AbstractCompiler* c)         { _compiler = c; }
   AbstractCompiler* compiler() const             { return _compiler; }
--- a/src/share/vm/runtime/vmStructs.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/runtime/vmStructs.cpp	Fri May 02 11:33:47 2014 +0200
@@ -1307,6 +1307,7 @@
   nonstatic_field(CompileTask,                 _osr_bci,                                     int)                                    \
   nonstatic_field(CompileTask,                 _comp_level,                                  int)                                    \
   nonstatic_field(CompileTask,                 _compile_id,                                  uint)                                   \
+  nonstatic_field(CompileTask,                 _num_inlined_bytecodes,                       int)                                    \
   nonstatic_field(CompileTask,                 _next,                                        CompileTask*)                           \
   nonstatic_field(CompileTask,                 _prev,                                        CompileTask*)                           \
                                                                                                                                      \
--- a/src/share/vm/utilities/exceptions.cpp	Fri May 02 10:46:52 2014 +0200
+++ b/src/share/vm/utilities/exceptions.cpp	Fri May 02 11:33:47 2014 +0200
@@ -84,7 +84,7 @@
 #endif // ASSERT
 
   if (thread->is_VM_thread()
-      || thread->is_Compiler_thread() ) {
+      || !thread->can_call_java() ) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
     thread->set_pending_exception(Universe::vm_exception(), file, line);
@@ -107,7 +107,7 @@
   }
 
   if (thread->is_VM_thread()
-      || thread->is_Compiler_thread() ) {
+      || !thread->can_call_java() ) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
     thread->set_pending_exception(Universe::vm_exception(), file, line);
--- a/test/baseline_whitelist.txt	Fri May 02 10:46:52 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-com.oracle.graal.jtt.loop.Loop03
-com.oracle.graal.jtt.loop.Loop04
-com.oracle.graal.jtt.loop.Loop08
-com.oracle.graal.jtt.loop.Loop11
-com.oracle.graal.jtt.bytecode.BC_iadd
-com.oracle.graal.jtt.bytecode.BC_iadd2
-com.oracle.graal.jtt.bytecode.BC_iadd3
-com.oracle.graal.jtt.bytecode.BC_ifeq_2
-com.oracle.graal.jtt.bytecode.BC_ifeq_3
-com.oracle.graal.jtt.bytecode.BC_ifeq
-com.oracle.graal.jtt.bytecode.BC_aload_3
-com.oracle.graal.jtt.bytecode.BC_aload_2
-com.oracle.graal.jtt.bytecode.BC_aload_1
-com.oracle.graal.jtt.bytecode.BC_aload_0
-com.oracle.graal.jtt.bytecode.BC_areturn
-com.oracle.graal.jtt.bytecode.BC_freturn
-com.oracle.graal.jtt.bytecode.BC_iconst
-com.oracle.graal.jtt.bytecode.BC_ireturn
-com.oracle.graal.jtt.bytecode.BC_lreturn
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/whitelist_baseline.txt	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,19 @@
+# com.oracle.graal.jtt.loop.Loop03
+# com.oracle.graal.jtt.loop.Loop04
+# com.oracle.graal.jtt.loop.Loop08
+# com.oracle.graal.jtt.loop.Loop11
+com.oracle.graal.jtt.bytecode.BC_iadd
+com.oracle.graal.jtt.bytecode.BC_iadd2
+com.oracle.graal.jtt.bytecode.BC_iadd3
+com.oracle.graal.jtt.bytecode.BC_ifeq_2
+com.oracle.graal.jtt.bytecode.BC_ifeq_3
+com.oracle.graal.jtt.bytecode.BC_ifeq
+com.oracle.graal.jtt.bytecode.BC_aload_3
+com.oracle.graal.jtt.bytecode.BC_aload_2
+com.oracle.graal.jtt.bytecode.BC_aload_1
+com.oracle.graal.jtt.bytecode.BC_aload_0
+com.oracle.graal.jtt.bytecode.BC_areturn
+com.oracle.graal.jtt.bytecode.BC_freturn
+com.oracle.graal.jtt.bytecode.BC_iconst
+com.oracle.graal.jtt.bytecode.BC_ireturn
+com.oracle.graal.jtt.bytecode.BC_lreturn
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/whitelist_shortunittest.txt	Fri May 02 11:33:47 2014 +0200
@@ -0,0 +1,1 @@
+com.oracle.graal.jtt.bytecode.*