changeset 15525:b3fbf52f34be

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Wed, 30 Apr 2014 13:40:36 +0200
parents 901b4440a451 (current diff) 2f684eda1938 (diff)
children 5ecbed00da23
files graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java
diffstat 84 files changed, 1684 insertions(+), 2457 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Apr 30 13:36:41 2014 +0200
+++ b/.hgignore	Wed Apr 30 13:40:36 2014 +0200
@@ -87,3 +87,4 @@
 agent/build/*
 agent/make/filelist
 agent/make/sa17.tar.gz
+export.json
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Wed Apr 30 13:40:36 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.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java	Wed Apr 30 13:40:36 2014 +0200
@@ -136,6 +136,11 @@
         emitAddrOp("lda_global_u64", dest, addr);
     }
 
+    public final void emitLea(Value dest, HSAILAddress addr) {
+        String prefix = getArgType(dest);
+        emitString(String.format("add_%s %s, $%s, 0x%s;", prefix, HSAIL.mapRegister(dest), addr.getBase().name, Long.toHexString(addr.getDisplacement())));
+    }
+
     public final void emitLoadKernelArg(Value dest, String kernArgName, String argTypeStr) {
         emitString("ld_kernarg_" + argTypeStr + " " + HSAIL.mapRegister(dest) + ", [" + kernArgName + "];");
     }
@@ -250,6 +255,9 @@
             case Byte:
                 prefix = "s8";
                 break;
+            case Boolean:
+                prefix = "u8";
+                break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java	Wed Apr 30 13:36:41 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.getLIRGeneratorTool().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.getLIRGeneratorTool().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.getLIRGeneratorTool().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.getLIRGeneratorTool().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.getLIRGeneratorTool().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.getLIRGeneratorTool().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.getLIRGeneratorTool().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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Wed Apr 30 13:40:36 2014 +0200
@@ -41,7 +41,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 
 public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
 
@@ -49,17 +48,6 @@
         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();
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Wed Apr 30 13:40:36 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/lambda/NewStringEqualsTest.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java	Wed Apr 30 13:40:36 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.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Wed Apr 30 13:40:36 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/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Apr 30 13:40:36 2014 +0200
@@ -216,16 +216,11 @@
             matchComplexExpressions(nodes);
         }
 
-        int instructionsFolded = 0;
         for (int i = 0; i < nodes.size(); i++) {
             Node instr = nodes.get(i);
             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()
 
@@ -234,15 +229,12 @@
                 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 (Value.INTERIOR_MATCH.equals(operand)) {
@@ -304,152 +296,6 @@
         }
     }
 
-    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;
-                    }
-                    ValueNode firstOperation = operation;
-                    if (operation instanceof LogicNode) {
-                        if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) {
-                            ValueNode ifNode = (ValueNode) operation.usages().first();
-                            if (!nodes.contains(ifNode)) {
-                                MemoryFoldFailedDifferentBlock.increment();
-                                Debug.log("if node %1s in different block from %1s", ifNode, operation);
-                                try (Indent indent = Debug.logAndIndent("checking operations")) {
-                                    int start = nodes.indexOf(access);
-                                    int end = nodes.indexOf(operation);
-                                    for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
-                                        Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
-                                    }
-                                }
-                                return 0;
-                            } else {
-                                operation = ifNode;
-                            }
-                        }
-                    }
-                    if (Debug.isLogEnabled()) {
-                        synchronized (LOG_OUTPUT_LOCK) {  // Hack to ensure the output is grouped.
-                            try (Indent indent = Debug.logAndIndent("checking operations")) {
-                                int start = nodes.indexOf(access);
-                                int end = nodes.indexOf(operation);
-                                for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
-                                    Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
-                                }
-                            }
-                        }
-                    }
-                    // Possible lowerable operation in the same block. Check out the dependencies.
-                    int opIndex = nodes.indexOf(operation);
-                    int current = i + 1;
-                    ArrayList<ValueNode> deferred = null;
-                    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) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java	Wed Apr 30 13:40:36 2014 +0200
@@ -26,10 +26,11 @@
 
 /**
  * Code generator for complex match patterns.
- *
- * @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.
  */
 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);
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Wed Apr 30 13:40:36 2014 +0200
@@ -159,7 +159,7 @@
         return new HotSpotSnippetReflectionProvider();
     }
 
-    protected AMD64HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
         return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
     }
 
@@ -189,15 +189,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             *
+             * 
              * Draft Version 0.96
-             *
+             * 
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             *
+             * 
              * 3.2.1
-             *
+             * 
              * ...
-             *
+             * 
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Apr 30 13:40:36 2014 +0200
@@ -548,6 +548,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);
@@ -570,6 +578,11 @@
         }
 
         @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);
@@ -589,7 +602,7 @@
                     masm.cmpl(x.toAddress(), 0xdeaddead);
                 }
             } else {
-                masm.cmpl(asRegister(y), x.toAddress());
+                masm.cmpl(asNarrowReg(y), x.toAddress());
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Wed Apr 30 13:40:36 2014 +0200
@@ -31,7 +31,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.amd64.*;
 
-public class AMD64HotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     private AMD64ConvertSnippets.Templates convertSnippets;
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java	Wed Apr 30 13:36:41 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +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 com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.amd64.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotLIRGenerator.CompareMemoryCompressedOp;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Specialized code gen for comparison with compressed memory.
- */
-
-public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole {
-    AMD64HotSpotMemoryPeephole(AMD64NodeLIRBuilder gen) {
-        super(gen);
-    }
-
-    @Override
-    protected Kind getMemoryKind(Access access) {
-        PlatformKind kind = gen.getLIRGeneratorTool().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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Wed Apr 30 13:40:36 2014 +0200
@@ -65,32 +65,38 @@
         return result;
     }
 
-    private void emitCompareCompressedMemory(IfNode ifNode, ValueNode value, Access access, CompareNode compare) {
+    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();
-        LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
-        LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
-        double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
         Value left;
         Value right;
         if (access == filterCompression(compare.x())) {
-            if (value.isConstant()) {
-                left = value.asConstant();
-            } else {
-                left = gen.loadNonConst(operand(value));
-            }
-            right = makeAddress(access);
+            left = value;
+            right = address;
         } else {
             assert access == filterCompression(compare.y());
-            left = makeAddress(access);
-            right = gen.loadNonConst(operand(value));
+            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());
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Wed Apr 30 13:40:36 2014 +0200
@@ -36,6 +36,10 @@
 @ServiceProvider(HotSpotBackendFactory.class)
 public class HSAILHotSpotBackendFactory implements HotSpotBackendFactory {
 
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        return new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
+    }
+
     @Override
     public HSAILHotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend hostBackend) {
         HotSpotProviders host = hostBackend.getProviders();
@@ -45,7 +49,7 @@
         HSAILHotSpotCodeCacheProvider codeCache = new HSAILHotSpotCodeCacheProvider(runtime, createTarget());
         ConstantReflectionProvider constantReflection = host.getConstantReflection();
         HotSpotForeignCallsProvider foreignCalls = new HSAILHotSpotForeignCallsProvider(runtime, metaAccess, codeCache);
-        LoweringProvider lowerer = new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
+        HotSpotLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers);
         // Replacements cannot have speculative optimizations since they have
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Wed Apr 30 13:40:36 2014 +0200
@@ -37,7 +37,7 @@
 
 import java.util.HashMap;
 
-public class HSAILHotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class HSAILHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     private HSAILNewObjectSnippets.Templates hsailNewObjectSnippets;
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Wed Apr 30 13:40:36 2014 +0200
@@ -30,7 +30,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class SPARCHotSpotLoweringProvider extends HotSpotLoweringProvider {
+public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
 
     public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
         super(runtime, metaAccess, foreignCalls, registers);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Apr 30 13:40:36 2014 +0200
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.meta;
+
+import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
+import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.debug.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * HotSpot implementation of {@link LoweringProvider}.
+ */
+public class DefaultHotSpotLoweringProvider implements HotSpotLoweringProvider {
+
+    protected final HotSpotGraalRuntime runtime;
+    protected final MetaAccessProvider metaAccess;
+    protected final ForeignCallsProvider foreignCalls;
+    protected final HotSpotRegistersProvider registers;
+
+    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
+    protected InstanceOfSnippets.Templates instanceofSnippets;
+    protected NewObjectSnippets.Templates newObjectSnippets;
+    protected MonitorSnippets.Templates monitorSnippets;
+    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
+    protected BoxingSnippets.Templates boxingSnippets;
+    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
+    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
+
+    public DefaultHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        this.runtime = runtime;
+        this.metaAccess = metaAccess;
+        this.foreignCalls = foreignCalls;
+        this.registers = registers;
+    }
+
+    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
+        TargetDescription target = providers.getCodeCache().getTarget();
+        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
+        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
+        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
+        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
+        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
+        boxingSnippets = new BoxingSnippets.Templates(providers, providers.getSnippetReflection(), target);
+        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
+        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
+        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        StructuredGraph graph = (StructuredGraph) n.graph();
+
+        if (n instanceof ArrayLengthNode) {
+            lowerArrayLengthNode((ArrayLengthNode) n, tool);
+        } else if (n instanceof Invoke) {
+            lowerInvoke((Invoke) n, tool, graph);
+        } else if (n instanceof LoadFieldNode) {
+            lowerLoadFieldNode((LoadFieldNode) n, tool);
+        } else if (n instanceof StoreFieldNode) {
+            lowerStoreFieldNode((StoreFieldNode) n, tool);
+        } else if (n instanceof CompareAndSwapNode) {
+            lowerCompareAndSwapNode((CompareAndSwapNode) n);
+        } else if (n instanceof AtomicReadAndWriteNode) {
+            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
+        } else if (n instanceof LoadIndexedNode) {
+            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
+        } else if (n instanceof StoreIndexedNode) {
+            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
+        } else if (n instanceof UnsafeLoadNode) {
+            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
+        } else if (n instanceof UnsafeStoreNode) {
+            lowerUnsafeStoreNode((UnsafeStoreNode) n);
+        } else if (n instanceof JavaReadNode) {
+            lowerJavaReadNode((JavaReadNode) n);
+        } else if (n instanceof JavaWriteNode) {
+            lowerJavaWriteNode((JavaWriteNode) n);
+        } else if (n instanceof LoadHubNode) {
+            lowerLoadHubNode((LoadHubNode) n);
+        } else if (n instanceof LoadMethodNode) {
+            lowerLoadMethodNode((LoadMethodNode) n);
+        } else if (n instanceof StoreHubNode) {
+            lowerStoreHubNode((StoreHubNode) n, graph);
+        } else if (n instanceof CommitAllocationNode) {
+            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
+        } else if (n instanceof OSRStartNode) {
+            lowerOSRStartNode((OSRStartNode) n);
+        } else if (n instanceof DynamicCounterNode) {
+            lowerDynamicCounterNode((DynamicCounterNode) n);
+        } else if (n instanceof BytecodeExceptionNode) {
+            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
+        } else if (n instanceof CheckCastDynamicNode) {
+            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
+        } else if (n instanceof InstanceOfNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfNode) n, tool);
+            }
+        } else if (n instanceof InstanceOfDynamicNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
+            }
+        } else if (n instanceof NewInstanceNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewInstanceNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool);
+            }
+        } else if (n instanceof NewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewArrayNode) n, registers, tool);
+            }
+        } else if (n instanceof DynamicNewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool);
+            }
+        } else if (n instanceof MonitorEnterNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                monitorSnippets.lower((MonitorEnterNode) n, registers, tool);
+            }
+        } else if (n instanceof MonitorExitNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                monitorSnippets.lower((MonitorExitNode) n, tool);
+            }
+        } else if (n instanceof G1PreWriteBarrier) {
+            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1PostWriteBarrier) {
+            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ReferentFieldReadBarrier) {
+            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
+        } else if (n instanceof SerialWriteBarrier) {
+            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
+        } else if (n instanceof SerialArrayRangeWriteBarrier) {
+            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
+        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
+        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
+        } else if (n instanceof NewMultiArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+            }
+        } else if (n instanceof 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.
+        } else if (n instanceof BoxNode) {
+            boxingSnippets.lower((BoxNode) n, tool);
+        } else if (n instanceof UnboxNode) {
+            boxingSnippets.lower((UnboxNode) n, tool);
+        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
+            /* No lowering, we generate LIR directly for these nodes. */
+        } else {
+            throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
+        }
+    }
+
+    private void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
+        StructuredGraph graph = arrayLengthNode.graph();
+        ValueNode array = arrayLengthNode.array();
+        ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, graph),
+                        StampFactory.positiveInt(), BarrierType.NONE, false));
+        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
+        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
+    }
+
+    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
+        if (invoke.callTarget() instanceof MethodCallTargetNode) {
+            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+            NodeInputList<ValueNode> parameters = callTarget.arguments();
+            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
+            GuardingNode receiverNullCheck = null;
+            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isObjectNonNull(receiver)) {
+                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
+                invoke.setGuard(receiverNullCheck);
+            }
+            JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
+
+            LoweredCallTargetNode loweredCallTarget = null;
+            if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
+
+                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+                if (!hsMethod.getDeclaringClass().isInterface()) {
+                    if (hsMethod.isInVirtualMethodTable()) {
+                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+                        assert vtableEntryOffset > 0;
+                        Kind wordKind = runtime.getTarget().wordKind;
+                        ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
+
+                        ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
+                        // We use LocationNode.ANY_LOCATION for the reads that access the
+                        // compiled code entry as HotSpot does not guarantee they are final
+                        // values.
+                        ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
+                                        StampFactory.forKind(wordKind), BarrierType.NONE, false));
+
+                        loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
+                                        CallingConvention.Type.JavaCall));
+
+                        graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+                        graph.addAfterFixed(metaspaceMethod, compiledEntry);
+                    }
+                }
+            }
+
+            if (loweredCallTarget == null) {
+                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
+                                callTarget.invokeKind()));
+            }
+            callTarget.replaceAndDelete(loweredCallTarget);
+        }
+    }
+
+    private Stamp loadStamp(Stamp stamp, Kind kind) {
+        return loadStamp(stamp, kind, true);
+    }
+
+    private Stamp loadStamp(Stamp stamp, Kind kind, boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return StampTool.narrowingConversion(stamp, 8);
+
+            case Char:
+            case Short:
+                return StampTool.narrowingConversion(stamp, 16);
+
+            case Object:
+                if (compressible && runtime.getConfig().useCompressedOops) {
+                    return new NarrowOopStamp((ObjectStamp) stamp, runtime.getConfig().getOopEncoding());
+                }
+        }
+        return stamp;
+    }
+
+    public ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value) {
+        return implicitLoadConvert(graph, kind, value, true);
+    }
+
+    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
+        switch (kind) {
+            case Byte:
+            case Short:
+                return graph.unique(new SignExtendNode(value, 32));
+
+            case Boolean:
+            case Char:
+                return graph.unique(new ZeroExtendNode(value, 32));
+
+            case Object:
+                if (compressible && runtime.getConfig().useCompressedOops) {
+                    return CompressionNode.uncompress(value, runtime.getConfig().getOopEncoding());
+                }
+        }
+        return value;
+    }
+
+    private void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
+        StructuredGraph graph = loadField.graph();
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
+        ValueNode object = loadField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : loadField.object();
+        assert loadField.getKind() != Kind.Illegal;
+        BarrierType barrierType = getFieldLoadBarrierType(field);
+
+        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
+        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadStamp, barrierType, false));
+        ValueNode readValue = implicitLoadConvert(graph, field.getKind(), memoryRead);
+
+        loadField.replaceAtUsages(readValue);
+        graph.replaceFixed(loadField, memoryRead);
+
+        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
+
+        if (loadField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+            graph.addBeforeFixed(memoryRead, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
+            graph.addAfterFixed(memoryRead, postMembar);
+        }
+    }
+
+    public ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value) {
+        return implicitStoreConvert(graph, kind, value, true);
+    }
+
+    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                return graph.unique(new NarrowNode(value, 8));
+            case Char:
+            case Short:
+                return graph.unique(new NarrowNode(value, 16));
+            case Object:
+                if (compressible && runtime.getConfig().useCompressedOops) {
+                    return CompressionNode.compress(value, runtime.getConfig().getOopEncoding());
+                }
+        }
+        return value;
+    }
+
+    private void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
+        StructuredGraph graph = storeField.graph();
+        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
+        ValueNode object = storeField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : storeField.object();
+        BarrierType barrierType = getFieldStoreBarrierType(storeField);
+
+        ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
+        WriteNode memoryWrite = graph.add(new WriteNode(object, value, createFieldLocation(graph, field, false), barrierType, false));
+        memoryWrite.setStateAfter(storeField.stateAfter());
+        graph.replaceFixedWithFixed(storeField, memoryWrite);
+        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
+        FixedWithNextNode last = memoryWrite;
+        FixedWithNextNode first = memoryWrite;
+
+        if (storeField.isVolatile()) {
+            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            graph.addBeforeFixed(first, preMembar);
+            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+            graph.addAfterFixed(last, postMembar);
+        }
+    }
+
+    private void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
+        StructuredGraph graph = cas.graph();
+        Kind valueKind = cas.getValueKind();
+        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), valueKind, cas.displacement(), cas.offset(), graph, 1);
+
+        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected(), true);
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue(), true);
+
+        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, expectedValue, newValue, getCompareAndSwapBarrierType(cas), false));
+        atomicNode.setStateAfter(cas.stateAfter());
+        graph.replaceFixedWithFixed(cas, atomicNode);
+    }
+
+    private void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
+        StructuredGraph graph = n.graph();
+        Kind valueKind = n.getValueKind();
+        LocationNode location = IndexedLocationNode.create(n.getLocationIdentity(), valueKind, 0, n.offset(), graph, 1);
+
+        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
+
+        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(n.object(), location, newValue, getAtomicReadAndWriteBarrierType(n), false));
+        memoryRead.setStateAfter(n.stateAfter());
+
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
+
+        n.replaceAtUsages(readValue);
+        graph.replaceFixedWithFixed(n, memoryRead);
+    }
+
+    private void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
+        StructuredGraph graph = loadIndexed.graph();
+        Kind elementKind = loadIndexed.elementKind();
+        LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
+
+        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
+        ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadStamp, BarrierType.NONE, false));
+        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
+
+        memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
+
+        loadIndexed.replaceAtUsages(readValue);
+        graph.replaceFixed(loadIndexed, memoryRead);
+    }
+
+    private void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
+        StructuredGraph graph = storeIndexed.graph();
+        GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+        Kind elementKind = storeIndexed.elementKind();
+        LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
+
+        ValueNode value = storeIndexed.value();
+        ValueNode array = storeIndexed.array();
+
+        CheckCastNode checkcastNode = null;
+        CheckCastDynamicNode checkcastDynamicNode = null;
+        if (elementKind == Kind.Object && !StampTool.isObjectAlwaysNull(value)) {
+            // Store check!
+            ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+            if (arrayType != null && StampTool.isExactType(array)) {
+                ResolvedJavaType elementType = arrayType.getComponentType();
+                if (!MetaUtil.isJavaLangObject(elementType)) {
+                    checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
+                    graph.addBeforeFixed(storeIndexed, checkcastNode);
+                    value = checkcastNode;
+                }
+            } else {
+                Kind wordKind = runtime.getTarget().wordKind;
+                ValueNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
+                LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph);
+                /*
+                 * Anchor the read of the element klass to the cfg, because it is only valid when
+                 * arrayClass is an object class, which might not be the case in other parts of the
+                 * compiled method.
+                 */
+                FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
+                checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
+                graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
+                value = checkcastDynamicNode;
+            }
+        }
+        BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
+        WriteNode memoryWrite = graph.add(new WriteNode(array, implicitStoreConvert(graph, elementKind, value), arrayLocation, barrierType, false));
+        memoryWrite.setGuard(boundsCheck);
+        memoryWrite.setStateAfter(storeIndexed.stateAfter());
+        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
+
+        // Lower the associated checkcast node.
+        if (checkcastNode != null) {
+            checkcastNode.lower(tool);
+        } else if (checkcastDynamicNode != null) {
+            checkcastDynamicSnippets.lower(checkcastDynamicNode, tool);
+        }
+    }
+
+    private ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
+        boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+        Kind readKind = load.accessKind();
+        LocationNode location = createLocation(load);
+        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
+        ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, loadStamp, guard, BarrierType.NONE, false));
+        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
+        load.replaceAtUsages(readValue);
+        return memoryRead;
+    }
+
+    private void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
+        StructuredGraph graph = load.graph();
+        if (load.getGuardingCondition() != null) {
+            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
+            ReadNode memoryRead = createUnsafeRead(graph, load, valueAnchorNode);
+            graph.replaceFixedWithFixed(load, valueAnchorNode);
+            graph.addAfterFixed(valueAnchorNode, memoryRead);
+        } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
+            assert load.getKind() != Kind.Illegal;
+            if (addReadBarrier(load)) {
+                unsafeLoadSnippets.lower(load, tool);
+            } else {
+                ReadNode memoryRead = createUnsafeRead(graph, load, null);
+                // An unsafe read must not float outside its block otherwise
+                // it may float above an explicit null check on its object.
+                memoryRead.setGuard(BeginNode.prevBegin(load));
+                graph.replaceFixedWithFixed(load, memoryRead);
+            }
+        }
+    }
+
+    private void lowerUnsafeStoreNode(UnsafeStoreNode store) {
+        StructuredGraph graph = store.graph();
+        LocationNode location = createLocation(store);
+        ValueNode object = store.object();
+        BarrierType barrierType = getUnsafeStoreBarrierType(store);
+        boolean compressible = store.value().getKind() == Kind.Object;
+        Kind valueKind = store.accessKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
+        WriteNode write = graph.add(new WriteNode(object, value, location, barrierType, false));
+        write.setStateAfter(store.stateAfter());
+        graph.replaceFixedWithFixed(store, write);
+    }
+
+    private void lowerJavaReadNode(JavaReadNode read) {
+        StructuredGraph graph = read.graph();
+
+        Kind valueKind = read.location().getValueKind();
+        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
+        ReadNode memoryRead = graph.add(new ReadNode(read.object(), read.location(), loadStamp, read.getBarrierType(), false));
+        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
+
+        memoryRead.setGuard(read.getGuard());
+
+        read.replaceAtUsages(readValue);
+        graph.replaceFixed(read, memoryRead);
+    }
+
+    private void lowerJavaWriteNode(JavaWriteNode write) {
+        StructuredGraph graph = write.graph();
+
+        Kind valueKind = write.location().getValueKind();
+        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
+
+        WriteNode memoryWrite = graph.add(new WriteNode(write.object(), value, write.location(), write.getBarrierType(), false, write.isInitialization()));
+        memoryWrite.setStateAfter(write.stateAfter());
+        graph.replaceFixedWithFixed(write, memoryWrite);
+
+        memoryWrite.setGuard(write.getGuard());
+    }
+
+    private void lowerLoadHubNode(LoadHubNode loadHub) {
+        StructuredGraph graph = loadHub.graph();
+        if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
+            Kind wordKind = runtime.getTarget().wordKind;
+            assert loadHub.getKind() == wordKind;
+            ValueNode object = loadHub.object();
+            GuardingNode guard = loadHub.getGuard();
+            ValueNode hub = createReadHub(graph, wordKind, object, guard);
+            graph.replaceFloating(loadHub, hub);
+        }
+    }
+
+    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
+        StructuredGraph graph = loadMethodNode.graph();
+        ResolvedJavaMethod method = loadMethodNode.getMethod();
+        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
+        graph.replaceFixed(loadMethodNode, metaspaceMethod);
+    }
+
+    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
+        WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue());
+        graph.replaceFixed(storeHub, hub);
+    }
+
+    private void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
+        StructuredGraph graph = commit.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+            BitSet omittedValues = new BitSet();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                FixedWithNextNode newObject;
+                if (virtual instanceof VirtualInstanceNode) {
+                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
+                } else {
+                    newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
+                }
+                graph.addBeforeFixed(commit, newObject);
+                allocations[objIndex] = newObject;
+                for (int i = 0; i < entryCount; i++) {
+                    ValueNode value = commit.getValues().get(valuePos);
+                    if (value instanceof VirtualObjectNode) {
+                        value = allocations[commit.getVirtualObjects().indexOf(value)];
+                    }
+                    if (value == null) {
+                        omittedValues.set(valuePos);
+                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                        // Constant.illegal is always the defaultForKind, so it is skipped
+                        Kind valueKind = value.getKind();
+                        Kind entryKind = virtual.entryKind(i);
+
+                        // Truffle requires some leniency in terms of what can be put where:
+                        Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
+                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
+                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
+                        ConstantLocationNode location;
+                        BarrierType barrierType;
+                        if (virtual instanceof VirtualInstanceNode) {
+                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
+                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
+                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
+                        } else {
+                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
+                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
+                        }
+                        WriteNode write = new WriteNode(newObject, implicitStoreConvert(graph, entryKind, value), location, barrierType, false);
+                        graph.addAfterFixed(newObject, graph.add(write));
+                    }
+                    valuePos++;
+
+                }
+            }
+            valuePos = 0;
+
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+                ValueNode newObject = allocations[objIndex];
+                for (int i = 0; i < entryCount; i++) {
+                    if (omittedValues.get(valuePos)) {
+                        ValueNode value = commit.getValues().get(valuePos);
+                        assert value instanceof VirtualObjectNode;
+                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
+                            WriteNode write;
+                            if (virtual instanceof VirtualInstanceNode) {
+                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i),
+                                                true), BarrierType.IMPRECISE, false);
+                            } else {
+                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph),
+                                                true), BarrierType.PRECISE, false);
+                            }
+                            graph.addBeforeFixed(commit, graph.add(write));
+                        }
+                    }
+                    valuePos++;
+                }
+            }
+
+            finishAllocatedObjects(tool, commit, allocations);
+            graph.removeFixed(commit);
+        }
+    }
+
+    private void lowerOSRStartNode(OSRStartNode osrStart) {
+        StructuredGraph graph = osrStart.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            StartNode newStart = graph.add(new StartNode());
+            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
+            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
+            migrationEnd.setStateAfter(osrStart.stateAfter());
+
+            newStart.setNext(migrationEnd);
+            FixedNode next = osrStart.next();
+            osrStart.setNext(null);
+            migrationEnd.setNext(next);
+            graph.setStart(newStart);
+
+            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
+            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
+                int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind());
+                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
+                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1);
+                ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
+                osrLocal.replaceAndDelete(load);
+                graph.addBeforeFixed(migrationEnd, load);
+            }
+            osrStart.replaceAtUsages(newStart);
+            osrStart.safeDelete();
+        }
+    }
+
+    private void lowerDynamicCounterNode(DynamicCounterNode n) {
+        StructuredGraph graph = n.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
+        }
+    }
+
+    static final class Exceptions {
+        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
+        protected static final NullPointerException cachedNullPointerException;
+
+        static {
+            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
+            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
+            cachedNullPointerException = new NullPointerException();
+            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
+        }
+    }
+
+    public static final class RuntimeCalls {
+        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
+        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
+    }
+
+    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
+        StructuredGraph graph = node.graph();
+        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
+            if (OmitHotExceptionStacktrace.getValue()) {
+                Throwable exception;
+                if (node.getExceptionClass() == NullPointerException.class) {
+                    exception = Exceptions.cachedNullPointerException;
+                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+                    exception = Exceptions.cachedArrayIndexOutOfBoundsException;
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+                FloatingNode exceptionNode = ConstantNode.forConstant(HotSpotObjectConstant.forObject(exception), metaAccess, graph);
+                graph.replaceFixedWithFloating(node, exceptionNode);
+
+            } else {
+                ForeignCallDescriptor descriptor;
+                if (node.getExceptionClass() == NullPointerException.class) {
+                    descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
+                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
+                    descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+
+                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
+                graph.replaceFixedWithFixed(node, foreignCallNode);
+            }
+        }
+    }
+
+    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++) {
+            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+            allocations[objIndex] = anchor;
+            graph.addBeforeFixed(commit, anchor);
+        }
+        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
+                graph.addBeforeFixed(commit, enter);
+                enter.lower(tool);
+            }
+        }
+        for (Node usage : commit.usages().snapshot()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+            graph.replaceFloating(addObject, allocations[index]);
+        }
+    }
+
+    private static LocationNode createLocation(UnsafeAccessNode access) {
+        return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind());
+    }
+
+    private static LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind) {
+        ValueNode offset = offsetNode;
+        if (offset.isConstant()) {
+            long offsetValue = offset.asConstant().asLong();
+            return ConstantLocationNode.create(locationIdentity, accessKind, offsetValue, offset.graph());
+        }
+
+        long displacement = 0;
+        int indexScaling = 1;
+        boolean signExtend = false;
+        if (offset instanceof SignExtendNode) {
+            SignExtendNode extend = (SignExtendNode) offset;
+            if (extend.getResultBits() == 64) {
+                signExtend = true;
+                offset = extend.getInput();
+            }
+        }
+        if (offset instanceof IntegerAddNode) {
+            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
+            if (integerAddNode.y() instanceof ConstantNode) {
+                displacement = integerAddNode.y().asConstant().asLong();
+                offset = integerAddNode.x();
+            }
+        }
+
+        if (offset instanceof LeftShiftNode) {
+            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
+            if (leftShiftNode.y() instanceof ConstantNode) {
+                long shift = leftShiftNode.y().asConstant().asLong();
+                if (shift >= 1 && shift <= 3) {
+                    if (shift == 1) {
+                        indexScaling = 2;
+                    } else if (shift == 2) {
+                        indexScaling = 4;
+                    } else {
+                        indexScaling = 8;
+                    }
+                    offset = leftShiftNode.x();
+                }
+            }
+        }
+        if (signExtend) {
+            // If we were using sign extended values before restore the sign extension.
+            offset = offset.graph().addOrUnique(new SignExtendNode(offset, 64));
+        }
+        return IndexedLocationNode.create(locationIdentity, accessKind, displacement, offset, offset.graph(), indexScaling);
+    }
+
+    private static boolean addReadBarrier(UnsafeLoadNode load) {
+        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
+                        !StampTool.isObjectAlwaysNull(load.object())) {
+            ResolvedJavaType type = StampTool.typeOrNull(load.object());
+            if (type != null && !type.isArray()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
+        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+        assert !hsMethod.getDeclaringClass().isInterface();
+        assert hsMethod.isInVirtualMethodTable();
+
+        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+        assert vtableEntryOffset > 0;
+        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
+        // entry as HotSpot does not guarantee that this is a final value.
+        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false));
+        return metaspaceMethod;
+    }
+
+    private ValueNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+
+        Stamp hubStamp;
+        if (config.useCompressedClassPointers) {
+            hubStamp = StampFactory.forInteger(32);
+        } else {
+            hubStamp = StampFactory.forKind(wordKind);
+        }
+
+        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(object, location, null, hubStamp, guard, BarrierType.NONE, false));
+        if (config.useCompressedClassPointers) {
+            return CompressionNode.uncompress(memoryRead, config.getKlassEncoding());
+        } else {
+            return memoryRead;
+        }
+    }
+
+    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+
+        ValueNode writeValue = value;
+        if (config.useCompressedClassPointers) {
+            writeValue = CompressionNode.compress(value, config.getKlassEncoding());
+        }
+
+        return graph.add(new WriteNode(object, writeValue, location, BarrierType.NONE, false));
+    }
+
+    private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
+        BarrierType barrierType = BarrierType.NONE;
+        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
+            barrierType = BarrierType.PRECISE;
+        }
+        return barrierType;
+    }
+
+    private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
+        if (storeField.field().getKind() == Kind.Object) {
+            return BarrierType.IMPRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
+        if (store.elementKind() == Kind.Object) {
+            return BarrierType.PRECISE;
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
+        if (store.value().getKind() == Kind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(store.object());
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getCompareAndSwapBarrierType(CompareAndSwapNode cas) {
+        if (cas.expected().getKind() == Kind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(cas.object());
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    private static BarrierType getAtomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
+        if (n.newValue().getKind() == Kind.Object) {
+            ResolvedJavaType type = StampTool.typeOrNull(n.object());
+            if (type != null && !type.isArray()) {
+                return BarrierType.IMPRECISE;
+            } else {
+                return BarrierType.PRECISE;
+            }
+        }
+        return BarrierType.NONE;
+    }
+
+    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : field;
+        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
+    }
+
+    public int getScalingFactor(Kind kind) {
+        if (useCompressedOops() && kind == Kind.Object) {
+            return this.runtime.getTarget().getSizeInBytes(Kind.Int);
+        } else {
+            return this.runtime.getTarget().getSizeInBytes(kind);
+        }
+    }
+
+    @Override
+    public IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
+        int scale = getScalingFactor(elementKind);
+        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
+    }
+
+    @Override
+    public ValueNode reconstructArrayIndex(LocationNode location) {
+        Kind elementKind = location.getValueKind();
+        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
+
+        long base;
+        ValueNode index;
+        int scale = getScalingFactor(elementKind);
+
+        if (location instanceof ConstantLocationNode) {
+            base = ((ConstantLocationNode) location).getDisplacement();
+            index = null;
+        } else if (location instanceof IndexedLocationNode) {
+            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
+            assert indexedLocation.getIndexScaling() == scale;
+            base = indexedLocation.getDisplacement();
+            index = indexedLocation.getIndex();
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        base -= getArrayBaseOffset(elementKind);
+        assert base >= 0 && base % scale == 0;
+
+        base /= scale;
+        assert NumUtil.isInt(base);
+
+        StructuredGraph graph = location.graph();
+        if (index == null) {
+            return ConstantNode.forInt((int) base, graph);
+        } else {
+            if (base == 0) {
+                return index;
+            } else {
+                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
+            }
+        }
+    }
+
+    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
+        StructuredGraph g = n.graph();
+        ValueNode array = n.array();
+        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
+        if (arrayLength == null) {
+            Stamp stamp = StampFactory.positiveInt();
+            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
+            g.addBeforeFixed(n, readArrayLength);
+            readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
+            arrayLength = readArrayLength;
+        }
+
+        if (arrayLength.isConstant() && n.index().isConstant()) {
+            int l = arrayLength.asConstant().asInt();
+            int i = n.index().asConstant().asInt();
+            if (i >= 0 && i < l) {
+                // unneeded range check
+                return null;
+            }
+        }
+
+        return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+    }
+
+    private static GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
+        if (StampTool.isObjectNonNull(object)) {
+            return null;
+        }
+        return tool.createGuard(before, before.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Apr 30 13:40:36 2014 +0200
@@ -44,7 +44,7 @@
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
-import static com.oracle.graal.hotspot.meta.HotSpotLoweringProvider.RuntimeCalls.*;
+import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.replacements.Log.*;
 import static com.oracle.graal.replacements.MathSubstitutionsX86.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Apr 30 13:40:36 2014 +0200
@@ -22,1006 +22,25 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
-import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.debug.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.replacements.*;
 
 /**
  * HotSpot implementation of {@link LoweringProvider}.
  */
-public class HotSpotLoweringProvider implements LoweringProvider {
-
-    protected final HotSpotGraalRuntime runtime;
-    protected final MetaAccessProvider metaAccess;
-    protected final ForeignCallsProvider foreignCalls;
-    protected final HotSpotRegistersProvider registers;
-
-    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
-    protected InstanceOfSnippets.Templates instanceofSnippets;
-    protected NewObjectSnippets.Templates newObjectSnippets;
-    protected MonitorSnippets.Templates monitorSnippets;
-    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
-    protected BoxingSnippets.Templates boxingSnippets;
-    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
-    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
-
-    public HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
-        this.runtime = runtime;
-        this.metaAccess = metaAccess;
-        this.foreignCalls = foreignCalls;
-        this.registers = registers;
-    }
-
-    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
-        TargetDescription target = providers.getCodeCache().getTarget();
-        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
-        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
-        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
-        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
-        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
-        boxingSnippets = new BoxingSnippets.Templates(providers, providers.getSnippetReflection(), target);
-        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
-        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
-        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
-    }
-
-    @Override
-    public void lower(Node n, LoweringTool tool) {
-        StructuredGraph graph = (StructuredGraph) n.graph();
-
-        if (n instanceof ArrayLengthNode) {
-            lowerArrayLengthNode((ArrayLengthNode) n, tool);
-        } else if (n instanceof Invoke) {
-            lowerInvoke((Invoke) n, tool, graph);
-        } else if (n instanceof LoadFieldNode) {
-            lowerLoadFieldNode((LoadFieldNode) n, tool);
-        } else if (n instanceof StoreFieldNode) {
-            lowerStoreFieldNode((StoreFieldNode) n, tool);
-        } else if (n instanceof CompareAndSwapNode) {
-            lowerCompareAndSwapNode((CompareAndSwapNode) n);
-        } else if (n instanceof AtomicReadAndWriteNode) {
-            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
-        } else if (n instanceof LoadIndexedNode) {
-            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
-        } else if (n instanceof StoreIndexedNode) {
-            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
-        } else if (n instanceof UnsafeLoadNode) {
-            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
-        } else if (n instanceof UnsafeStoreNode) {
-            lowerUnsafeStoreNode((UnsafeStoreNode) n);
-        } else if (n instanceof JavaReadNode) {
-            lowerJavaReadNode((JavaReadNode) n);
-        } else if (n instanceof JavaWriteNode) {
-            lowerJavaWriteNode((JavaWriteNode) n);
-        } else if (n instanceof LoadHubNode) {
-            lowerLoadHubNode((LoadHubNode) n);
-        } else if (n instanceof LoadMethodNode) {
-            lowerLoadMethodNode((LoadMethodNode) n);
-        } else if (n instanceof StoreHubNode) {
-            lowerStoreHubNode((StoreHubNode) n, graph);
-        } else if (n instanceof CommitAllocationNode) {
-            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
-        } else if (n instanceof OSRStartNode) {
-            lowerOSRStartNode((OSRStartNode) n);
-        } else if (n instanceof DynamicCounterNode) {
-            lowerDynamicCounterNode((DynamicCounterNode) n);
-        } else if (n instanceof BytecodeExceptionNode) {
-            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
-        } else if (n instanceof CheckCastDynamicNode) {
-            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
-        } else if (n instanceof InstanceOfNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfNode) n, tool);
-            }
-        } else if (n instanceof InstanceOfDynamicNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
-            }
-        } else if (n instanceof NewInstanceNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
-            }
-        } else if (n instanceof DynamicNewInstanceNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool);
-            }
-        } else if (n instanceof NewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewArrayNode) n, registers, tool);
-            }
-        } else if (n instanceof DynamicNewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool);
-            }
-        } else if (n instanceof MonitorEnterNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                monitorSnippets.lower((MonitorEnterNode) n, registers, tool);
-            }
-        } else if (n instanceof MonitorExitNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                monitorSnippets.lower((MonitorExitNode) n, tool);
-            }
-        } else if (n instanceof G1PreWriteBarrier) {
-            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1PostWriteBarrier) {
-            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1ReferentFieldReadBarrier) {
-            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
-        } else if (n instanceof SerialWriteBarrier) {
-            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
-        } else if (n instanceof SerialArrayRangeWriteBarrier) {
-            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
-        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
-        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
-        } else if (n instanceof NewMultiArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
-            }
-        } else if (n instanceof 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.
-        } else if (n instanceof BoxNode) {
-            boxingSnippets.lower((BoxNode) n, tool);
-        } else if (n instanceof UnboxNode) {
-            boxingSnippets.lower((UnboxNode) n, tool);
-        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
-            /* No lowering, we generate LIR directly for these nodes. */
-        } else {
-            throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
-        }
-    }
-
-    private void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
-        StructuredGraph graph = arrayLengthNode.graph();
-        ValueNode array = arrayLengthNode.array();
-        ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, graph),
-                        StampFactory.positiveInt(), BarrierType.NONE, false));
-        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
-        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
-    }
-
-    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
-        if (invoke.callTarget() instanceof MethodCallTargetNode) {
-            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-            NodeInputList<ValueNode> parameters = callTarget.arguments();
-            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
-            GuardingNode receiverNullCheck = null;
-            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isObjectNonNull(receiver)) {
-                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
-                invoke.setGuard(receiverNullCheck);
-            }
-            JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
-
-            LoweredCallTargetNode loweredCallTarget = null;
-            if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
-
-                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
-                if (!hsMethod.getDeclaringClass().isInterface()) {
-                    if (hsMethod.isInVirtualMethodTable()) {
-                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-                        assert vtableEntryOffset > 0;
-                        Kind wordKind = runtime.getTarget().wordKind;
-                        ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
-
-                        ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
-                        // We use LocationNode.ANY_LOCATION for the reads that access the
-                        // compiled code entry as HotSpot does not guarantee they are final
-                        // values.
-                        ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
-                                        StampFactory.forKind(wordKind), BarrierType.NONE, false));
-
-                        loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
-                                        CallingConvention.Type.JavaCall));
-
-                        graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
-                        graph.addAfterFixed(metaspaceMethod, compiledEntry);
-                    }
-                }
-            }
-
-            if (loweredCallTarget == null) {
-                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
-                                callTarget.invokeKind()));
-            }
-            callTarget.replaceAndDelete(loweredCallTarget);
-        }
-    }
-
-    private Stamp loadStamp(Stamp stamp, Kind kind) {
-        return loadStamp(stamp, kind, true);
-    }
-
-    private Stamp loadStamp(Stamp stamp, Kind kind, boolean compressible) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                return StampTool.narrowingConversion(stamp, 8);
-
-            case Char:
-            case Short:
-                return StampTool.narrowingConversion(stamp, 16);
-
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return new NarrowOopStamp((ObjectStamp) stamp, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return stamp;
-    }
-
-    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value) {
-        return implicitLoadConvert(graph, kind, value, true);
-    }
-
-    private ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
-        switch (kind) {
-            case Byte:
-            case Short:
-                return graph.unique(new SignExtendNode(value, 32));
-
-            case Boolean:
-            case Char:
-                return graph.unique(new ZeroExtendNode(value, 32));
+public interface HotSpotLoweringProvider extends LoweringProvider {
 
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return CompressionNode.uncompress(value, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return value;
-    }
-
-    private void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
-        StructuredGraph graph = loadField.graph();
-        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
-        ValueNode object = loadField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : loadField.object();
-        assert loadField.getKind() != Kind.Illegal;
-        BarrierType barrierType = getFieldLoadBarrierType(field);
-
-        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
-        ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadStamp, barrierType, false));
-        ValueNode readValue = implicitLoadConvert(graph, field.getKind(), memoryRead);
-
-        loadField.replaceAtUsages(readValue);
-        graph.replaceFixed(loadField, memoryRead);
-
-        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
-
-        if (loadField.isVolatile()) {
-            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
-            graph.addBeforeFixed(memoryRead, preMembar);
-            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
-            graph.addAfterFixed(memoryRead, postMembar);
-        }
-    }
-
-    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value) {
-        return implicitStoreConvert(graph, kind, value, true);
-    }
-
-    private ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                return graph.unique(new NarrowNode(value, 8));
-            case Char:
-            case Short:
-                return graph.unique(new NarrowNode(value, 16));
-            case Object:
-                if (compressible && runtime.getConfig().useCompressedOops) {
-                    return CompressionNode.compress(value, runtime.getConfig().getOopEncoding());
-                }
-        }
-        return value;
-    }
-
-    private void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
-        StructuredGraph graph = storeField.graph();
-        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
-        ValueNode object = storeField.isStatic() ? ConstantNode.forConstant(HotSpotObjectConstant.forObject(field.getDeclaringClass().mirror()), metaAccess, graph) : storeField.object();
-        BarrierType barrierType = getFieldStoreBarrierType(storeField);
-
-        ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
-        WriteNode memoryWrite = graph.add(new WriteNode(object, value, createFieldLocation(graph, field, false), barrierType, false));
-        memoryWrite.setStateAfter(storeField.stateAfter());
-        graph.replaceFixedWithFixed(storeField, memoryWrite);
-        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
-        FixedWithNextNode last = memoryWrite;
-        FixedWithNextNode first = memoryWrite;
-
-        if (storeField.isVolatile()) {
-            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
-            graph.addBeforeFixed(first, preMembar);
-            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
-            graph.addAfterFixed(last, postMembar);
-        }
-    }
-
-    private void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
-        StructuredGraph graph = cas.graph();
-        Kind valueKind = cas.getValueKind();
-        LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), valueKind, cas.displacement(), cas.offset(), graph, 1);
-
-        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected(), true);
-        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue(), true);
-
-        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, expectedValue, newValue, getCompareAndSwapBarrierType(cas), false));
-        atomicNode.setStateAfter(cas.stateAfter());
-        graph.replaceFixedWithFixed(cas, atomicNode);
-    }
-
-    private void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
-        StructuredGraph graph = n.graph();
-        Kind valueKind = n.getValueKind();
-        LocationNode location = IndexedLocationNode.create(n.getLocationIdentity(), valueKind, 0, n.offset(), graph, 1);
-
-        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
-
-        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(n.object(), location, newValue, getAtomicReadAndWriteBarrierType(n), false));
-        memoryRead.setStateAfter(n.stateAfter());
-
-        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
-
-        n.replaceAtUsages(readValue);
-        graph.replaceFixedWithFixed(n, memoryRead);
-    }
-
-    private void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
-        StructuredGraph graph = loadIndexed.graph();
-        Kind elementKind = loadIndexed.elementKind();
-        LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
-
-        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
-        ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadStamp, BarrierType.NONE, false));
-        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
-
-        memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
-
-        loadIndexed.replaceAtUsages(readValue);
-        graph.replaceFixed(loadIndexed, memoryRead);
-    }
+    void initialize(HotSpotProviders providers, HotSpotVMConfig config);
 
-    private void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
-        StructuredGraph graph = storeIndexed.graph();
-        GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
-        Kind elementKind = storeIndexed.elementKind();
-        LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
-
-        ValueNode value = storeIndexed.value();
-        ValueNode array = storeIndexed.array();
-
-        CheckCastNode checkcastNode = null;
-        CheckCastDynamicNode checkcastDynamicNode = null;
-        if (elementKind == Kind.Object && !StampTool.isObjectAlwaysNull(value)) {
-            // Store check!
-            ResolvedJavaType arrayType = StampTool.typeOrNull(array);
-            if (arrayType != null && StampTool.isExactType(array)) {
-                ResolvedJavaType elementType = arrayType.getComponentType();
-                if (!MetaUtil.isJavaLangObject(elementType)) {
-                    checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
-                    graph.addBeforeFixed(storeIndexed, checkcastNode);
-                    value = checkcastNode;
-                }
-            } else {
-                Kind wordKind = runtime.getTarget().wordKind;
-                ValueNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
-                LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph);
-                /*
-                 * Anchor the read of the element klass to the cfg, because it is only valid when
-                 * arrayClass is an object class, which might not be the case in other parts of the
-                 * compiled method.
-                 */
-                FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
-                checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
-                graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
-                value = checkcastDynamicNode;
-            }
-        }
-        BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
-        WriteNode memoryWrite = graph.add(new WriteNode(array, implicitStoreConvert(graph, elementKind, value), arrayLocation, barrierType, false));
-        memoryWrite.setGuard(boundsCheck);
-        memoryWrite.setStateAfter(storeIndexed.stateAfter());
-        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
-
-        // Lower the associated checkcast node.
-        if (checkcastNode != null) {
-            checkcastNode.lower(tool);
-        } else if (checkcastDynamicNode != null) {
-            checkcastDynamicSnippets.lower(checkcastDynamicNode, tool);
-        }
-    }
-
-    private ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
-        boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-        Kind readKind = load.accessKind();
-        LocationNode location = createLocation(load);
-        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
-        ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, loadStamp, guard, BarrierType.NONE, false));
-        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
-        load.replaceAtUsages(readValue);
-        return memoryRead;
-    }
-
-    private void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
-        StructuredGraph graph = load.graph();
-        if (load.getGuardingCondition() != null) {
-            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
-            ReadNode memoryRead = createUnsafeRead(graph, load, valueAnchorNode);
-            graph.replaceFixedWithFixed(load, valueAnchorNode);
-            graph.addAfterFixed(valueAnchorNode, memoryRead);
-        } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
-            assert load.getKind() != Kind.Illegal;
-            if (addReadBarrier(load)) {
-                unsafeLoadSnippets.lower(load, tool);
-            } else {
-                ReadNode memoryRead = createUnsafeRead(graph, load, null);
-                // An unsafe read must not float outside its block otherwise
-                // it may float above an explicit null check on its object.
-                memoryRead.setGuard(BeginNode.prevBegin(load));
-                graph.replaceFixedWithFixed(load, memoryRead);
-            }
-        }
-    }
-
-    private void lowerUnsafeStoreNode(UnsafeStoreNode store) {
-        StructuredGraph graph = store.graph();
-        LocationNode location = createLocation(store);
-        ValueNode object = store.object();
-        BarrierType barrierType = getUnsafeStoreBarrierType(store);
-        boolean compressible = store.value().getKind() == Kind.Object;
-        Kind valueKind = store.accessKind();
-        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
-        WriteNode write = graph.add(new WriteNode(object, value, location, barrierType, false));
-        write.setStateAfter(store.stateAfter());
-        graph.replaceFixedWithFixed(store, write);
-    }
-
-    private void lowerJavaReadNode(JavaReadNode read) {
-        StructuredGraph graph = read.graph();
-
-        Kind valueKind = read.location().getValueKind();
-        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
-        ReadNode memoryRead = graph.add(new ReadNode(read.object(), read.location(), loadStamp, read.getBarrierType(), false));
-        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
-
-        memoryRead.setGuard(read.getGuard());
-
-        read.replaceAtUsages(readValue);
-        graph.replaceFixed(read, memoryRead);
-    }
-
-    private void lowerJavaWriteNode(JavaWriteNode write) {
-        StructuredGraph graph = write.graph();
-
-        Kind valueKind = write.location().getValueKind();
-        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
-
-        WriteNode memoryWrite = graph.add(new WriteNode(write.object(), value, write.location(), write.getBarrierType(), false, write.isInitialization()));
-        memoryWrite.setStateAfter(write.stateAfter());
-        graph.replaceFixedWithFixed(write, memoryWrite);
-
-        memoryWrite.setGuard(write.getGuard());
-    }
+    int getScalingFactor(Kind kind);
 
-    private void lowerLoadHubNode(LoadHubNode loadHub) {
-        StructuredGraph graph = loadHub.graph();
-        if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
-            Kind wordKind = runtime.getTarget().wordKind;
-            assert loadHub.getKind() == wordKind;
-            ValueNode object = loadHub.object();
-            GuardingNode guard = loadHub.getGuard();
-            ValueNode hub = createReadHub(graph, wordKind, object, guard);
-            graph.replaceFloating(loadHub, hub);
-        }
-    }
-
-    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
-        StructuredGraph graph = loadMethodNode.graph();
-        ResolvedJavaMethod method = loadMethodNode.getMethod();
-        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
-        graph.replaceFixed(loadMethodNode, metaspaceMethod);
-    }
-
-    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
-        WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue());
-        graph.replaceFixed(storeHub, hub);
-    }
-
-    private void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
-        StructuredGraph graph = commit.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
-            BitSet omittedValues = new BitSet();
-            int valuePos = 0;
-            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                int entryCount = virtual.entryCount();
-                FixedWithNextNode newObject;
-                if (virtual instanceof VirtualInstanceNode) {
-                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
-                } else {
-                    newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true));
-                }
-                graph.addBeforeFixed(commit, newObject);
-                allocations[objIndex] = newObject;
-                for (int i = 0; i < entryCount; i++) {
-                    ValueNode value = commit.getValues().get(valuePos);
-                    if (value instanceof VirtualObjectNode) {
-                        value = allocations[commit.getVirtualObjects().indexOf(value)];
-                    }
-                    if (value == null) {
-                        omittedValues.set(valuePos);
-                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                        // Constant.illegal is always the defaultForKind, so it is skipped
-                        Kind valueKind = value.getKind();
-                        Kind entryKind = virtual.entryKind(i);
-
-                        // Truffle requires some leniency in terms of what can be put where:
-                        Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind;
-                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
-                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
-                        ConstantLocationNode location;
-                        BarrierType barrierType;
-                        if (virtual instanceof VirtualInstanceNode) {
-                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
-                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph);
-                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
-                        } else {
-                            location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph);
-                            barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE;
-                        }
-                        WriteNode write = new WriteNode(newObject, implicitStoreConvert(graph, entryKind, value), location, barrierType, false);
-                        graph.addAfterFixed(newObject, graph.add(write));
-                    }
-                    valuePos++;
-
-                }
-            }
-            valuePos = 0;
-
-            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                int entryCount = virtual.entryCount();
-                ValueNode newObject = allocations[objIndex];
-                for (int i = 0; i < entryCount; i++) {
-                    if (omittedValues.get(valuePos)) {
-                        ValueNode value = commit.getValues().get(valuePos);
-                        assert value instanceof VirtualObjectNode;
-                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
-                            WriteNode write;
-                            if (virtual instanceof VirtualInstanceNode) {
-                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i),
-                                                true), BarrierType.IMPRECISE, false);
-                            } else {
-                                write = new WriteNode(newObject, implicitStoreConvert(graph, Kind.Object, allocValue), createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph),
-                                                true), BarrierType.PRECISE, false);
-                            }
-                            graph.addBeforeFixed(commit, graph.add(write));
-                        }
-                    }
-                    valuePos++;
-                }
-            }
-
-            finishAllocatedObjects(tool, commit, allocations);
-            graph.removeFixed(commit);
-        }
-    }
-
-    private void lowerOSRStartNode(OSRStartNode osrStart) {
-        StructuredGraph graph = osrStart.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-            StartNode newStart = graph.add(new StartNode());
-            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
-            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
-            migrationEnd.setStateAfter(osrStart.stateAfter());
-
-            newStart.setNext(migrationEnd);
-            FixedNode next = osrStart.next();
-            osrStart.setNext(null);
-            migrationEnd.setNext(next);
-            graph.setStart(newStart);
-
-            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
-            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
-            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
-                int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind());
-                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
-                IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1);
-                ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
-                osrLocal.replaceAndDelete(load);
-                graph.addBeforeFixed(migrationEnd, load);
-            }
-            osrStart.replaceAtUsages(newStart);
-            osrStart.safeDelete();
-        }
-    }
-
-    private void lowerDynamicCounterNode(DynamicCounterNode n) {
-        StructuredGraph graph = n.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-            BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind);
-        }
-    }
-
-    static final class Exceptions {
-        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
-        protected static final NullPointerException cachedNullPointerException;
-
-        static {
-            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
-            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
-            cachedNullPointerException = new NullPointerException();
-            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
-        }
-    }
-
-    public static final class RuntimeCalls {
-        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
-        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
-    }
-
-    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
-        StructuredGraph graph = node.graph();
-        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
-            if (OmitHotExceptionStacktrace.getValue()) {
-                Throwable exception;
-                if (node.getExceptionClass() == NullPointerException.class) {
-                    exception = Exceptions.cachedNullPointerException;
-                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
-                    exception = Exceptions.cachedArrayIndexOutOfBoundsException;
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-                FloatingNode exceptionNode = ConstantNode.forConstant(HotSpotObjectConstant.forObject(exception), metaAccess, graph);
-                graph.replaceFixedWithFloating(node, exceptionNode);
-
-            } else {
-                ForeignCallDescriptor descriptor;
-                if (node.getExceptionClass() == NullPointerException.class) {
-                    descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
-                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
-                    descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-
-                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
-                graph.replaceFixedWithFixed(node, foreignCallNode);
-            }
-        }
-    }
-
-    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);
-    }
-
-    protected static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
-        StructuredGraph graph = commit.graph();
-        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
-            allocations[objIndex] = anchor;
-            graph.addBeforeFixed(commit, anchor);
-        }
-        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
-                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
-                graph.addBeforeFixed(commit, enter);
-                enter.lower(tool);
-            }
-        }
-        for (Node usage : commit.usages().snapshot()) {
-            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
-            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
-            graph.replaceFloating(addObject, allocations[index]);
-        }
-    }
-
-    private static LocationNode createLocation(UnsafeAccessNode access) {
-        return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind());
-    }
-
-    private static LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind) {
-        ValueNode offset = offsetNode;
-        if (offset.isConstant()) {
-            long offsetValue = offset.asConstant().asLong();
-            return ConstantLocationNode.create(locationIdentity, accessKind, offsetValue, offset.graph());
-        }
+    IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization);
 
-        long displacement = 0;
-        int indexScaling = 1;
-        boolean signExtend = false;
-        if (offset instanceof SignExtendNode) {
-            SignExtendNode extend = (SignExtendNode) offset;
-            if (extend.getResultBits() == 64) {
-                signExtend = true;
-                offset = extend.getInput();
-            }
-        }
-        if (offset instanceof IntegerAddNode) {
-            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
-            if (integerAddNode.y() instanceof ConstantNode) {
-                displacement = integerAddNode.y().asConstant().asLong();
-                offset = integerAddNode.x();
-            }
-        }
-
-        if (offset instanceof LeftShiftNode) {
-            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
-            if (leftShiftNode.y() instanceof ConstantNode) {
-                long shift = leftShiftNode.y().asConstant().asLong();
-                if (shift >= 1 && shift <= 3) {
-                    if (shift == 1) {
-                        indexScaling = 2;
-                    } else if (shift == 2) {
-                        indexScaling = 4;
-                    } else {
-                        indexScaling = 8;
-                    }
-                    offset = leftShiftNode.x();
-                }
-            }
-        }
-        if (signExtend) {
-            // If we were using sign extended values before restore the sign extension.
-            offset = offset.graph().addOrUnique(new SignExtendNode(offset, 64));
-        }
-        return IndexedLocationNode.create(locationIdentity, accessKind, displacement, offset, offset.graph(), indexScaling);
-    }
-
-    private static boolean addReadBarrier(UnsafeLoadNode load) {
-        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
-                        !StampTool.isObjectAlwaysNull(load.object())) {
-            ResolvedJavaType type = StampTool.typeOrNull(load.object());
-            if (type != null && !type.isArray()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
-        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-        assert !hsMethod.getDeclaringClass().isInterface();
-        assert hsMethod.isInVirtualMethodTable();
-
-        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-        assert vtableEntryOffset > 0;
-        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
-        // entry as HotSpot does not guarantee that this is a final value.
-        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false));
-        return metaspaceMethod;
-    }
-
-    private ValueNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-
-        Stamp hubStamp;
-        if (config.useCompressedClassPointers) {
-            hubStamp = StampFactory.forInteger(32);
-        } else {
-            hubStamp = StampFactory.forKind(wordKind);
-        }
-
-        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(object, location, null, hubStamp, guard, BarrierType.NONE, false));
-        if (config.useCompressedClassPointers) {
-            return CompressionNode.uncompress(memoryRead, config.getKlassEncoding());
-        } else {
-            return memoryRead;
-        }
-    }
-
-    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-
-        ValueNode writeValue = value;
-        if (config.useCompressedClassPointers) {
-            writeValue = CompressionNode.compress(value, config.getKlassEncoding());
-        }
-
-        return graph.add(new WriteNode(object, writeValue, location, BarrierType.NONE, false));
-    }
-
-    private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
-            barrierType = BarrierType.PRECISE;
-        }
-        return barrierType;
-    }
-
-    private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
-        if (storeField.field().getKind() == Kind.Object) {
-            return BarrierType.IMPRECISE;
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
-        if (store.elementKind() == Kind.Object) {
-            return BarrierType.PRECISE;
-        }
-        return BarrierType.NONE;
-    }
+    ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value);
 
-    private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
-        if (store.value().getKind() == Kind.Object) {
-            ResolvedJavaType type = StampTool.typeOrNull(store.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getCompareAndSwapBarrierType(CompareAndSwapNode cas) {
-        if (cas.expected().getKind() == Kind.Object) {
-            ResolvedJavaType type = StampTool.typeOrNull(cas.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    private static BarrierType getAtomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
-        if (n.newValue().getKind() == Kind.Object) {
-            ResolvedJavaType type = StampTool.typeOrNull(n.object());
-            if (type != null && !type.isArray()) {
-                return BarrierType.IMPRECISE;
-            } else {
-                return BarrierType.PRECISE;
-            }
-        }
-        return BarrierType.NONE;
-    }
-
-    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : field;
-        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
-    }
-
-    public int getScalingFactor(Kind kind) {
-        if (useCompressedOops() && kind == Kind.Object) {
-            return this.runtime.getTarget().getSizeInBytes(Kind.Int);
-        } else {
-            return this.runtime.getTarget().getSizeInBytes(kind);
-        }
-    }
-
-    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
-        int scale = getScalingFactor(elementKind);
-        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
-    }
-
-    @Override
-    public ValueNode reconstructArrayIndex(LocationNode location) {
-        Kind elementKind = location.getValueKind();
-        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
-
-        long base;
-        ValueNode index;
-        int scale = getScalingFactor(elementKind);
-
-        if (location instanceof ConstantLocationNode) {
-            base = ((ConstantLocationNode) location).getDisplacement();
-            index = null;
-        } else if (location instanceof IndexedLocationNode) {
-            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
-            assert indexedLocation.getIndexScaling() == scale;
-            base = indexedLocation.getDisplacement();
-            index = indexedLocation.getIndex();
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        base -= getArrayBaseOffset(elementKind);
-        assert base >= 0 && base % scale == 0;
-
-        base /= scale;
-        assert NumUtil.isInt(base);
-
-        StructuredGraph graph = location.graph();
-        if (index == null) {
-            return ConstantNode.forInt((int) base, graph);
-        } else {
-            if (base == 0) {
-                return index;
-            } else {
-                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
-            }
-        }
-    }
-
-    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
-        StructuredGraph g = n.graph();
-        ValueNode array = n.array();
-        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
-        if (arrayLength == null) {
-            Stamp stamp = StampFactory.positiveInt();
-            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
-            g.addBeforeFixed(n, readArrayLength);
-            readArrayLength.setGuard(createNullCheck(array, readArrayLength, tool));
-            arrayLength = readArrayLength;
-        }
-
-        if (arrayLength.isConstant() && n.index().isConstant()) {
-            int l = arrayLength.asConstant().asInt();
-            int i = n.index().asConstant().asInt();
-            if (i >= 0 && i < l) {
-                // unneeded range check
-                return null;
-            }
-        }
-
-        return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
-    }
-
-    private static GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
-        if (StampTool.isObjectNonNull(object)) {
-            return null;
-        }
-        return tool.createGuard(before, before.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
-    }
-
+    ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value);
 }
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java	Wed Apr 30 13:40:36 2014 +0200
@@ -402,7 +402,8 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            throw new InternalError("NYI");
+            HSAILAddress addr = address.toAddress();
+            masm.emitLea(result, addr);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Wed Apr 30 13:40:36 2014 +0200
@@ -23,13 +23,12 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
-public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, MemoryArithmeticLIRLowerable, Canonicalizable {
+public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
@@ -80,9 +79,4 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return false;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Apr 30 13:40:36 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/UnaryOpLogicNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Wed Apr 30 13:40:36 2014 +0200
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.meta.ProfilingInfo.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.nodes.spi.*;
 
-public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable, MemoryArithmeticLIRLowerable {
+public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable {
 
     @Input private ValueNode object;
 
@@ -49,9 +48,4 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
     }
-
-    @Override
-    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
-        return false;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Apr 30 13:40:36 2014 +0200
@@ -120,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());
             }
@@ -142,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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Wed Apr 30 13:40:36 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/FloatMulNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Wed Apr 30 13:40:36 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/IntegerConvertNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Wed Apr 30 13:40:36 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/IntegerMulNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Wed Apr 30 13:40:36 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/NarrowNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Wed Apr 30 13:40:36 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/OrNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Wed Apr 30 13:40:36 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/extended/MemoryCheckpoint.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Wed Apr 30 13:40:36 2014 +0200
@@ -31,7 +31,7 @@
  * represented by location identities (i.e. change a value at one or more locations that belong to
  * these location identities).
  */
-public interface MemoryCheckpoint extends MemoryNode, NodeInterface {
+public interface MemoryCheckpoint extends MemoryNode {
 
     FixedNode asNode();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java	Wed Apr 30 13:36:41 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	Wed Apr 30 13:36:41 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Wed Apr 30 13:40:36 2014 +0200
@@ -70,8 +70,6 @@
 
     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);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Wed Apr 30 13:40:36 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);
             }
         }
@@ -140,7 +150,9 @@
         if (fixed instanceof StateSplit) {
             FrameState stateAfter = ((StateSplit) fixed).stateAfter();
             ((StateSplit) fixed).setStateAfter(null);
-            killWithUnusedFloatingInputs(stateAfter);
+            if (stateAfter.usages().isEmpty()) {
+                killWithUnusedFloatingInputs(stateAfter);
+            }
         }
         FixedNode next = fixed.next();
         fixed.setNext(null);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Apr 30 13:40:36 2014 +0200
@@ -346,7 +346,7 @@
             @Override
             public void deleteBranch(Node branch) {
                 branch.predecessor().replaceFirstSuccessor(branch, null);
-                GraphUtil.killCFG(branch);
+                GraphUtil.killCFG(branch, this);
             }
 
             /**
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Wed Apr 30 13:40:36 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/cfs/BaseReduction.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java	Wed Apr 30 13:40:36 2014 +0200
@@ -49,7 +49,7 @@
  * 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");
@@ -70,7 +70,7 @@
      *
      * @see State#impossiblePath()
      * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#finished()
-     * */
+     */
     public static class PostponedDeopt {
 
         private final boolean goesBeforeFixed;
@@ -105,7 +105,7 @@
          * 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));
         }
@@ -115,7 +115,7 @@
          * 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));
         }
@@ -131,7 +131,7 @@
      * 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;
@@ -159,7 +159,7 @@
          * 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);
@@ -207,8 +207,8 @@
      * reported as such.
      * </p>
      *
-     * */
-    protected static boolean precisionLoss(ValueNode input, ValueNode output) {
+     */
+    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())) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java	Wed Apr 30 13:40:36 2014 +0200
@@ -31,7 +31,7 @@
 
 /**
  * @see #extract(com.oracle.graal.nodes.LogicNode)
- * */
+ */
 class CastCheckExtractor {
 
     public final ResolvedJavaType type;
@@ -42,7 +42,7 @@
         this.subject = subject;
     }
 
-    static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) {
+    private static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) {
         if (x instanceof IsNullNode) {
             IsNullNode isNull = (IsNullNode) x;
             ValueNode subject = isNull.object();
@@ -57,7 +57,7 @@
     /**
      * 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;
@@ -76,8 +76,8 @@
 
     /**
      * Porcelain method.
-     * */
-    public static boolean isInstanceOfCheckOn(LogicNode cond, ValueNode subject) {
+     */
+    static boolean isInstanceOfCheckOn(LogicNode cond, ValueNode subject) {
         if (!(cond instanceof InstanceOfNode)) {
             return false;
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java	Wed Apr 30 13:40:36 2014 +0200
@@ -42,7 +42,7 @@
  * </p>
  *
  * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
- * */
+ */
 public abstract class CheckCastReduction extends GuardingPiReduction {
 
     public CheckCastReduction(FixedNode start, State initialState, PhaseContext context) {
@@ -60,14 +60,14 @@
      * 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#downcastedGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode, Witness)}
+     * {@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) {
 
         /*
@@ -109,7 +109,7 @@
          * others.
          */
 
-        PiNode untrivialNull = reasoner.untrivialNull(subject);
+        PiNode untrivialNull = reasoner.nonTrivialNull(subject);
         if (untrivialNull != null) {
             metricCheckCastRemoved.increment();
             checkCast.replaceAtUsages(untrivialNull);
@@ -121,7 +121,7 @@
 
         if (w == null) {
             /*
-             * If there's no witness, attempting `downcasted(subject)` is futile.
+             * If there's no witness, attempting `downcast(subject)` is futile.
              */
             visitCheckCastNodeLackingWitness(checkCast);
             return;
@@ -139,14 +139,14 @@
      * @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.downcasted(subject) == subject;
+        assert reasoner.downcast(subject) == subject;
         lowerCheckCastAnchorFriendlyWay(checkCast, subject);
     }
 
@@ -170,7 +170,7 @@
      *
      * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
      *
-     * */
+     */
     public void lowerCheckCastAnchorFriendlyWay(CheckCastNode checkCast, ValueNode subject) {
         ValueNode originalCheckCastObject = checkCast.object();
 
@@ -268,7 +268,7 @@
 
     /**
      * Porcelain method.
-     * */
+     */
     public static boolean isTypeOfWitnessBetter(Witness w, ObjectStamp stamp) {
         if (w == null) {
             return false;
@@ -281,27 +281,24 @@
      * 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.downcasted(checkCast);
+            subject = reasoner.downcast(checkCast);
             if (subject == checkCast) {
-                subject = reasoner.downcasted(checkCast.object());
+                subject = reasoner.downcast(checkCast.object());
             }
         } else {
-            subject = reasoner.downcasted(checkCast.object());
+            subject = reasoner.downcast(checkCast.object());
         }
 
         ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
         ResolvedJavaType subjectType = subjectStamp.type();
 
-        // TODO move this check to downcasted()
-        assert !precisionLoss(checkCast.object(), subject);
-
         /*
          * 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
@@ -316,7 +313,7 @@
         }
 
         /*
-         * At this point, `downcasted()` might or might not have delivered a more precise value. If
+         * 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).
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java	Wed Apr 30 13:40:36 2014 +0200
@@ -51,10 +51,10 @@
  * 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
- * 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
+ * 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>
  *
@@ -111,7 +111,7 @@
      * {@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();
@@ -253,13 +253,13 @@
          * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)`
          */
         if (v instanceof ValueProxy) {
-            return downcasted(v);
+            return downcast(v);
         }
 
         if (n instanceof FloatingNode) {
             /*
              * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not
-             * possible anymore it resorts to calling `downcasted()`. Thus it's ok to take the
+             * possible anymore it resorts to calling `downcast()`. Thus it's ok to take the
              * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be
              * missed.
              */
@@ -267,7 +267,7 @@
         }
 
         if (FlowUtil.hasLegalObjectStamp(v)) {
-            return downcasted(v);
+            return downcast(v);
         }
 
         return n;
@@ -285,7 +285,7 @@
      * 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()";
@@ -339,7 +339,7 @@
                  * No input has changed doesn't imply there's no witness to refine the
                  * floating-object value.
                  */
-                ValueNode d = downcasted(f);
+                ValueNode d = downcast(f);
                 return d;
             } else {
                 return f;
@@ -356,11 +356,11 @@
 
     /**
      * In case of doubt (on whether a reduction actually triggered) it's always ok to invoke "
-     * <code>rememberSubstitution(f, downcasted(f))</code>": this method records a map entry only if
+     * <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) {
@@ -483,7 +483,7 @@
             return isNull;
         }
         ValueNode scrutinee = GraphUtil.unproxify(isNull.object());
-        GuardingNode evidence = untrivialNullAnchor(scrutinee);
+        GuardingNode evidence = nonTrivialNullAnchor(scrutinee);
         if (evidence != null) {
             metricNullCheckRemoved.increment();
             return trueConstant;
@@ -515,7 +515,7 @@
     }
 
     /**
-     * It's always ok to use "<code>downcasted(object)</code>" instead of " <code>object</code>"
+     * 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.
      *
@@ -534,7 +534,7 @@
      *         <li>the unmodified argument otherwise.</li>
      *         </ul>
      */
-    ValueNode downcasted(final ValueNode object) {
+    ValueNode downcast(final ValueNode object) {
 
         // -------------------------------------------------
         // actions based only on the stamp of the input node
@@ -547,7 +547,7 @@
             return object;
         }
         if (StampTool.isObjectAlwaysNull(object.stamp())) {
-            return untrivialNull(object);
+            return object;
         }
 
         // ------------------------------------------
@@ -556,7 +556,7 @@
 
         ValueNode scrutinee = GraphUtil.unproxify(object);
 
-        PiNode untrivialNull = untrivialNull(scrutinee);
+        PiNode untrivialNull = nonTrivialNull(scrutinee);
         if (untrivialNull != null) {
             return untrivialNull;
         }
@@ -581,11 +581,13 @@
 
         ValueNode result;
         if (object instanceof ValueProxy) {
-            result = downcastedValueProxy((ValueProxy) object, w);
+            result = downcastValueProxy((ValueProxy) object, w);
         } else {
             result = downcastedUtil(object, w);
         }
 
+        assert !BaseReduction.precisionLoss(object, result);
+
         return result;
     }
 
@@ -597,7 +599,7 @@
      * {@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;
@@ -625,7 +627,7 @@
      * <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();
@@ -653,7 +655,7 @@
      * Otherwise, if an anchor is found it is returned, null otherwise.
      * </p>
      */
-    public GuardingNode untrivialNullAnchor(ValueNode object) {
+    public GuardingNode nonTrivialNullAnchor(ValueNode object) {
         assert FlowUtil.hasLegalObjectStamp(object);
         if (StampTool.isObjectAlwaysNull(object)) {
             return null;
@@ -676,9 +678,9 @@
      * .
      * </p>
      */
-    public PiNode untrivialNull(ValueNode object) {
+    public PiNode nonTrivialNull(ValueNode object) {
         assert FlowUtil.hasLegalObjectStamp(object);
-        GuardingNode anchor = untrivialNullAnchor(object);
+        GuardingNode anchor = nonTrivialNullAnchor(object);
         if (anchor == null) {
             return null;
         }
@@ -711,7 +713,7 @@
      *     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>downcasted(proxy) == proxy</code> in such cases.
+     *     thus <code>downcast(proxy) == proxy</code> in such cases.
      * </p>
      *
      * <p>
@@ -733,7 +735,7 @@
      *</p>
      */
     // @formatter:on
-    private ValueNode downcastedValueProxy(ValueProxy proxy, Witness w) {
+    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());
@@ -741,13 +743,13 @@
         assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify((proxy).getOriginalNode());
 
         if (proxy instanceof PiNode) {
-            return downcastedPiNodeOrPiArrayNode((PiNode) proxy, w);
+            return downcastPiNodeOrPiArrayNode((PiNode) proxy, w);
         } else if (proxy instanceof GuardingPiNode) {
-            return downcastedGuardingPiNode((GuardingPiNode) proxy, w);
+            return downcastGuardingPiNode((GuardingPiNode) proxy, w);
         } else if (proxy instanceof TypeProfileProxyNode) {
-            return downcastedTypeProfileProxyNode((TypeProfileProxyNode) proxy);
+            return downcastTypeProfileProxyNode((TypeProfileProxyNode) proxy);
         } else if (proxy instanceof CheckCastNode) {
-            return downcastedCheckCastNode((CheckCastNode) proxy, w);
+            return downcastCheckCastNode((CheckCastNode) proxy, w);
         } else if (proxy instanceof ProxyNode || proxy instanceof GuardedValueNode) {
             // TODO scaladacapo return downcastedUtil((ValueNode) proxy, w);
             return (ValueNode) proxy;
@@ -781,9 +783,9 @@
      * GuardingPiNode is clear: devirtualizing the `intValue()` callsite.
      * </p>
      *
-     * @see #downcastedValueProxy
-     * */
-    public ValueNode downcastedGuardingPiNode(GuardingPiNode envelope, Witness w) {
+     * @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);
     }
@@ -813,9 +815,9 @@
      * PiNode.canonical()} does). Not clear the benefits of duplicating that logic here.
      * </p>
      *
-     * @see #downcastedValueProxy
-     * */
-    private ValueNode downcastedPiNodeOrPiArrayNode(PiNode envelope, Witness w) {
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastPiNodeOrPiArrayNode(PiNode envelope, Witness w) {
         return downcastedUtil(envelope, w);
     }
 
@@ -829,11 +831,11 @@
      * Otherwise returns the unmodified argument.
      * </p>
      *
-     * @see #downcastedValueProxy
-     * */
-    private ValueNode downcastedTypeProfileProxyNode(TypeProfileProxyNode envelope) {
+     * @see #downcastValueProxy
+     */
+    private ValueNode downcastTypeProfileProxyNode(TypeProfileProxyNode envelope) {
         ValueNode payload = envelope.getOriginalNode();
-        ValueNode d = downcasted(payload);
+        ValueNode d = downcast(payload);
         if (payload != d) {
             TypeProfileProxyNode changed = (TypeProfileProxyNode) envelope.copyWithInputs();
             added.add(changed);
@@ -859,8 +861,8 @@
      * 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 downcastedCheckCastNode(CheckCastNode checkCast, Witness w) {
+     */
+    private ValueNode downcastCheckCastNode(CheckCastNode checkCast, Witness w) {
 
         final ResolvedJavaType toType = checkCast.type();
 
@@ -869,7 +871,7 @@
             while (innerMost instanceof CheckCastNode) {
                 innerMost = ((CheckCastNode) innerMost).object();
             }
-            ValueNode deepest = downcasted(innerMost);
+            ValueNode deepest = downcast(innerMost);
             ResolvedJavaType deepestType = ((ObjectStamp) deepest.stamp()).type();
             if ((deepestType != null && deepestType.equals(toType)) || FlowUtil.isMorePrecise(deepestType, toType)) {
                 assert !w.knowsBetterThan(deepest);
@@ -877,7 +879,7 @@
             }
         }
 
-        ValueNode subject = downcasted(checkCast.object());
+        ValueNode subject = downcast(checkCast.object());
         ObjectStamp subjectStamp = (ObjectStamp) subject.stamp();
         ResolvedJavaType subjectType = subjectStamp.type();
 
@@ -899,7 +901,7 @@
      * 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();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java	Wed Apr 30 13:40:36 2014 +0200
@@ -35,7 +35,7 @@
  * </p>
  * 
  * @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)
- * */
+ */
 public abstract class FixedGuardReduction extends CheckCastReduction {
 
     public FixedGuardReduction(FixedNode start, State initialState, PhaseContext context) {
@@ -104,7 +104,7 @@
             final IsNullNode isNullNode = (IsNullNode) cond;
             if (isTrue) {
                 // grab an anchor attesting nullness
-                final GuardingNode replacement = reasoner.untrivialNullAnchor(isNullNode.object());
+                final GuardingNode replacement = reasoner.nonTrivialNullAnchor(isNullNode.object());
                 if (replacement != null) {
                     removeFixedGuardNode(f, replacement);
                     return;
@@ -152,7 +152,7 @@
             } else {
                 // grab an anchor attesting not-instanceof
                 // (1 of 2) attempt determining nullness
-                final GuardingNode nullGuard = reasoner.untrivialNullAnchor(iOf.object());
+                final GuardingNode nullGuard = reasoner.nonTrivialNullAnchor(iOf.object());
                 if (nullGuard != null) {
                     removeFixedGuardNode(f, nullGuard);
                     return;
@@ -190,7 +190,7 @@
 
     /**
      * Porcelain method.
-     * */
+     */
     private void markFixedGuardNodeAlwaysFails(FixedGuardNode f) {
         metricFixedGuardNodeRemoved.increment();
         state.impossiblePath();
@@ -204,7 +204,7 @@
      * <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;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Wed Apr 30 13:40:36 2014 +0200
@@ -26,6 +26,7 @@
 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.*;
@@ -37,6 +38,7 @@
 
 import java.lang.reflect.Modifier;
 
+import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 
 /**
@@ -61,7 +63,7 @@
  * @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) {
@@ -111,7 +113,7 @@
      * Checking if they aren't in use, proceeding to remove them in that case.
      * </p>
      *
-     * */
+     */
     @Override
     public void finished() {
         if (!postponedDeopts.isEmpty()) {
@@ -134,7 +136,7 @@
     }
 
     private static boolean isAliveWithoutUsages(FloatingNode node) {
-        return node.isAlive() && node.usages().isEmpty();
+        return node.isAlive() && FlowUtil.lacksUsages(node);
     }
 
     private void registerControlSplit(Node pred, BeginNode begin) {
@@ -177,7 +179,7 @@
      * 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();
@@ -195,18 +197,13 @@
                 // `begin` denotes the default case of the TypeSwitchNode
                 return;
             }
-            // preferable would be trackExact, but not there yet
-            state.addNullness(false, loadHub.object(), begin);
             if (state.knownNotToConform(loadHub.object(), type)) {
                 postponedDeopts.addDeoptAfter(begin, UnreachedCode);
                 state.impossiblePath();
                 return;
             }
-            if (type.isInterface()) {
-                state.trackNN(loadHub.object(), begin);
-            } else {
-                state.trackIO(loadHub.object(), type, begin);
-            }
+            // it's unwarranted to assume loadHub.object() to be non-null
+            // it also seems unwarranted state.trackCC(loadHub.object(), type, begin);
         }
     }
 
@@ -252,7 +249,7 @@
      * </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)) {
@@ -276,7 +273,7 @@
      * @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)) {
@@ -437,12 +434,14 @@
      * <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)) {
@@ -459,7 +458,17 @@
             graph.removeFixed(ncn);
             return;
         }
-        // TODO ANCHOR NEEDED: state.trackNN(object, ncn);
+        /*
+         * 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);
     }
 
     /**
@@ -471,7 +480,7 @@
      * <p>
      * Precondition: inputs haven't been deverbosified yet.
      * </p>
-     * */
+     */
     private void visitAbstractEndNode(AbstractEndNode endNode) {
         MergeNode merge = endNode.merge();
         for (PhiNode phi : merge.phis()) {
@@ -498,7 +507,7 @@
      * <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
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java	Wed Apr 30 13:40:36 2014 +0200
@@ -43,7 +43,9 @@
     @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);
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Wed Apr 30 13:40:36 2014 +0200
@@ -61,7 +61,7 @@
 
     /**
      * @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;
@@ -132,7 +132,7 @@
      * 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();
     }
@@ -162,7 +162,7 @@
      * 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) {
@@ -234,7 +234,7 @@
     /**
      * 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;
@@ -275,7 +275,7 @@
      * 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);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java	Wed Apr 30 13:40:36 2014 +0200
@@ -39,7 +39,7 @@
  * </p>
  * 
  * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
- * */
+ */
 public abstract class GuardingPiReduction extends BaseReduction {
 
     public GuardingPiReduction(FixedNode start, State initialState, PhaseContext context) {
@@ -75,7 +75,7 @@
      * Precondition: the condition hasn't been deverbosified yet.
      * </p>
      * 
-     * */
+     */
     protected final void visitGuardingPiNode(GuardingPiNode envelope) {
 
         if (!FlowUtil.hasLegalObjectStamp(envelope)) {
@@ -181,7 +181,7 @@
      * 
      * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
      * 
-     * */
+     */
     private boolean tryRemoveGuardingPiNode(GuardingPiNode envelope) {
 
         LogicNode cond = envelope.condition();
@@ -203,7 +203,7 @@
                 /*
                  * GuardingPiNode succeeds if payload null
                  */
-                ValueNode replacement = StampTool.isObjectAlwaysNull(payload) ? payload : reasoner.untrivialNull(payload);
+                ValueNode replacement = StampTool.isObjectAlwaysNull(payload) ? payload : reasoner.nonTrivialNull(payload);
                 if (replacement != null) {
                     // replacement == null means !isKnownNull(payload)
                     removeGuardingPiNode(envelope, replacement);
@@ -222,7 +222,7 @@
             assert io.type() != null;
             Witness w = state.typeInfo(payload);
             if (w != null && w.isNonNull() && isEqualOrMorePrecise(w.type(), io.type())) {
-                ValueNode d = reasoner.downcasted(payload);
+                ValueNode d = reasoner.downcast(payload);
                 removeGuardingPiNode(envelope, d);
                 return true;
             }
@@ -251,7 +251,7 @@
      * non-null.
      * 
      * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
-     * */
+     */
     private boolean tryRemoveGuardingPiNodeNonNullCond(GuardingPiNode envelope) {
 
         ValueNode payload = envelope.object();
@@ -306,7 +306,7 @@
      * 
      * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
      * 
-     * */
+     */
     private boolean tryRemoveGuardingPiNodeCheckCastCond(GuardingPiNode envelope, ResolvedJavaType toType) {
         assert toType != null;
         ValueNode payload = envelope.object();
@@ -318,7 +318,7 @@
             warnAboutOutOfTheBlueGuardingPiNode(envelope);
         }
 
-        ValueNode d = reasoner.downcasted(payload);
+        ValueNode d = reasoner.downcast(payload);
         if (d == null) {
             return false;
         }
@@ -353,7 +353,7 @@
 
     /**
      * Porcelain method.
-     * */
+     */
     private void removeGuardingPiNode(GuardingPiNode envelope, ValueNode replacement) {
         assert !precisionLoss(envelope, replacement);
         metricGuardingPiNodeRemoved.increment();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java	Wed Apr 30 13:40:36 2014 +0200
@@ -80,7 +80,7 @@
      * </ul>
      * </p>
      *
-     * */
+     */
     int versionNr = 0;
 
     boolean isUnreachable = false;
@@ -91,7 +91,7 @@
      * detect an "impossible path" could be shaved off.
      *
      * @see com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt
-     * */
+     */
     void impossiblePath() {
         isUnreachable = true;
         metricImpossiblePathDetected.increment();
@@ -112,10 +112,10 @@
      * 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#downcasted(com.oracle.graal.nodes.ValueNode) downcasted()}
+     * {@link EquationalReasoner#downcast(com.oracle.graal.nodes.ValueNode) downcast()}
      * </p>
      *
-     * */
+     */
     private IdentityHashMap<ValueNode, Witness> typeRefinements;
 
     IdentityHashMap<ValueNode, GuardingNode> knownNull;
@@ -143,7 +143,7 @@
 
     /**
      * @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();
@@ -275,14 +275,18 @@
             return true;
         }
 
-        for (State state : withReachableStates) {
-            versionNr = Math.max(versionNr, state.versionNr) + 1;
-            isUnreachable &= state.isUnreachable;
+        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;
         }
 
@@ -346,7 +350,7 @@
     }
 
     /**
-     * @retun null if no type-witness available for the argument, the witness otherwise.
+     * @return null if no type-witness available for the argument, the witness otherwise.
      */
     public Witness typeInfo(ValueNode object) {
         assert FlowUtil.hasLegalObjectStamp(object);
@@ -354,7 +358,7 @@
     }
 
     /**
-     * @retun true iff the argument is known to stand for null.
+     * @return true iff the argument is known to stand for null.
      */
     public boolean isNull(ValueNode object) {
         assert FlowUtil.hasLegalObjectStamp(object);
@@ -377,7 +381,7 @@
      * is-non-null set.
      * </p>
      *
-     * @retun true iff the argument is known to stand for non-null.
+     * @return true iff the argument is known to stand for non-null.
      */
     public boolean isNonNull(ValueNode object) {
         assert FlowUtil.hasLegalObjectStamp(object);
@@ -389,7 +393,7 @@
     }
 
     /**
-     * @retun true iff the argument is known to stand for an object conforming to the given type.
+     * @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);
@@ -411,8 +415,8 @@
     }
 
     /**
-     * @retun true iff the argument is known to stand for an object that definitely does not conform
-     *        to the given type.
+     * @return true iff the argument is known to stand for an object that definitely does not
+     *         conform to the given type.
      */
     public boolean knownNotToConform(ValueNode object, ResolvedJavaType to) {
         assert FlowUtil.hasLegalObjectStamp(object);
@@ -454,7 +458,7 @@
      *    final: exact non-interface reference-type
      *    non-f: non-exact non-interface reference-type
      *
-     * @retun true iff the first argument is known not to conform to the second argument.
+     * @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) {
@@ -514,6 +518,7 @@
         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);
@@ -548,6 +553,7 @@
         if (isDependencyTainted(object, anchor)) {
             return false;
         }
+        assert anchor instanceof FixedNode;
         Witness w = getOrElseAddTypeInfo(object);
         if (w.trackCC(observed, anchor)) {
             versionNr++;
@@ -573,6 +579,7 @@
         if (isDependencyTainted(object, anchor)) {
             return false;
         }
+        assert anchor instanceof FixedNode;
         Witness w = getOrElseAddTypeInfo(object);
         if (w.trackIO(observed, anchor)) {
             versionNr++;
@@ -592,7 +599,7 @@
      * 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)) {
@@ -608,9 +615,10 @@
      * <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) {
@@ -679,16 +687,6 @@
             } else {
                 trackIO(object, instanceOf.type(), anchor);
             }
-        } else {
-            if (knownToConform(object, instanceOf.type())) {
-                impossiblePath(); // TODO this used to be a bug
-                return;
-            }
-            if (instanceOf.type().isInterface()) {
-                if (!knownNotToConform(object, instanceOf.type())) {
-                    addFactPrimordial(instanceOf, falseFacts, anchor);
-                }
-            }
         }
     }
 
@@ -699,6 +697,7 @@
         if (isDependencyTainted(equals.y(), anchor)) {
             return;
         }
+        assert anchor instanceof FixedNode;
         ValueNode x = GraphUtil.unproxify(equals.x());
         ValueNode y = GraphUtil.unproxify(equals.y());
         if (isTrue) {
@@ -757,6 +756,7 @@
         if (isDependencyTainted(value, anchor)) {
             return;
         }
+        assert anchor instanceof FixedNode;
         ValueNode original = GraphUtil.unproxify(value);
         boolean wasNull = isNull(original);
         boolean wasNonNull = isNonNull(original);
@@ -781,8 +781,9 @@
     /**
      *
      * @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;
@@ -808,6 +809,8 @@
         isUnreachable = false;
         typeRefinements.clear();
         knownNull.clear();
+        trueFacts.clear();
+        falseFacts.clear();
     }
 
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java	Wed Apr 30 13:40:36 2014 +0200
@@ -118,7 +118,7 @@
 
     /**
      * Counterpart to {@link #asStamp()}
-     * */
+     */
     public Witness(ObjectStamp stamp, GuardingNode anchor) {
         assert stamp.isLegal();
         assert anchor != null;
@@ -381,7 +381,7 @@
     /**
      * 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);
@@ -389,14 +389,14 @@
 
     /**
      * @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();
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Apr 30 13:40:36 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.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java	Wed Apr 30 13:40:36 2014 +0200
@@ -145,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/TruffleCompilerImpl.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Apr 30 13:40:36 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.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Apr 30 13:40:36 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);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/mx.cmd	Wed Apr 30 13:40:36 2014 +0200
@@ -1,1 +1,1 @@
-python mxtool/mx.py %*
+python %~dp0/mxtool/mx.py %*
--- a/mx/mx_graal.py	Wed Apr 30 13:36:41 2014 +0200
+++ b/mx/mx_graal.py	Wed Apr 30 13:40:36 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
@@ -163,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):
 
--- a/mx/projects	Wed Apr 30 13:36:41 2014 +0200
+++ b/mx/projects	Wed Apr 30 13:40:36 2014 +0200
@@ -53,8 +53,8 @@
 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
--- a/mxtool/mx.py	Wed Apr 30 13:36:41 2014 +0200
+++ b/mxtool/mx.py	Wed Apr 30 13:40:36 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)
@@ -3985,7 +3996,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',
@@ -3995,6 +4012,7 @@
                      '-source', str(projectJava.javaCompliance),
                      '-bootclasspath', projectJava.bootclasspath(),
                      '-extdirs', projectJava.extdirs()] +
+                     ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
                      links +
                      extraArgs +
                      nowarnAPI +
@@ -4032,115 +4050,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)')
@@ -4151,7 +4073,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 = []
@@ -4200,6 +4122,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
@@ -4253,29 +4178,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):
--- a/src/share/vm/code/debugInfoRec.cpp	Wed Apr 30 13:36:41 2014 +0200
+++ b/src/share/vm/code/debugInfoRec.cpp	Wed Apr 30 13:40:36 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	Wed Apr 30 13:36:41 2014 +0200
+++ b/src/share/vm/code/nmethod.cpp	Wed Apr 30 13:40:36 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/graal/graalGlobals.hpp	Wed Apr 30 13:36:41 2014 +0200
+++ b/src/share/vm/graal/graalGlobals.hpp	Wed Apr 30 13:40:36 2014 +0200
@@ -53,7 +53,7 @@
           "Bootstrap Graal before running Java main method"))               \
                                                                             \
   product(bool, ForceGraalInitialization, false,                            \
-          "Force VM to initialize the Compiler although not used")          \
+          "Force VM to initialize the compiler even if not used")           \
                                                                             \
   product(intx, TraceGraal, 0,                                              \
           "Trace level for Graal")                                          \
--- a/src/share/vm/runtime/globals.hpp	Wed Apr 30 13:36:41 2014 +0200
+++ b/src/share/vm/runtime/globals.hpp	Wed Apr 30 13:40:36 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")                \
                                                                             \