changeset 16662:e7b7a5be4d21

Merge
author Stefan Anzinger <stefan.anzinger@gmail.com>
date Wed, 30 Jul 2014 10:39:39 -0700
parents f1fba319d4e3 (current diff) faaea970b951 (diff)
children 4ccd6b6b6780
files graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCTestOp.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java src/share/vm/graal/graalCodeInstaller.cpp src/share/vm/graal/graalJavaAccess.hpp
diffstat 200 files changed, 3593 insertions(+), 1654 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Wed Jul 30 09:36:32 2014 -0700
+++ b/CHANGELOG.md	Wed Jul 30 10:39:39 2014 -0700
@@ -10,6 +10,7 @@
 * Enabled use of separate class loader (via -XX:+UseGraalClassLoader) for classes loaded from graal.jar to hide them from application classes.
 
 ### Truffle
+* Change API for stack walking to a visitor: `TruffleRuntime#iterateFrames` replaces `TruffleRuntime#getStackTrace`
 * New flag -G:+TraceTruffleCompilationCallTree to print the tree of inlined calls before compilation.
 * `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`)
 * New flag -G:+TraceTruffleCompilationAST to print the AST before compilation.
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Wed Jul 30 10:39:39 2014 -0700
@@ -138,7 +138,7 @@
     private final EnumSet<CPUFeature> features;
 
     public AMD64(EnumSet<CPUFeature> features) {
-        super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, cpuRegisters.length + xmmRegisters.length << XMM_REFERENCE_MAP_SHIFT, 8);
+        super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, cpuRegisters.length + (xmmRegisters.length << XMM_REFERENCE_MAP_SHIFT), 8);
         this.features = features;
         assert features.contains(CPUFeature.SSE2) : "minimum config for x64";
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodePosition.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodePosition.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,7 +32,7 @@
  * system to reconstruct a source-level stack trace for exceptions and to create
  * {@linkplain BytecodeFrame frames} for deoptimization.
  */
-public abstract class BytecodePosition implements Serializable {
+public class BytecodePosition implements Serializable {
 
     private static final long serialVersionUID = 8633885274526033515L;
 
@@ -42,7 +42,7 @@
 
     /**
      * Constructs a new object representing a given parent/caller, a given method, and a given BCI.
-     * 
+     *
      * @param caller the parent position
      * @param method the method
      * @param bci a BCI within the method
@@ -56,7 +56,7 @@
 
     /**
      * Converts this code position to a string representation.
-     * 
+     *
      * @return a string representation of this code position
      */
     @Override
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Wed Jul 30 10:39:39 2014 -0700
@@ -620,9 +620,24 @@
      */
     public void addInfopoint(Infopoint infopoint) {
         // The infopoints list must always be sorted
-        if (!infopoints.isEmpty() && infopoints.get(infopoints.size() - 1).pcOffset >= infopoint.pcOffset) {
-            // This re-sorting should be very rare
-            Collections.sort(infopoints);
+        if (!infopoints.isEmpty()) {
+            Infopoint previousInfopoint = infopoints.get(infopoints.size() - 1);
+            if (previousInfopoint.pcOffset > infopoint.pcOffset) {
+                // This re-sorting should be very rare
+                Collections.sort(infopoints);
+                previousInfopoint = infopoints.get(infopoints.size() - 1);
+            }
+            if (previousInfopoint.pcOffset == infopoint.pcOffset) {
+                if (infopoint.reason.canBeOmited()) {
+                    return;
+                }
+                if (previousInfopoint.reason.canBeOmited()) {
+                    Infopoint removed = infopoints.remove(infopoints.size() - 1);
+                    assert removed == previousInfopoint;
+                } else {
+                    throw new RuntimeException("Infopoints that can not be omited should have distinct PCs");
+                }
+            }
         }
         infopoints.add(infopoint);
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InfopointReason.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InfopointReason.java	Wed Jul 30 10:39:39 2014 -0700
@@ -26,13 +26,21 @@
  * A reason for infopoint insertion.
  */
 public enum InfopointReason {
+    UNKNOWN(false),
+    SAFEPOINT(false),
+    CALL(false),
+    IMPLICIT_EXCEPTION(false),
+    METHOD_START(true),
+    METHOD_END(true),
+    LINE_NUMBER(true);
 
-    UNKNOWN,
-    SAFEPOINT,
-    CALL,
-    IMPLICIT_EXCEPTION,
-    METHOD_START,
-    METHOD_END,
-    LINE_NUMBER;
+    private InfopointReason(boolean canBeOmited) {
+        this.canBeOmited = canBeOmited;
+    }
 
+    private final boolean canBeOmited;
+
+    public boolean canBeOmited() {
+        return canBeOmited;
+    }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Wed Jul 30 10:39:39 2014 -0700
@@ -140,22 +140,30 @@
                 for (int i = 0; i < values.length; i++) {
                     ResolvedJavaField field = fields[fieldIndex++];
                     Kind valKind = values[i].getKind().getStackKind();
-                    if ((valKind == Kind.Double || valKind == Kind.Long) && field.getKind() == Kind.Int) {
-                        assert fields[fieldIndex].getKind() == Kind.Int;
-                        fieldIndex++;
+                    if (field.getKind() == Kind.Object) {
+                        assert values[i].getLIRKind().isReference(0) : field + ": " + valKind + " != " + field.getKind();
                     } else {
-                        assert valKind == field.getKind().getStackKind() : field + ": " + valKind + " != " + field.getKind().getStackKind();
+                        if ((valKind == Kind.Double || valKind == Kind.Long) && field.getKind() == Kind.Int) {
+                            assert fields[fieldIndex].getKind() == Kind.Int;
+                            fieldIndex++;
+                        } else {
+                            assert valKind == field.getKind().getStackKind() : field + ": " + valKind + " != " + field.getKind();
+                        }
                     }
                 }
                 assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values);
             } else {
                 Kind componentKind = type.getComponentType().getKind().getStackKind();
-                for (int i = 0; i < values.length; i++) {
-                    assert values[i].getKind().getStackKind() == componentKind || componentKind.getBitCount() >= values[i].getKind().getStackKind().getBitCount() : values[i].getKind() + " != " +
-                                    componentKind;
+                if (componentKind == Kind.Object) {
+                    for (int i = 0; i < values.length; i++) {
+                        assert values[i].getLIRKind().isReference(0) : values[i].getKind() + " != " + componentKind;
+                    }
+                } else {
+                    for (int i = 0; i < values.length; i++) {
+                        assert values[i].getKind() == componentKind || componentKind.getBitCount() >= values[i].getKind().getBitCount() : values[i].getKind() + " != " + componentKind;
+                    }
                 }
             }
-
         }
         return true;
     }
@@ -187,7 +195,11 @@
                 return false;
             }
             for (int i = 0; i < values.length; i++) {
-                if (!Objects.equals(values[i], l.values[i])) {
+                /*
+                 * Virtual objects can form cycles. Calling equals() could therefore lead to
+                 * infinite recursion.
+                 */
+                if (!same(values[i], l.values[i])) {
                     return false;
                 }
             }
@@ -195,4 +207,8 @@
         }
         return false;
     }
+
+    private static boolean same(Object o1, Object o2) {
+        return o1 == o2;
+    }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java	Wed Jul 30 10:39:39 2014 -0700
@@ -60,4 +60,10 @@
      * @return the current method
      */
     ResolvedJavaMethod getMethod();
+
+    /**
+     * Checks if the current method is equal to the given method. This is semantically equivalent to
+     * {@code method.equals(getMethod())}, but can be implemented more efficiently.
+     */
+    boolean isMethod(ResolvedJavaMethod method);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrameVisitor.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.code.stack;
+
+/**
+ * Callback interface for {@link StackIntrospection#iterateFrames}. Implementations of
+ * {@link #visitFrame} return null to indicate that frame iteration should continue and the next
+ * caller frame should be visited; and return any non-null value to indicate that frame iteration
+ * should stop.
+ */
+public interface InspectedFrameVisitor<T> {
+
+    T visitFrame(InspectedFrame frame);
+}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Wed Jul 30 10:39:39 2014 -0700
@@ -27,13 +27,19 @@
 public interface StackIntrospection {
 
     /**
-     * Accesses the current stack, returning a collection of {@link InspectedFrame}s that can be
-     * used to inspect the stack frames' contents.
+     * Accesses the current stack, providing {@link InspectedFrame}s to the visitor that can be used
+     * to inspect the stack frames' contents. Iteration continues as long as
+     * {@link InspectedFrameVisitor#visitFrame}, which is invoked for every {@link InspectedFrame},
+     * returns null. Any non-null result of the visitor indicates that frame iteration should stop.
      *
      * @param initialMethods if this is non-{@code null}, then the stack trace will start at these
      *            methods
      * @param matchingMethods if this is non-{@code null}, then only matching stack frames are
      *            returned
+     * @param initialSkip the number of matching methods to skip (including the initial method)
+     * @param visitor the visitor that is called for every matching method
+     * @return the last result returned by the visitor (which is non-null to indicate that iteration
+     *         should stop), or null if the whole stack was iterated.
      */
-    Iterable<InspectedFrame> getStackTrace(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip);
+    <T> T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor<T> visitor);
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Wed Jul 30 10:39:39 2014 -0700
@@ -41,4 +41,5 @@
     RuntimeConstraint,
     LoopLimitCheck,
     Aliasing,
+    TransferToInterpreter,
 }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -52,7 +52,7 @@
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
         AllocatableValue targetAddress = AMD64.rax.asValue();
         gen.emitMove(targetAddress, operand(callTarget.computedAddress()));
-        append(new AMD64Call.IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState));
+        append(new AMD64Call.IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, targetAddress, callState));
     }
 
     @Override
@@ -350,10 +350,10 @@
 
     @MatchRule("(If (IntegerEquals=compare value Read=access))")
     @MatchRule("(If (IntegerLessThan=compare value Read=access))")
-    @MatchRule("(If (IntegerBelowThan=compare value Read=access))")
+    @MatchRule("(If (IntegerBelow=compare value Read=access))")
     @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
     @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
-    @MatchRule("(If (IntegerBelowThan=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerBelow=compare value FloatingRead=access))")
     @MatchRule("(If (FloatEquals=compare value Read=access))")
     @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
     @MatchRule("(If (FloatLessThan=compare value Read=access))")
@@ -473,11 +473,6 @@
     }
 
     @Override
-    public void visitInfopointNode(InfopointNode i) {
-        append(new InfopointOp(stateFor(i.getState()), i.reason));
-    }
-
-    @Override
     public AMD64LIRGenerator getLIRGeneratorTool() {
         return (AMD64LIRGenerator) gen;
     }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Wed Jul 30 10:39:39 2014 -0700
@@ -150,6 +150,8 @@
     public static final OptionValue<Integer> PrintIdealGraphPort = new OptionValue<>(4444);
     @Option(help = "")
     public static final OptionValue<Integer> PrintBinaryGraphPort = new OptionValue<>(4445);
+    @Option(help = "")
+    public static final OptionValue<Boolean> PrintIdealGraphSchedule = new OptionValue<>(false);
 
     // Other printing settings
     @Option(help = "")
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/calc/Condition.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/calc/Condition.java	Wed Jul 30 10:39:39 2014 -0700
@@ -337,128 +337,130 @@
      *         false
      */
     public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
-        switch (lt.getKind()) {
-            case Boolean:
-            case Byte:
-            case Char:
-            case Short:
-            case Int: {
-                int x = lt.asInt();
-                int y = rt.asInt();
-                switch (this) {
-                    case EQ:
-                        return x == y;
-                    case NE:
-                        return x != y;
-                    case LT:
-                        return x < y;
-                    case LE:
-                        return x <= y;
-                    case GT:
-                        return x > y;
-                    case GE:
-                        return x >= y;
-                    case AE:
-                        return UnsignedMath.aboveOrEqual(x, y);
-                    case BE:
-                        return UnsignedMath.belowOrEqual(x, y);
-                    case AT:
-                        return UnsignedMath.aboveThan(x, y);
-                    case BT:
-                        return UnsignedMath.belowThan(x, y);
-                    default:
-                        throw new GraalInternalError("expected condition: %s", this);
-                }
-            }
-            case Long: {
-                long x = lt.asLong();
-                long y = rt.asLong();
-                switch (this) {
-                    case EQ:
-                        return x == y;
-                    case NE:
-                        return x != y;
-                    case LT:
-                        return x < y;
-                    case LE:
-                        return x <= y;
-                    case GT:
-                        return x > y;
-                    case GE:
-                        return x >= y;
-                    case AE:
-                        return UnsignedMath.aboveOrEqual(x, y);
-                    case BE:
-                        return UnsignedMath.belowOrEqual(x, y);
-                    case AT:
-                        return UnsignedMath.aboveThan(x, y);
-                    case BT:
-                        return UnsignedMath.belowThan(x, y);
-                    default:
-                        throw new GraalInternalError("expected condition: %s", this);
-                }
-            }
-            case Object: {
-                Boolean equal = constantReflection.constantEquals(lt, rt);
-                if (equal != null) {
+        if (lt instanceof PrimitiveConstant) {
+            switch (lt.getKind()) {
+                case Boolean:
+                case Byte:
+                case Char:
+                case Short:
+                case Int: {
+                    int x = lt.asInt();
+                    int y = rt.asInt();
                     switch (this) {
                         case EQ:
-                            return equal.booleanValue();
+                            return x == y;
                         case NE:
-                            return !equal.booleanValue();
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        case AE:
+                            return UnsignedMath.aboveOrEqual(x, y);
+                        case BE:
+                            return UnsignedMath.belowOrEqual(x, y);
+                        case AT:
+                            return UnsignedMath.aboveThan(x, y);
+                        case BT:
+                            return UnsignedMath.belowThan(x, y);
+                        default:
+                            throw new GraalInternalError("expected condition: %s", this);
+                    }
+                }
+                case Long: {
+                    long x = lt.asLong();
+                    long y = rt.asLong();
+                    switch (this) {
+                        case EQ:
+                            return x == y;
+                        case NE:
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        case AE:
+                            return UnsignedMath.aboveOrEqual(x, y);
+                        case BE:
+                            return UnsignedMath.belowOrEqual(x, y);
+                        case AT:
+                            return UnsignedMath.aboveThan(x, y);
+                        case BT:
+                            return UnsignedMath.belowThan(x, y);
                         default:
                             throw new GraalInternalError("expected condition: %s", this);
                     }
                 }
-            }
-            case Float: {
-                float x = lt.asFloat();
-                float y = rt.asFloat();
-                if (Float.isNaN(x) || Float.isNaN(y)) {
-                    return unorderedIsTrue;
+                case Float: {
+                    float x = lt.asFloat();
+                    float y = rt.asFloat();
+                    if (Float.isNaN(x) || Float.isNaN(y)) {
+                        return unorderedIsTrue;
+                    }
+                    switch (this) {
+                        case EQ:
+                            return x == y;
+                        case NE:
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        default:
+                            throw new GraalInternalError("expected condition: %s", this);
+                    }
                 }
-                switch (this) {
-                    case EQ:
-                        return x == y;
-                    case NE:
-                        return x != y;
-                    case LT:
-                        return x < y;
-                    case LE:
-                        return x <= y;
-                    case GT:
-                        return x > y;
-                    case GE:
-                        return x >= y;
-                    default:
-                        throw new GraalInternalError("expected condition: %s", this);
+                case Double: {
+                    double x = lt.asDouble();
+                    double y = rt.asDouble();
+                    if (Double.isNaN(x) || Double.isNaN(y)) {
+                        return unorderedIsTrue;
+                    }
+                    switch (this) {
+                        case EQ:
+                            return x == y;
+                        case NE:
+                            return x != y;
+                        case LT:
+                            return x < y;
+                        case LE:
+                            return x <= y;
+                        case GT:
+                            return x > y;
+                        case GE:
+                            return x >= y;
+                        default:
+                            throw new GraalInternalError("expected condition: %s", this);
+                    }
                 }
+                default:
+                    throw new GraalInternalError("expected value kind %s while folding condition: %s", lt.getKind(), this);
             }
-            case Double: {
-                double x = lt.asDouble();
-                double y = rt.asDouble();
-                if (Double.isNaN(x) || Double.isNaN(y)) {
-                    return unorderedIsTrue;
-                }
-                switch (this) {
-                    case EQ:
-                        return x == y;
-                    case NE:
-                        return x != y;
-                    case LT:
-                        return x < y;
-                    case LE:
-                        return x <= y;
-                    case GT:
-                        return x > y;
-                    case GE:
-                        return x >= y;
-                    default:
-                        throw new GraalInternalError("expected condition: %s", this);
-                }
+        } else {
+            Boolean equal = constantReflection.constantEquals(lt, rt);
+            if (equal == null) {
+                throw new GraalInternalError("could not fold %s %s %s", lt, this, rt);
             }
-            default:
-                throw new GraalInternalError("expected value kind %s while folding condition: %s", lt.getKind(), this);
+            switch (this) {
+                case EQ:
+                    return equal.booleanValue();
+                case NE:
+                    return !equal.booleanValue();
+                default:
+                    throw new GraalInternalError("expected condition: %s", this);
+            }
         }
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.compiler.common.type;
 
+import java.util.function.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.spi.*;
@@ -134,6 +136,16 @@
         return str.toString();
     }
 
+    private static double meetBounds(double a, double b, DoubleBinaryOperator op) {
+        if (Double.isNaN(a)) {
+            return b;
+        } else if (Double.isNaN(b)) {
+            return a;
+        } else {
+            return op.applyAsDouble(a, b);
+        }
+    }
+
     @Override
     public Stamp meet(Stamp otherStamp) {
         if (otherStamp == this) {
@@ -144,12 +156,12 @@
         }
         FloatStamp other = (FloatStamp) otherStamp;
         assert getBits() == other.getBits();
-        double meetUpperBound = Math.max(upperBound, other.upperBound);
-        double meetLowerBound = Math.min(lowerBound, other.lowerBound);
+        double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max);
+        double meetLowerBound = meetBounds(lowerBound, other.lowerBound, Math::min);
         boolean meetNonNaN = nonNaN && other.nonNaN;
-        if (meetLowerBound == lowerBound && meetUpperBound == upperBound && meetNonNaN == nonNaN) {
+        if (Double.compare(meetLowerBound, lowerBound) == 0 && Double.compare(meetUpperBound, upperBound) == 0 && meetNonNaN == nonNaN) {
             return this;
-        } else if (meetLowerBound == other.lowerBound && meetUpperBound == other.upperBound && meetNonNaN == other.nonNaN) {
+        } else if (Double.compare(meetLowerBound, other.lowerBound) == 0 && Double.compare(meetUpperBound, other.upperBound) == 0 && meetNonNaN == other.nonNaN) {
             return other;
         } else {
             return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN);
@@ -169,9 +181,9 @@
         double joinUpperBound = Math.min(upperBound, other.upperBound);
         double joinLowerBound = Math.max(lowerBound, other.lowerBound);
         boolean joinNonNaN = nonNaN || other.nonNaN;
-        if (joinLowerBound == lowerBound && joinUpperBound == upperBound && joinNonNaN == nonNaN) {
+        if (Double.compare(joinLowerBound, lowerBound) == 0 && Double.compare(joinUpperBound, upperBound) == 0 && joinNonNaN == nonNaN) {
             return this;
-        } else if (joinLowerBound == other.lowerBound && joinUpperBound == other.upperBound && joinNonNaN == other.nonNaN) {
+        } else if (Double.compare(joinLowerBound, other.lowerBound) == 0 && Double.compare(joinUpperBound, other.upperBound) == 0 && joinNonNaN == other.nonNaN) {
             return other;
         } else {
             return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN);
@@ -227,7 +239,7 @@
 
     @Override
     public Constant asConstant() {
-        if (nonNaN && lowerBound == upperBound) {
+        if (nonNaN && Double.compare(lowerBound, upperBound) == 0) {
             switch (getBits()) {
                 case 32:
                     return Constant.forFloat((float) lowerBound);
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,7 +32,7 @@
     }
 
     @Override
-    protected AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+    protected ObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
         return new ObjectStamp(type, exactType, nonNull, alwaysNull);
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java	Wed Jul 30 10:39:39 2014 -0700
@@ -248,6 +248,10 @@
     }
 
     public static Stamp exact(ResolvedJavaType type) {
-        return new ObjectStamp(type, true, false, false);
+        if (ObjectStamp.isConcreteType(type)) {
+            return new ObjectStamp(type, true, false, false);
+        } else {
+            return illegal(Kind.Object);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -47,22 +47,16 @@
 
     @Override
     protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented(callTarget.target().format("direct call to %H.%n(%p)"));
+        throw GraalInternalError.unimplemented(callTarget.targetMethod().format("direct call to %H.%n(%p)"));
     }
 
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        throw GraalInternalError.unimplemented(callTarget.target().format("direct call to %H.%n(%p)"));
+        throw GraalInternalError.unimplemented(callTarget.targetMethod().format("direct call to %H.%n(%p)"));
     }
 
     @Override
     public void visitBreakpointNode(BreakpointNode node) {
         throw GraalInternalError.unimplemented();
     }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented();
-    }
 }
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -123,9 +123,4 @@
         // append(new PTXSafepointOp(info, runtime().config, this));
         Debug.log("visitSafePointNode unimplemented");
     }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        throw GraalInternalError.unimplemented("PTXLIRGenerator.visitInfopointNode()");
-    }
 }
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -26,7 +26,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
@@ -56,9 +55,4 @@
         Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, gen.target(), false), node.arguments());
         append(new SPARCBreakpointOp(parameters));
     }
-
-    @Override
-    public void visitInfopointNode(InfopointNode i) {
-        append(new InfopointOp(stateFor(i.getState()), i.reason));
-    }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.calc.ObjectEqualsNode;
 import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -27,12 +27,13 @@
 import static org.junit.Assert.*;
 
 import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase;
+
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -693,7 +693,7 @@
      * Parses a Java method in debug mode to produce a graph with extra infopoints.
      */
     protected StructuredGraph parseDebug(Method m) {
-        return parse0(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerInfopointDefault()));
+        return parse0(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()));
     }
 
     private StructuredGraph parse0(Method m, PhaseSuite<HighTierContext> graphBuilderSuite) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -76,14 +76,14 @@
         final Method method = getMethod("testMethod");
         final StructuredGraph graph = parseDebug(method);
         int graphLineSPs = 0;
-        for (InfopointNode ipn : graph.getNodes().filter(InfopointNode.class)) {
-            if (ipn.reason == InfopointReason.LINE_NUMBER) {
+        for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) {
+            if (ipn.getReason() == InfopointReason.LINE_NUMBER) {
                 ++graphLineSPs;
             }
         }
         assertTrue(graphLineSPs > 0);
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerInfopointDefault());
+        PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault());
         final CompilationResult cr = compileGraph(graph, null, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL,
                         getProfilingInfo(graph), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         int lineSPs = 0;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -232,7 +232,7 @@
         try (Scope s = Debug.scope("InliningTest", new DebugDumpScope(snippet))) {
             Method method = getMethod(snippet);
             StructuredGraph graph = eagerInfopointMode ? parseDebug(method) : parse(method);
-            PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerInfopointDefault()) : getDefaultGraphBuilderSuite();
+            PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()) : getDefaultGraphBuilderSuite();
             Assumptions assumptions = new Assumptions(true);
             HighTierContext context = new HighTierContext(getProviders(), assumptions, null, graphBuilderSuite, OptimisticOptimizations.ALL);
             Debug.dump(graph, "Graph");
@@ -277,10 +277,10 @@
     private static int[] countMethodInfopoints(StructuredGraph graph) {
         int start = 0;
         int end = 0;
-        for (InfopointNode ipn : graph.getNodes().filter(InfopointNode.class)) {
-            if (ipn.reason == InfopointReason.METHOD_START) {
+        for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) {
+            if (ipn.getReason() == InfopointReason.METHOD_START) {
                 ++start;
-            } else if (ipn.reason == InfopointReason.METHOD_END) {
+            } else if (ipn.getReason() == InfopointReason.METHOD_END) {
                 ++end;
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -89,11 +89,11 @@
                             assert currentField != null;
                             int pos = 0;
                             for (int i = 0; i < vobj.entryCount(); i++) {
-                                if (!currentField.fieldValues().get(i).isConstant() || currentField.fieldValues().get(i).asConstant().getKind() != Kind.Illegal) {
-                                    values[pos++] = toValue(currentField.fieldValues().get(i));
+                                if (!currentField.values().get(i).isConstant() || currentField.values().get(i).asConstant().getKind() != Kind.Illegal) {
+                                    values[pos++] = toValue(currentField.values().get(i));
                                 } else {
-                                    assert currentField.fieldValues().get(i - 1).getKind() == Kind.Double || currentField.fieldValues().get(i - 1).getKind() == Kind.Long : vobj + " " + i + " " +
-                                                    currentField.fieldValues().get(i - 1);
+                                    assert currentField.values().get(i - 1).getKind() == Kind.Double || currentField.values().get(i - 1).getKind() == Kind.Long : vobj + " " + i + " " +
+                                                    currentField.values().get(i - 1);
                                 }
                             }
                             if (pos != vobj.entryCount()) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -74,7 +74,7 @@
 @MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = FloatMulNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerAddNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerBelowThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerBelowNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerMulNode.class, inputs = {"x", "y"}, commutative = true)
@@ -602,6 +602,16 @@
     }
 
     @Override
+    public void visitFullInfopointNode(FullInfopointNode i) {
+        append(new FullInfopointOp(stateFor(i.getState()), i.getReason()));
+    }
+
+    @Override
+    public void visitSimpleInfopointNode(SimpleInfopointNode i) {
+        append(new SimpleInfopointOp(i.getReason(), i.getPosition()));
+    }
+
+    @Override
     public LIRGeneratorTool getLIRGeneratorTool() {
         return gen;
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Wed Jul 30 10:39:39 2014 -0700
@@ -68,35 +68,41 @@
         private static final DebugMetric MatchResult_ALREADY_USED = Debug.metric("MatchResult_ALREADY_USED");
 
         static final Result OK = new Result(MatchResultCode.OK, null, null);
+        private static final Result CACHED_WRONG_CLASS = new Result(MatchResultCode.WRONG_CLASS, null, null);
+        private static final Result CACHED_NAMED_VALUE_MISMATCH = new Result(MatchResultCode.NAMED_VALUE_MISMATCH, null, null);
+        private static final Result CACHED_TOO_MANY_USERS = new Result(MatchResultCode.TOO_MANY_USERS, null, null);
+        private static final Result CACHED_NOT_IN_BLOCK = new Result(MatchResultCode.NOT_IN_BLOCK, null, null);
+        private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null);
+        private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null);
 
         static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) {
             MatchResult_WRONG_CLASS.increment();
-            return new Result(MatchResultCode.WRONG_CLASS, node, matcher);
+            return Debug.isEnabled() ? new Result(MatchResultCode.WRONG_CLASS, node, matcher) : CACHED_WRONG_CLASS;
         }
 
         static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) {
             MatchResult_NAMED_VALUE_MISMATCH.increment();
-            return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher);
+            return Debug.isEnabled() ? new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher) : CACHED_NAMED_VALUE_MISMATCH;
         }
 
         static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) {
             MatchResult_TOO_MANY_USERS.increment();
-            return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher);
+            return Debug.isEnabled() ? new Result(MatchResultCode.TOO_MANY_USERS, node, matcher) : CACHED_TOO_MANY_USERS;
         }
 
         static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) {
             MatchResult_NOT_IN_BLOCK.increment();
-            return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher);
+            return Debug.isEnabled() ? new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher) : CACHED_NOT_IN_BLOCK;
         }
 
         static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) {
             MatchResult_NOT_SAFE.increment();
-            return new Result(MatchResultCode.NOT_SAFE, node, matcher);
+            return Debug.isEnabled() ? new Result(MatchResultCode.NOT_SAFE, node, matcher) : CACHED_NOT_SAFE;
         }
 
         static Result ALREADY_USED(ValueNode node, MatchPattern matcher) {
             MatchResult_ALREADY_USED.increment();
-            return new Result(MatchResultCode.ALREADY_USED, node, matcher);
+            return Debug.isEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED;
         }
 
         @Override
@@ -104,7 +110,11 @@
             if (code == MatchResultCode.OK) {
                 return "OK";
             }
-            return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
+            if (node == null) {
+                return code.toString();
+            } else {
+                return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
+            }
         }
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Wed Jul 30 10:39:39 2014 -0700
@@ -70,7 +70,7 @@
             }
         }
 
-        appendPhase(new CleanTypeProfileProxyPhase());
+        appendPhase(new CleanTypeProfileProxyPhase(canonicalizer));
 
         if (FullUnroll.getValue()) {
             appendPhase(new LoopFullUnrollPhase(canonicalizer));
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Wed Jul 30 10:39:39 2014 -0700
@@ -54,6 +54,13 @@
 
         appendPhase(new ExpandLogicPhase());
 
+        /* Cleanup IsNull checks resulting from MID_TIER/LOW_TIER lowering and ExpandLogic phase. */
+        if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+            appendPhase(new IterativeConditionalEliminationPhase(canonicalizer));
+            /* Canonicalizer may create some new ShortCircuitOrNodes so clean them up. */
+            appendPhase(new ExpandLogicPhase());
+        }
+
         appendPhase(new UseTrappingNullChecksPhase());
 
         appendPhase(new DeadCodeEliminationPhase());
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Wed Jul 30 10:39:39 2014 -0700
@@ -578,7 +578,7 @@
                 }
             }
             if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) {
-                maybeNotifyZeroInputs(oldInput);
+                maybeNotifyZeroUsages(oldInput);
             }
         }
     }
@@ -707,7 +707,7 @@
         }
     }
 
-    private void maybeNotifyZeroInputs(Node node) {
+    private void maybeNotifyZeroUsages(Node node) {
         if (graph != null) {
             assert !graph.isFrozen();
             NodeEventListener listener = graph.nodeEventListener;
@@ -753,7 +753,7 @@
             if (input.recordsUsages()) {
                 removeThisFromUsages(input);
                 if (input.usages().isEmpty()) {
-                    maybeNotifyZeroInputs(input);
+                    maybeNotifyZeroUsages(input);
                 }
             }
         }
@@ -806,12 +806,18 @@
     }
 
     public final Node copyWithInputs() {
-        Node newNode = clone(graph);
+        return copyWithInputs(true);
+    }
+
+    public final Node copyWithInputs(boolean addToGraph) {
+        Node newNode = clone(addToGraph ? graph : null);
         NodeClass clazz = getNodeClass();
         clazz.copyInputs(this, newNode);
-        for (Node input : inputs()) {
-            if (input.recordsUsages()) {
-                input.addUsage(newNode);
+        if (addToGraph) {
+            for (Node input : inputs()) {
+                if (input.recordsUsages()) {
+                    input.addUsage(newNode);
+                }
             }
         }
         return newNode;
@@ -834,7 +840,7 @@
 
     final Node clone(Graph into, boolean clearInputsAndSuccessors) {
         NodeClass nodeClass = getNodeClass();
-        if (nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
+        if (into != null && nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
             Node otherNode = into.findNodeInCache(this);
             if (otherNode != null) {
                 return otherNode;
@@ -854,13 +860,15 @@
         newNode.graph = into;
         newNode.typeCacheNext = null;
         newNode.id = INITIAL_ID;
-        into.register(newNode);
+        if (into != null) {
+            into.register(newNode);
+        }
         newNode.usage0 = null;
         newNode.usage1 = null;
         newNode.extraUsages = NO_NODES;
         newNode.predecessor = null;
 
-        if (nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
+        if (into != null && nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
             into.putNodeIntoCache(newNode);
         }
         newNode.afterClone(this);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Jul 30 10:39:39 2014 -0700
@@ -397,7 +397,7 @@
             node.getNodeClass().set(node, this, value);
         }
 
-        void initialize(Node node, Node value) {
+        public void initialize(Node node, Node value) {
             node.getNodeClass().initializePosition(node, this, value);
         }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -48,9 +48,9 @@
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
@@ -148,12 +148,12 @@
     protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
         InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
         if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
-            append(new AMD64HotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
+            append(new AMD64HotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
         } else {
             assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
-            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
             assert !resolvedMethod.isAbstract() : "Cannot make direct call to abstract method.";
-            append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
+            append(new AMD64HotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
         }
     }
 
@@ -164,7 +164,7 @@
             gen.emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
             AllocatableValue targetAddress = AMD64.rax.asValue();
             gen.emitMove(targetAddress, operand(callTarget.computedAddress()));
-            append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
+            append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
         } else {
             super.emitIndirectCall(callTarget, result, parameters, temps, callState);
         }
@@ -192,11 +192,11 @@
     }
 
     @Override
-    public void visitInfopointNode(InfopointNode i) {
+    public void visitFullInfopointNode(FullInfopointNode i) {
         if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) {
             Debug.log("Ignoring InfopointNode for AFTER_BCI");
         } else {
-            super.visitInfopointNode(i);
+            super.visitFullInfopointNode(i);
         }
     }
 
@@ -243,12 +243,12 @@
 
     @MatchRule("(If (IntegerEquals=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (IntegerLessThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
-    @MatchRule("(If (IntegerBelowThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerBelow=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (FloatEquals=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (FloatLessThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (IntegerEquals=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (IntegerLessThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
-    @MatchRule("(If (IntegerBelowThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerBelow=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (FloatEquals=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
     @MatchRule("(If (FloatLessThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
     public ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, CompressionNode compress, ValueNode value, ConstantLocationNode location, Access access) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -28,7 +28,7 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 /**
  * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind.*;
-
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
@@ -32,7 +30,7 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 /**
  * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
@@ -53,7 +51,7 @@
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         // The mark for an invocation that uses an inline cache must be placed at the
         // instruction that loads the Klass from the inline cache.
-        MarkId.recordMark(crb, invokeKind == Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE);
+        MarkId.recordMark(crb, invokeKind == InvokeKind.Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE);
         // This must be emitted exactly like this to ensure it's patchable
         masm.movq(AMD64.rax, HotSpotGraalRuntime.runtime().getConfig().nonOopBits);
         super.emitCode(crb, masm);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Wed Jul 30 10:39:39 2014 -0700
@@ -238,10 +238,12 @@
         @Override
         protected void run(StructuredGraph graph) {
             int argCount = 0;
+            Stamp nonNull = StampFactory.objectNonNull();
             for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
                 argCount++;
                 if (argCount < numArgs && param.stamp() instanceof ObjectStamp) {
-                    param.setStamp(StampFactory.declaredNonNull(((ObjectStamp) param.stamp()).type()));
+                    ObjectStamp paramStamp = (ObjectStamp) param.stamp();
+                    param.setStamp(paramStamp.join(nonNull));
                 }
             }
         }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -40,7 +40,7 @@
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
@@ -97,12 +97,12 @@
     protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
         InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
         if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
-            append(new SPARCHotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
+            append(new SPARCHotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
         } else {
             assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special;
-            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target();
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
             assert !resolvedMethod.isAbstract() : "Cannot make direct call to abstract method.";
-            append(new SPARCHotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind));
+            append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
         }
     }
 
@@ -112,7 +112,7 @@
         gen.emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
         AllocatableValue targetAddress = g3.asValue();
         gen.emitMove(targetAddress, operand(callTarget.computedAddress()));
-        append(new SPARCIndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
+        append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
     }
 
     @Override
@@ -142,12 +142,11 @@
     }
 
     @Override
-    public void visitInfopointNode(InfopointNode i) {
+    public void visitFullInfopointNode(FullInfopointNode i) {
         if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) {
             Debug.log("Ignoring InfopointNode for AFTER_BCI");
         } else {
-            super.visitInfopointNode(i);
+            super.visitFullInfopointNode(i);
         }
     }
-
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -28,7 +28,7 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.SPARCCall.DirectCallOp;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 /**
  * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -22,19 +22,18 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.SPARCCall.DirectCallOp;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
 /**
  * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
@@ -55,7 +54,7 @@
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
         // The mark for an invocation that uses an inline cache must be placed at the
         // instruction that loads the Klass from the inline cache.
-        MarkId.recordMark(crb, invokeKind == Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE);
+        MarkId.recordMark(crb, invokeKind == InvokeKind.Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE);
         Register scratchRegister = g5;
         new Setx(HotSpotGraalRuntime.runtime().getConfig().nonOopBits, scratchRegister, true).emit(masm);
         super.emitCode(crb, masm);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -52,7 +52,7 @@
                         Invoke invoke = (Invoke) node;
                         Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode);
                         LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget();
-                        JavaMethod callee = directCall.target();
+                        JavaMethod callee = directCall.targetMethod();
                         Assert.assertTrue(callee.getName().equals("<init>"));
                         Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) ||
                                         getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass()));
@@ -64,7 +64,7 @@
                     if (node instanceof Invoke) {
                         Invoke invoke = (Invoke) node;
                         LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget();
-                        JavaMethod callee = directCall.target();
+                        JavaMethod callee = directCall.targetMethod();
                         if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) {
                             found = true;
                         } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/BytecodeVerificationTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,122 @@
+/*
+ * 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.test;
+
+import java.io.*;
+
+import jdk.internal.org.objectweb.asm.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+
+/**
+ * Tests that the Graal API can only be used to access verified bytecode.
+ */
+public class BytecodeVerificationTest extends GraalCompilerTest {
+
+    @Test(expected = VerifyError.class)
+    public void test() throws Exception {
+        BadClassLoader loader = new BadClassLoader();
+        String className = BytecodeVerificationTest.class.getName() + "$BadClass";
+        Class<?> c = loader.findClass(className);
+
+        // Should fail with a verification error as long as -XX:-BytecodeVerificationRemote is not
+        // specified on the command line
+        getMetaAccess().lookupJavaMethod(c.getDeclaredMethod("getValue")).getCode();
+    }
+
+    /**
+     * Class that will be rewritten during loading to be unverifiable.
+     */
+    public static class BadClass {
+
+        public static String value;
+
+        public static String getValue() {
+            // Re-written to "return 5;"
+            return value;
+        }
+    }
+
+    /**
+     * Rewrites {@link BadClass#getValue()} to:
+     *
+     * <pre>
+     * public static String getValue() {
+     *     return 5;
+     * }
+     * </pre>
+     */
+    private static class BadClassRewriter extends ClassVisitor {
+
+        public BadClassRewriter(ClassWriter cw) {
+            super(Opcodes.ASM5, cw);
+        }
+
+        @Override
+        public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) {
+            MethodVisitor mv = super.visitMethod(access, name, d, signature, exceptions);
+            if (name.equals("getValue")) {
+                return new MethodVisitor(Opcodes.ASM5, mv) {
+                    @Override
+                    public void visitFieldInsn(int opcode, String owner, String fieldName, String fieldDesc) {
+                        if (opcode == Opcodes.GETSTATIC) {
+                            visitInsn(Opcodes.ICONST_5);
+                        } else {
+                            super.visitFieldInsn(opcode, owner, name, fieldDesc);
+                        }
+                    }
+                };
+            }
+            return mv;
+        }
+    }
+
+    /**
+     * Class loader used for loading {@link BadClass}. Using a separate class loader ensure the
+     * class is treated as "remote" so that it will be subject to verification by default.
+     */
+    private static class BadClassLoader extends ClassLoader {
+
+        @Override
+        protected Class<?> findClass(final String name) throws ClassNotFoundException {
+            byte[] classData = null;
+            try {
+                InputStream is = BytecodeVerificationTest.class.getResourceAsStream("/" + name.replace('.', '/') + ".class");
+                classData = new byte[is.available()];
+                new DataInputStream(is).readFully(classData);
+            } catch (IOException e) {
+                Assert.fail("can't access class: " + name);
+            }
+
+            ClassReader cr = new ClassReader(classData);
+            ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
+
+            BadClassRewriter rewriter = new BadClassRewriter(cw);
+            cr.accept(rewriter, ClassReader.SKIP_FRAMES);
+            classData = cw.toByteArray();
+            return defineClass(null, classData, 0, classData.length);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/GraalClassLoaderTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.test;
+
+import org.junit.*;
+
+import sun.management.*;
+
+import com.oracle.graal.api.runtime.*;
+import com.sun.management.*;
+
+/**
+ * Tests that the Graal API is inaccessible when -XX:+UseGraalClassLoader is specified. Execute as
+ * follows to show class loader based isolation:
+ *
+ * <pre>
+ * mx unittest -XX:+UseGraalClassLoader GraalClassLoaderTest
+ * </pre>
+ */
+public class GraalClassLoaderTest {
+
+    @Test
+    public void test() throws Exception {
+        if (System.getProperty("java.vm.version").contains("graal")) {
+            HotSpotDiagnosticMXBean diag = ManagementFactoryHelper.getDiagnosticMXBean();
+            VMOption option = diag.getVMOption("UseGraalClassLoader");
+            if (option.getValue().equals("true")) {
+                try {
+                    Graal.getRuntime();
+                    Assert.fail();
+                } catch (NoClassDefFoundError e) {
+                    // expected
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Jul 30 10:39:39 2014 -0700
@@ -52,6 +52,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -133,7 +134,11 @@
 
         if (HotSpotGraalRuntime.runtime().getCompilerToVM().shouldDebugNonSafepoints()) {
             // need to tweak the graph builder config
-            suite.findPhase(GraphBuilderPhase.class).set(new GraphBuilderPhase(GraphBuilderConfiguration.getInfopointDefault()));
+            suite = suite.copy();
+            GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) suite.findPhase(GraphBuilderPhase.class).previous();
+            GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
+            GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig.withDebugInfoMode(DebugInfoMode.Simple));
+            suite.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
         }
 
         boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Wed Jul 30 10:39:39 2014 -0700
@@ -519,38 +519,20 @@
         }
     }
 
-    public Iterable<InspectedFrame> getStackTrace(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip) {
+    @Override
+    public <T> T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor<T> visitor) {
         final long[] initialMetaMethods = toMeta(initialMethods);
         final long[] matchingMetaMethods = toMeta(matchingMethods);
-        class StackFrameIterator implements Iterator<InspectedFrame> {
 
-            private HotSpotStackFrameReference current = compilerToVm.getNextStackFrame(null, initialMetaMethods, initialSkip);
-            // we don't want to read ahead if hasNext isn't called
-            private boolean advanced = true;
-
-            public boolean hasNext() {
-                update();
-                return current != null;
+        HotSpotStackFrameReference current = compilerToVm.getNextStackFrame(null, initialMetaMethods, initialSkip);
+        while (current != null) {
+            T result = visitor.visitFrame(current);
+            if (result != null) {
+                return result;
             }
-
-            public InspectedFrame next() {
-                update();
-                advanced = false;
-                return current;
-            }
-
-            private void update() {
-                if (!advanced) {
-                    current = compilerToVm.getNextStackFrame(current, matchingMetaMethods, 0);
-                    advanced = true;
-                }
-            }
+            current = compilerToVm.getNextStackFrame(current, matchingMetaMethods, 0);
         }
-        return new Iterable<InspectedFrame>() {
-            public Iterator<InspectedFrame> iterator() {
-                return new StackFrameIterator();
-            }
-        };
+        return null;
     }
 
     private static long[] toMeta(ResolvedJavaMethod[] methods) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java	Wed Jul 30 10:39:39 2014 -0700
@@ -51,26 +51,37 @@
         return frameNumber;
     }
 
+    @Override
     public Object getLocal(int index) {
         return locals[index];
     }
 
+    @Override
     public boolean isVirtual(int index) {
         return localIsVirtual == null ? false : localIsVirtual[index];
     }
 
+    @Override
     public void materializeVirtualObjects(boolean invalidateCode) {
         compilerToVM.materializeVirtualObjects(this, invalidateCode);
     }
 
+    @Override
     public int getBytecodeIndex() {
         return bci;
     }
 
+    @Override
     public ResolvedJavaMethod getMethod() {
         return HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
     }
 
+    @Override
+    public boolean isMethod(ResolvedJavaMethod method) {
+        return metaspaceMethod == ((HotSpotResolvedJavaMethod) method).getMetaspaceMethod();
+    }
+
+    @Override
     public boolean hasVirtualObjects() {
         return localIsVirtual != null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Jul 30 10:39:39 2014 -0700
@@ -848,6 +848,8 @@
     @HotSpotVMType(name = "vtableEntry", get = HotSpotVMType.Type.SIZE) @Stable public int vtableEntrySize;
     @HotSpotVMField(name = "vtableEntry::_method", type = "Method*", get = HotSpotVMField.Type.OFFSET) @Stable public int vtableEntryMethodOffset;
     @HotSpotVMValue(expression = "InstanceKlass::vtable_start_offset() * HeapWordSize") @Stable public int instanceKlassVtableStartOffset;
+    @HotSpotVMValue(expression = "InstanceKlass::vtable_length_offset() * HeapWordSize") @Stable public int instanceKlassVtableLengthOffset;
+    @HotSpotVMValue(expression = "Universe::base_vtable_size() / vtableEntry::size()") @Stable public int baseVtableLength;
 
     /**
      * The offset of the array length word in an array object's header.
@@ -1014,6 +1016,7 @@
     @HotSpotVMField(name = "ThreadShadow::_pending_exception", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingExceptionOffset;
     @HotSpotVMField(name = "ThreadShadow::_pending_deoptimization", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingDeoptimizationOffset;
     @HotSpotVMField(name = "ThreadShadow::_pending_failed_speculation", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingFailedSpeculationOffset;
+    @HotSpotVMField(name = "ThreadShadow::_pending_transfer_to_interpreter", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingTransferToInterpreterOffset;
 
     @HotSpotVMFlag(name = "UseHSAILDeoptimization") @Stable public boolean useHSAILDeoptimization;
     @HotSpotVMFlag(name = "UseHSAILSafepoints") @Stable public boolean useHSAILSafepoints;
@@ -1460,6 +1463,7 @@
     @HotSpotVMConstant(name = "Deoptimization::Reason_constraint") @Stable public int deoptReasonConstraint;
     @HotSpotVMConstant(name = "Deoptimization::Reason_loop_limit_check") @Stable public int deoptReasonLoopLimitCheck;
     @HotSpotVMConstant(name = "Deoptimization::Reason_aliasing") @Stable public int deoptReasonAliasing;
+    @HotSpotVMConstant(name = "Deoptimization::Reason_transfer_to_interpreter") @Stable public int deoptReasonTransferToInterpreter;
     @HotSpotVMConstant(name = "Deoptimization::Reason_LIMIT") @Stable public int deoptReasonOSROffset;
 
     @HotSpotVMConstant(name = "Deoptimization::Action_none") @Stable public int deoptActionNone;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,6 +32,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -342,7 +343,7 @@
         if (Options.TimedDynamicCounters.getValue() > 0) {
             Thread thread = new Thread() {
                 long lastTime = System.nanoTime();
-                PrintStream out = System.out;
+                PrintStream out = TTY.cachedOut;
 
                 @Override
                 public void run() {
@@ -369,7 +370,7 @@
 
     public static void shutdown(CompilerToVM compilerToVM, long compilerStartTime) {
         if (Options.GenericDynamicCounters.getValue()) {
-            dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters(), 100);
+            dump(TTY.cachedOut, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters(), 100);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Jul 30 10:39:39 2014 -0700
@@ -40,12 +40,12 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
@@ -202,7 +202,7 @@
                                     StampFactory.forKind(wordKind), BarrierType.NONE));
 
                     loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
-                                    CallingConvention.Type.JavaCall));
+                                    CallingConvention.Type.JavaCall, callTarget.invokeKind()));
 
                     graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
                     graph.addAfterFixed(metaspaceMethod, compiledEntry);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Wed Jul 30 10:39:39 2014 -0700
@@ -230,6 +230,8 @@
                 return config.deoptReasonLoopLimitCheck;
             case Aliasing:
                 return config.deoptReasonAliasing;
+            case TransferToInterpreter:
+                return config.deoptReasonTransferToInterpreter;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -282,6 +284,9 @@
         if (reason == config.deoptReasonAliasing) {
             return DeoptimizationReason.Aliasing;
         }
+        if (reason == config.deoptReasonTransferToInterpreter) {
+            return DeoptimizationReason.TransferToInterpreter;
+        }
         throw GraalInternalError.shouldNotReachHere(Integer.toHexString(reason));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Wed Jul 30 10:39:39 2014 -0700
@@ -488,11 +488,24 @@
             long totalCount = 0;
             int entries = 0;
 
-            for (int i = 0; i < typeProfileWidth; i++) {
+            outer: for (int i = 0; i < typeProfileWidth; i++) {
                 long receiverKlass = data.readWord(position, getTypeOffset(i));
                 if (receiverKlass != 0) {
-                    types[entries] = HotSpotResolvedObjectType.fromMetaspaceKlass(receiverKlass);
+                    ResolvedJavaType klass = HotSpotResolvedObjectType.fromMetaspaceKlass(receiverKlass);
                     long count = data.readUnsignedInt(position, getTypeCountOffset(i));
+                    /*
+                     * Because of races in the profile collection machinery it's possible for a
+                     * class to appear multiple times so merge them to make the profile look
+                     * rational.
+                     */
+                    for (int j = 0; j < entries; j++) {
+                        if (types[j].equals(klass)) {
+                            totalCount += count;
+                            counts[j] += count;
+                            continue outer;
+                        }
+                    }
+                    types[entries] = klass;
                     totalCount += count;
                     counts[entries] = count;
                     entries++;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Wed Jul 30 10:39:39 2014 -0700
@@ -612,21 +612,26 @@
     public int vtableEntryOffset(ResolvedJavaType resolved) {
         guarantee(isInVirtualMethodTable(resolved), "%s does not have a vtable entry", this);
         HotSpotVMConfig config = runtime().getConfig();
-        final int vtableIndex = getVtableIndex(resolved);
+        final int vtableIndex = getVtableIndex((HotSpotResolvedObjectType) resolved);
         return config.instanceKlassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
     }
 
     @Override
     public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
-        return getVtableIndex(resolved) >= 0;
+        if (resolved instanceof HotSpotResolvedObjectType) {
+            HotSpotResolvedObjectType hotspotResolved = (HotSpotResolvedObjectType) resolved;
+            int vtableIndex = getVtableIndex(hotspotResolved);
+            return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength();
+        }
+        return false;
     }
 
-    private int getVtableIndex(ResolvedJavaType resolved) {
+    private int getVtableIndex(HotSpotResolvedObjectType resolved) {
         if (!holder.isLinked()) {
             return runtime().getConfig().invalidVtableIndex;
         }
         if (holder.isInterface()) {
-            if (resolved.isArray() || resolved.isInterface()) {
+            if (resolved.isInterface()) {
                 return runtime().getConfig().invalidVtableIndex;
             }
             return getVtableIndexForInterface(resolved);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Wed Jul 30 10:39:39 2014 -0700
@@ -436,6 +436,17 @@
         return method;
     }
 
+    public int getVtableLength() {
+        HotSpotVMConfig config = runtime().getConfig();
+        if (isInterface() || isArray()) {
+            /* Everything has the core vtable of java.lang.Object */
+            return config.baseVtableLength;
+        }
+        int result = unsafe.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize);
+        assert result >= config.baseVtableLength : unsafe.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) + " " + config.vtableEntrySize;
+        return result;
+    }
+
     /**
      * Gets the mask used to filter out HotSpot internal flags for fields when a {@link Field}
      * object is created. This is the value of {@code JVM_RECOGNIZED_FIELD_MODIFIERS} in
@@ -712,13 +723,13 @@
     }
 
     /**
-     * Determines if this type is resolved in the context of a given accessing class. This is a
-     * conservative check based on this type's class loader being identical to
-     * {@code accessingClass}'s loader. This type may still be the correct resolved type in the
-     * context of {@code accessingClass} if its loader is an ancestor of {@code accessingClass}'s
-     * loader.
+     * Performs a fast-path check that this type is resolved in the context of a given accessing
+     * class. A negative result does not mean this type is not resolved with respect to
+     * {@code accessingClass}. That can only be determined by
+     * {@linkplain HotSpotGraalRuntime#lookupType(String, HotSpotResolvedObjectType, boolean)
+     * re-resolving} the type.
      */
-    public boolean isResolvedWithRespectTo(ResolvedJavaType accessingClass) {
+    public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) {
         assert accessingClass != null;
         ResolvedJavaType elementType = getElementalType();
         if (elementType.isPrimitive()) {
@@ -738,7 +749,7 @@
 
     @Override
     public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
-        if (isResolvedWithRespectTo(requireNonNull(accessingClass))) {
+        if (isDefinitelyResolvedWithRespectTo(requireNonNull(accessingClass))) {
             return this;
         }
         HotSpotResolvedObjectType accessingType = (HotSpotResolvedObjectType) accessingClass;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Wed Jul 30 10:39:39 2014 -0700
@@ -134,7 +134,7 @@
         }
 
         if (type instanceof HotSpotResolvedObjectType) {
-            return ((HotSpotResolvedObjectType) type).isResolvedWithRespectTo(accessingClass);
+            return ((HotSpotResolvedObjectType) type).isDefinitelyResolvedWithRespectTo(accessingClass);
         }
         return true;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -56,7 +56,7 @@
             ParameterNode arg0 = g.unique(new ParameterNode(0, StampFactory.forKind(Kind.Object)));
             ParameterNode arg1 = g.unique(new ParameterNode(1, StampFactory.forKind(Kind.Object)));
             ParameterNode arg2 = g.unique(new ParameterNode(2, StampFactory.forKind(Kind.Object)));
-            FrameState frameState = g.add(new FrameState(method, 0, Arrays.asList(new ValueNode[]{arg0, arg1, arg2}), 3, 0, false, false, new ArrayList<MonitorIdNode>(),
+            FrameState frameState = g.add(new FrameState(null, method, 0, Arrays.asList(new ValueNode[]{arg0, arg1, arg2}), 3, 0, false, false, new ArrayList<MonitorIdNode>(),
                             new ArrayList<EscapeObjectState>()));
             g.start().setStateAfter(frameState);
             List<ValueNode> parameters = new ArrayList<>();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -56,6 +56,11 @@
         this.encoding = encoding;
     }
 
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(mkStamp(op, getValue().stamp(), encoding));
+    }
+
     public static CompressionNode compress(ValueNode input, CompressEncoding encoding) {
         return input.graph().unique(new CompressionNode(CompressionOp.Compress, input, encoding));
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -28,18 +28,9 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 public class HotSpotDirectCallTargetNode extends DirectCallTargetNode {
-
-    private final InvokeKind invokeKind;
-
     public HotSpotDirectCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, Type callType, InvokeKind invokeKind) {
-        super(arguments, returnStamp, signature, target, callType);
-        this.invokeKind = invokeKind;
-    }
-
-    public InvokeKind invokeKind() {
-        return invokeKind;
+        super(arguments, returnStamp, signature, target, callType, invokeKind);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -34,8 +34,8 @@
     @Input private ValueNode metaspaceMethod;
 
     public HotSpotIndirectCallTargetNode(ValueNode metaspaceMethod, ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target,
-                    Type callType) {
-        super(computedAddress, arguments, returnStamp, signature, target, callType);
+                    Type callType, InvokeKind invokeKind) {
+        super(computedAddress, arguments, returnStamp, signature, target, callType, invokeKind);
         this.metaspaceMethod = metaspaceMethod;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -35,8 +35,8 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Jul 30 10:39:39 2014 -0700
@@ -40,10 +40,10 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 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.options.*;
--- a/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConfigProcessor.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConfigProcessor.java	Wed Jul 30 10:39:39 2014 -0700
@@ -26,6 +26,7 @@
 import java.lang.annotation.*;
 import java.util.*;
 import java.util.Map.Entry;
+import java.util.function.*;
 
 import javax.annotation.processing.*;
 import javax.lang.model.*;
@@ -142,7 +143,6 @@
         "void VMStructs::initHotSpotVMConfig(oop vmconfig_oop) {",
         "  InstanceKlass* vmconfig_klass = InstanceKlass::cast(vmconfig_oop->klass());",
         "",
-        "  for (JavaFieldStream fs(vmconfig_klass); !fs.done(); fs.next()) {",
     };
     //@formatter:on
 
@@ -158,7 +158,29 @@
                 out.println(line);
             }
 
-            out.println();
+            Map<String, Integer> expectedValues = new HashMap<>();
+            for (VMConfigField value : annotations.values()) {
+                if (!value.optional) {
+                    String key = value.define != null ? value.define : "";
+                    if (expectedValues.get(key) == null) {
+                        expectedValues.put(key, 1);
+                    } else {
+                        expectedValues.put(key, expectedValues.get(key) + 1);
+                    }
+                }
+            }
+
+            out.printf("  int expected = %s;%n", expectedValues.get(""));
+            for (Entry<String, Integer> entry : expectedValues.entrySet()) {
+                if (entry.getKey().equals("")) {
+                    continue;
+                }
+                out.printf("#if %s%n", entry.getKey());
+                out.printf("  expected += %s;%n", entry.getValue());
+                out.printf("#endif%n");
+            }
+            out.println("  int assigned = 0;");
+            out.println("  for (JavaFieldStream fs(vmconfig_klass); !fs.done(); fs.next()) {");
 
             Set<String> fieldTypes = new HashSet<>();
             for (VMConfigField key : annotations.values()) {
@@ -194,6 +216,7 @@
                 out.println("    } // if");
             }
             out.println("  } // for");
+            out.println("  guarantee(assigned == expected, \"Didn't find all fields during init of HotSpotVMConfig.  Maybe recompile?\");");
             out.println("}");
         }
     }
@@ -215,21 +238,84 @@
         }
     }
 
-    class VMConfigField {
+    static class VMConfigField {
+        final String setter;
+        final String define;
+        private boolean optional;
         final VariableElement field;
-        final Annotation annotation;
+
+        public VMConfigField(VariableElement field, HotSpotVMField value) {
+            this.field = field;
+            define = archDefines(value.archs());
+            String type = field.asType().toString();
+            String name = value.name();
+            int i = name.lastIndexOf("::");
+            switch (value.get()) {
+                case OFFSET:
+                    setter = String.format("set_%s(\"%s\", offset_of(%s, %s));", type, field.getSimpleName(), name.substring(0, i), name.substring(i + 2));
+                    break;
+                case ADDRESS:
+                    setter = String.format("set_address(\"%s\", &%s);", field.getSimpleName(), name);
+                    break;
+                case VALUE:
+                    setter = String.format("set_%s(\"%s\", (%s) (intptr_t) %s);", type, field.getSimpleName(), type, name);
+                    break;
+                default:
+                    throw new GraalInternalError("unexpected type: " + value.get());
+            }
+        }
+
+        public VMConfigField(VariableElement field, HotSpotVMType value) {
+            this.field = field;
+            define = null; // ((HotSpotVMType) annotation).archs();
+            String type = field.asType().toString();
+            setter = String.format("set_%s(\"%s\", sizeof(%s));", type, field.getSimpleName(), value.name());
+        }
 
-        public VMConfigField(VariableElement field, Annotation value) {
-            super();
+        public VMConfigField(VariableElement field, HotSpotVMValue value) {
             this.field = field;
-            this.annotation = value;
+            String[] defines = value.defines();
+            int length = defines.length;
+            if (length != 0) {
+                for (int i = 0; i < length; i++) {
+                    defines[i] = "defined(" + defines[i] + ")";
+                }
+                define = String.join(" || ", defines);
+            } else {
+                define = null; // ((HotSpotVMValue) annotation).archs();
+            }
+            String type = field.asType().toString();
+            if (value.get() == HotSpotVMValue.Type.ADDRESS) {
+                setter = String.format("set_address(\"%s\", %s);", field.getSimpleName(), value.expression());
+            } else {
+                setter = String.format("set_%s(\"%s\", %s);", type, field.getSimpleName(), value.expression());
+            }
+        }
+
+        public VMConfigField(VariableElement field, HotSpotVMConstant value) {
+            this.field = field;
+            define = archDefines(value.archs());
+            String type = field.asType().toString();
+            setter = String.format("set_%s(\"%s\", %s);", type, field.getSimpleName(), value.name());
+        }
+
+        public VMConfigField(VariableElement field, HotSpotVMFlag value) {
+            this.field = field;
+            define = archDefines(value.archs());
+            optional = value.optional();
+            String type = field.asType().toString();
+            if (value.optional()) {
+                setter = String.format("set_optional_%s_flag(\"%s\",  \"%s\");", type, field.getSimpleName(), value.name());
+            } else {
+                setter = String.format("set_%s(\"%s\", %s);", type, field.getSimpleName(), value.name());
+            }
         }
 
         public String getType() {
             return field.asType().toString();
         }
 
-        private String archDefine(String arch) {
+        private static String archDefine(String arch) {
             switch (arch) {
                 case "amd64":
                     return "defined(AMD64)";
@@ -242,8 +328,8 @@
             }
         }
 
-        private String archDefines(String[] archs) {
-            if (archs.length == 0) {
+        private static String archDefines(String[] archs) {
+            if (archs == null || archs.length == 0) {
                 return null;
             }
             if (archs.length == 1) {
@@ -254,102 +340,16 @@
             for (String arch : archs) {
                 defs[i++] = archDefine(arch);
             }
-            return String.join(" ||", defs);
+            return String.join(" || ", defs);
         }
 
         public void emit(PrintWriter out) {
-            if (annotation instanceof HotSpotVMField) {
-                emitField(out, (HotSpotVMField) annotation);
-            } else if (annotation instanceof HotSpotVMType) {
-                emitType(out, (HotSpotVMType) annotation);
-            } else if (annotation instanceof HotSpotVMFlag) {
-                emitFlag(out, (HotSpotVMFlag) annotation);
-            } else if (annotation instanceof HotSpotVMConstant) {
-                emitConstant(out, (HotSpotVMConstant) annotation);
-            } else if (annotation instanceof HotSpotVMValue) {
-                emitValue(out, (HotSpotVMValue) annotation);
-            } else {
-                throw new InternalError(annotation.toString());
-            }
-
-        }
-
-        private void emitField(PrintWriter out, HotSpotVMField value) {
-            String type = field.asType().toString();
-            String define = archDefines(value.archs());
             if (define != null) {
                 out.printf("#if %s\n", define);
             }
-
-            String name = value.name();
-            int i = name.lastIndexOf("::");
-            switch (value.get()) {
-                case OFFSET:
-                    out.printf("            set_%s(\"%s\", offset_of(%s, %s));\n", type, field.getSimpleName(), name.substring(0, i), name.substring(i + 2));
-                    break;
-                case ADDRESS:
-                    out.printf("            set_address(\"%s\", &%s);\n", field.getSimpleName(), name);
-                    break;
-                case VALUE:
-                    out.printf("            set_%s(\"%s\", (%s) (intptr_t) %s);\n", type, field.getSimpleName(), type, name);
-                    break;
-            }
-            if (define != null) {
-                out.printf("#endif\n");
-            }
-        }
-
-        private void emitType(PrintWriter out, HotSpotVMType value) {
-            String type = field.asType().toString();
-            out.printf("            set_%s(\"%s\", sizeof(%s));\n", type, field.getSimpleName(), value.name());
-        }
-
-        private void emitValue(PrintWriter out, HotSpotVMValue value) {
-            String type = field.asType().toString();
-            int length = value.defines().length;
-            if (length != 0) {
-                out.printf("#if ");
-                for (int i = 0; i < length; i++) {
-                    out.printf("defined(%s)", value.defines()[i]);
-                    if (i + 1 < length) {
-                        out.printf(" || ");
-                    }
-                }
-                out.println();
-            }
-            if (value.get() == HotSpotVMValue.Type.ADDRESS) {
-                out.printf("            set_address(\"%s\", %s);\n", field.getSimpleName(), value.expression());
-            } else {
-                out.printf("            set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.expression());
-            }
-            if (length != 0) {
-                out.println("#endif");
-            }
-        }
-
-        private void emitConstant(PrintWriter out, HotSpotVMConstant value) {
-            String define = archDefines(value.archs());
-            if (define != null) {
-                out.printf("#if %s\n", define);
-            }
-            String type = field.asType().toString();
-            out.printf("            set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.name());
-            if (define != null) {
-                out.printf("#endif\n");
-            }
-        }
-
-        private void emitFlag(PrintWriter out, HotSpotVMFlag value) {
-            String type = field.asType().toString();
-
-            String define = archDefines(value.archs());
-            if (define != null) {
-                out.printf("#if %s\n", define);
-            }
-            if (value.optional()) {
-                out.printf("            set_optional_%s_flag(\"%s\",  \"%s\");\n", type, field.getSimpleName(), value.name());
-            } else {
-                out.printf("            set_%s(\"%s\", %s);\n", type, field.getSimpleName(), value.name());
+            out.printf("            %s%n", setter);
+            if (!optional) {
+                out.printf("            assigned++;%n");
             }
             if (define != null) {
                 out.printf("#endif\n");
@@ -358,7 +358,9 @@
 
     }
 
-    private void collectAnnotations(RoundEnvironment roundEnv, Map<String, VMConfigField> annotationMap, Class<? extends Annotation> annotationClass) {
+    @SuppressWarnings("unchecked")
+    private <T extends Annotation> void collectAnnotations(RoundEnvironment roundEnv, Map<String, VMConfigField> annotationMap, Class<T> annotationClass,
+                    BiFunction<VariableElement, T, VMConfigField> builder) {
         for (Element element : roundEnv.getElementsAnnotatedWith(annotationClass)) {
             Annotation constant = element.getAnnotation(annotationClass);
             if (element.getKind() != ElementKind.FIELD) {
@@ -377,7 +379,7 @@
                     errorMessage(element, "Multiple types encountered.  Only HotSpotVMConfig is supported");
                 }
             }
-            annotationMap.put(element.getSimpleName().toString(), new VMConfigField((VariableElement) element, constant));
+            annotationMap.put(element.getSimpleName().toString(), builder.apply((VariableElement) element, (T) constant));
         }
     }
 
@@ -399,11 +401,11 @@
 
             // First collect all the annotations.
             Map<String, VMConfigField> annotationMap = new HashMap<>();
-            collectAnnotations(roundEnv, annotationMap, HotSpotVMConstant.class);
-            collectAnnotations(roundEnv, annotationMap, HotSpotVMFlag.class);
-            collectAnnotations(roundEnv, annotationMap, HotSpotVMField.class);
-            collectAnnotations(roundEnv, annotationMap, HotSpotVMType.class);
-            collectAnnotations(roundEnv, annotationMap, HotSpotVMValue.class);
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMConstant.class, (e, v) -> new VMConfigField(e, v));
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMFlag.class, (e, v) -> new VMConfigField(e, v));
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMField.class, (e, v) -> new VMConfigField(e, v));
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMType.class, (e, v) -> new VMConfigField(e, v));
+            collectAnnotations(roundEnv, annotationMap, HotSpotVMValue.class, (e, v) -> new VMConfigField(e, v));
 
             if (annotationMap.isEmpty()) {
                 return true;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java	Wed Jul 30 10:39:39 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.java;
 
+import static com.oracle.graal.nodes.cfg.ControlFlowGraph.*;
+
 import java.util.*;
 import java.util.stream.*;
 
@@ -30,7 +32,6 @@
 
 public class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure<Double> {
 
-    private static final double EPSILON = Double.MIN_NORMAL;
     private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure();
 
     private ComputeLoopFrequenciesClosure() {
@@ -62,8 +63,8 @@
 
         double exitProbability = exitStates.values().stream().mapToDouble(d -> d).sum();
         assert exitProbability <= 1D && exitProbability >= 0D;
-        if (exitProbability < EPSILON) {
-            exitProbability = EPSILON;
+        if (exitProbability < MIN_PROBABILITY) {
+            exitProbability = MIN_PROBABILITY;
         }
         double loopFrequency = 1D / exitProbability;
         loop.setLoopFrequency(loopFrequency);
@@ -75,14 +76,14 @@
     }
 
     /**
-     * Multiplies a and b and saturates the result to 1/{@link Double#MIN_NORMAL}.
+     * Multiplies a and b and saturates the result to 1/{@link #MIN_PROBABILITY}.
      *
-     * @return a times b saturated to 1/{@link Double#MIN_NORMAL}
+     * @return a times b saturated to 1/{@link #MIN_PROBABILITY}
      */
     public static double multiplySaturate(double a, double b) {
         double r = a * b;
-        if (r > 1 / Double.MIN_NORMAL) {
-            return 1 / Double.MIN_NORMAL;
+        if (r > 1 / MIN_PROBABILITY) {
+            return 1 / MIN_PROBABILITY;
         }
         return r;
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Wed Jul 30 10:39:39 2014 -0700
@@ -22,34 +22,57 @@
  */
 package com.oracle.graal.java;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 
 public class GraphBuilderConfiguration {
+    private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
 
     private final boolean eagerResolving;
     private final boolean omitAllExceptionEdges;
-    private ResolvedJavaType[] skippedExceptionTypes;
+    private final ResolvedJavaType[] skippedExceptionTypes;
+    private final DebugInfoMode debugInfoMode;
 
-    /**
-     * When the graph builder is in eager infopoint mode, it inserts {@link InfopointNode}s in
-     * places where no safepoints would be inserted: inlining boundaries, and line number switches.
-     * This is relevant when code is to be generated for native, machine-code level debugging.
-     */
-    private boolean eagerInfopointMode;
+    public static enum DebugInfoMode {
+        SafePointsOnly,
+        /**
+         * This mode inserts {@link FullInfopointNode}s in places where no safepoints would be
+         * inserted: inlining boundaries, and line number switches.
+         * <p>
+         * In this mode the infopoint only have a location (method and bytecode index) and no
+         * values.
+         * <p>
+         * This is useful to have better program counter to bci mapping and has no influence on the
+         * generated code. However it can increase the amount of metadata and does not allow access
+         * to accessing values at runtime.
+         */
+        Simple,
+        /**
+         * In this mode, infopoints are generated in the same locations as in {@link #Simple} mode
+         * but the infopoints have access to the runtime values.
+         * <p>
+         * This is relevant when code is to be generated for native, machine-code level debugging
+         * but can have a limit the amount of optimisation applied to the code.
+         */
+        Full,
+    }
 
-    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, boolean eagerInfopointMode) {
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes) {
         this.eagerResolving = eagerResolving;
         this.omitAllExceptionEdges = omitAllExceptionEdges;
-        this.eagerInfopointMode = eagerInfopointMode;
-    }
-
-    public void setSkippedExceptionTypes(ResolvedJavaType[] skippedExceptionTypes) {
+        this.debugInfoMode = debugInfoMode;
         this.skippedExceptionTypes = skippedExceptionTypes;
     }
 
-    public void setEagerInfopointMode(boolean eagerInfopointMode) {
-        this.eagerInfopointMode = eagerInfopointMode;
+    public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes);
+    }
+
+    public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
+        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes);
     }
 
     public ResolvedJavaType[] getSkippedExceptionTypes() {
@@ -64,28 +87,28 @@
         return omitAllExceptionEdges;
     }
 
-    public boolean eagerInfopointMode() {
-        return eagerInfopointMode;
+    public boolean insertNonSafepointDebugInfo() {
+        return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal();
+    }
+
+    public boolean insertFullDebugInfo() {
+        return debugInfoMode.ordinal() >= DebugInfoMode.Full.ordinal();
     }
 
     public static GraphBuilderConfiguration getDefault() {
-        return new GraphBuilderConfiguration(false, false, false);
-    }
-
-    public static GraphBuilderConfiguration getInfopointDefault() {
-        return new GraphBuilderConfiguration(false, false, true);
+        return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY);
     }
 
     public static GraphBuilderConfiguration getEagerDefault() {
-        return new GraphBuilderConfiguration(true, false, false);
+        return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY);
     }
 
     public static GraphBuilderConfiguration getSnippetDefault() {
-        return new GraphBuilderConfiguration(true, true, false);
+        return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY);
     }
 
-    public static GraphBuilderConfiguration getEagerInfopointDefault() {
-        return new GraphBuilderConfiguration(true, false, true);
+    public static GraphBuilderConfiguration getFullDebugDefault() {
+        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY);
     }
 
     /**
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -44,10 +44,10 @@
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
@@ -69,6 +69,10 @@
         new Instance(context.getMetaAccess(), graphBuilderConfig, context.getOptimisticOptimizations()).run(graph);
     }
 
+    public GraphBuilderConfiguration getGraphBuilderConfig() {
+        return graphBuilderConfig;
+    }
+
     public static class Instance extends Phase {
 
         private LineNumberTable lnt;
@@ -139,7 +143,7 @@
         @Override
         protected void run(StructuredGraph graph) {
             ResolvedJavaMethod method = graph.method();
-            if (graphBuilderConfig.eagerInfopointMode()) {
+            if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
                 lnt = method.getLineNumberTable();
                 previousLineNumber = -1;
             }
@@ -232,11 +236,12 @@
                         lastInstr = genMonitorEnter(methodSynchronizedObject);
                     }
                     frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
-                    ((StateSplit) lastInstr).setStateAfter(frameState.create(0));
+                    assert bci() == 0;
+                    ((StateSplit) lastInstr).setStateAfter(frameState.create(bci()));
                     finishPrepare(lastInstr);
 
-                    if (graphBuilderConfig.eagerInfopointMode()) {
-                        InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0)));
+                    if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
+                        InfopointNode ipn = currentGraph.add(createInfoPointNode(InfopointReason.METHOD_START));
                         lastInstr.setNext(ipn);
                         lastInstr = ipn;
                     }
@@ -661,7 +666,7 @@
             protected void emitBoundsCheck(ValueNode index, ValueNode length) {
                 BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode(this));
                 BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode(this));
-                append(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.99));
+                append(new IfNode(currentGraph.unique(new IntegerBelowNode(index, length)), trueSucc, falseSucc, 0.99));
                 lastInstr = trueSucc;
 
                 BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
@@ -835,8 +840,8 @@
             protected void genReturn(ValueNode x) {
                 frameState.setRethrowException(false);
                 frameState.clearStack();
-                if (graphBuilderConfig.eagerInfopointMode()) {
-                    append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci())));
+                if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
+                    append(createInfoPointNode(InfopointReason.METHOD_END));
                 }
 
                 synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x);
@@ -1290,10 +1295,10 @@
                 BytecodesParsed.add(block.endBci - bci);
 
                 while (bci < endBCI) {
-                    if (graphBuilderConfig.eagerInfopointMode() && lnt != null) {
+                    if (graphBuilderConfig.insertNonSafepointDebugInfo() && lnt != null) {
                         currentLineNumber = lnt.getLineNumber(bci);
                         if (currentLineNumber != previousLineNumber) {
-                            append(new InfopointNode(InfopointReason.LINE_NUMBER, frameState.create(bci)));
+                            append(createInfoPointNode(InfopointReason.LINE_NUMBER));
                             previousLineNumber = currentLineNumber;
                         }
                     }
@@ -1356,6 +1361,14 @@
                 return instr;
             }
 
+            private InfopointNode createInfoPointNode(InfopointReason reason) {
+                if (graphBuilderConfig.insertFullDebugInfo()) {
+                    return new FullInfopointNode(reason, frameState.create(bci()));
+                } else {
+                    return new SimpleInfopointNode(reason, new BytecodePosition(null, method, bci()));
+                }
+            }
+
             private void traceState() {
                 if (traceLevel >= TRACELEVEL_STATE && Debug.isLogEnabled()) {
                     Debug.log(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method));
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCTestOp.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCTestOp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -29,8 +29,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw;
-import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.asm.*;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FullInfopointOp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Emits an infopoint (only mark the position).
+ */
+@Opcode("INFOPOINT")
+public class FullInfopointOp extends LIRInstruction {
+
+    @State protected LIRFrameState state;
+
+    private final InfopointReason reason;
+
+    public FullInfopointOp(LIRFrameState state, InfopointReason reason) {
+        this.state = state;
+        this.reason = reason;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        crb.recordInfopoint(crb.asm.position(), state, reason);
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java	Wed Jul 30 09:36:32 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.lir.asm.*;
-
-/**
- * Emits an infopoint (only mark the position).
- */
-@Opcode("INFOPOINT")
-public class InfopointOp extends LIRInstruction {
-
-    @State protected LIRFrameState state;
-
-    private final InfopointReason reason;
-
-    public InfopointOp(LIRFrameState state, InfopointReason reason) {
-        this.state = state;
-        this.reason = reason;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb) {
-        crb.recordInfopoint(crb.asm.position(), state, reason);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SimpleInfopointOp.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("SIMPLE_INFOPOINT")
+public class SimpleInfopointOp extends LIRInstruction {
+    private final InfopointReason reason;
+    private final BytecodePosition position;
+
+    public SimpleInfopointOp(InfopointReason reason, BytecodePosition position) {
+        this.reason = reason;
+        this.position = position;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb) {
+        crb.recordInfopoint(crb.asm.position(), new DebugInfo(position, null), reason);
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -146,6 +146,10 @@
     public void recordInfopoint(int pos, LIRFrameState info, InfopointReason reason) {
         // infopoints always need debug info
         DebugInfo debugInfo = info.debugInfo();
+        recordInfopoint(pos, debugInfo, reason);
+    }
+
+    public void recordInfopoint(int pos, DebugInfo debugInfo, InfopointReason reason) {
         compilationResult.recordInfopoint(pos, debugInfo, reason);
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Wed Jul 30 10:39:39 2014 -0700
@@ -51,7 +51,7 @@
         AbstractEndNode forwardEnd = loopBegin.forwardEnd();
         for (PhiNode phi : loopBegin.phis()) {
             ValueNode backValue = phi.singleBackValue();
-            if (backValue == PhiNode.NO_VALUE) {
+            if (backValue == PhiNode.MULTIPLE_VALUES) {
                 continue;
             }
             ValueNode stride = addSub(backValue, phi);
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Wed Jul 30 10:39:39 2014 -0700
@@ -173,7 +173,7 @@
             }
             LogicNode ifTest = ifNode.condition();
             if (!(ifTest instanceof IntegerLessThanNode)) {
-                if (ifTest instanceof IntegerBelowThanNode) {
+                if (ifTest instanceof IntegerBelowNode) {
                     Debug.log("Ignored potential Counted loop at %s with |<|", loopBegin);
                 }
                 return false;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Jul 30 10:39:39 2014 -0700
@@ -332,7 +332,7 @@
                  * VirtualState nodes contained in the old exit's state may be shared by other
                  * dominated VirtualStates. Those dominated virtual states need to see the
                  * proxy->phi update that are applied below.
-                 *
+                 * 
                  * We now update the original fragment's nodes accordingly:
                  */
                 originalExitState.applyToVirtual(node -> original.nodes.clearAndGrow(node));
@@ -345,7 +345,7 @@
             }
 
             boolean newEarlyExitIsLoopExit = newEarlyExit instanceof LoopExitNode;
-            for (final ProxyNode vpn : loopEarlyExit.proxies().snapshot()) {
+            for (ProxyNode vpn : loopEarlyExit.proxies().snapshot()) {
                 if (vpn.usages().isEmpty()) {
                     continue;
                 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Jul 30 10:39:39 2014 -0700
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
+import java.util.*;
 import java.util.function.*;
 
 import com.oracle.graal.debug.*;
@@ -63,25 +64,27 @@
         return loop.loopBegin().unswitches() <= LoopMaxUnswitch.getValue();
     }
 
-    public static boolean shouldUnswitch(LoopEx loop, ControlSplitNode controlSplit) {
-        Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(controlSplit).getPostdominator();
-        BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null;
+    public static boolean shouldUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
         int loopTotal = loop.size();
         int inBranchTotal = 0;
         double maxProbability = 0;
-        for (Node successor : controlSplit.successors()) {
-            BeginNode branch = (BeginNode) successor;
-            // this may count twice because of fall-through in switches
-            inBranchTotal += loop.nodesInLoopFrom(branch, postDom).count();
-            double probability = controlSplit.probability(branch);
-            if (probability > maxProbability) {
-                maxProbability = probability;
+        for (ControlSplitNode controlSplit : controlSplits) {
+            Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(controlSplit).getPostdominator();
+            BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null;
+            for (Node successor : controlSplit.successors()) {
+                BeginNode branch = (BeginNode) successor;
+                // this may count twice because of fall-through in switches
+                inBranchTotal += loop.nodesInLoopFrom(branch, postDom).count();
+                double probability = controlSplit.probability(branch);
+                if (probability > maxProbability) {
+                    maxProbability = probability;
+                }
             }
         }
         int netDiff = loopTotal - (inBranchTotal);
         double uncertainty = 1 - maxProbability;
         int maxDiff = LoopUnswitchMaxIncrease.getValue() + (int) (LoopUnswitchUncertaintyBoost.getValue() * loop.loopBegin().loopFrequency() * uncertainty);
-        Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of branches", loop, controlSplit, netDiff, maxDiff, (double) (inBranchTotal) / loopTotal * 100);
+        Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of branches", loop, controlSplits, netDiff, maxDiff, (double) (inBranchTotal) / loopTotal * 100);
         return netDiff <= maxDiff;
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Jul 30 10:39:39 2014 -0700
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
@@ -71,30 +73,53 @@
         }
     }
 
-    public static void unswitch(LoopEx loop, ControlSplitNode controlSplitNode) {
+    public static void unswitch(LoopEx loop, List<ControlSplitNode> controlSplitNodeSet) {
+        ControlSplitNode firstNode = controlSplitNodeSet.iterator().next();
         LoopFragmentWhole originalLoop = loop.whole();
+        StructuredGraph graph = firstNode.graph();
+
         // create new control split out of loop
-        ControlSplitNode newControlSplit = (ControlSplitNode) controlSplitNode.copyWithInputs();
+        ControlSplitNode newControlSplit = (ControlSplitNode) firstNode.copyWithInputs();
         originalLoop.entryPoint().replaceAtPredecessor(newControlSplit);
 
-        NodeClassIterator successors = controlSplitNode.successors().iterator();
+        /*
+         * The code below assumes that all of the control split nodes have the same successor
+         * structure, which should have been enforced by findUnswitchable.
+         */
+        NodeClassIterator successors = firstNode.successors().iterator();
         assert successors.hasNext();
         // original loop is used as first successor
         Position firstPosition = successors.nextPosition();
-        NodeClass controlSplitClass = controlSplitNode.getNodeClass();
-        controlSplitClass.set(newControlSplit, firstPosition, BeginNode.begin(originalLoop.entryPoint()));
+        NodeClass controlSplitClass = firstNode.getNodeClass();
+        BeginNode originalLoopBegin = BeginNode.begin(originalLoop.entryPoint());
+        controlSplitClass.set(newControlSplit, firstPosition, originalLoopBegin);
 
-        StructuredGraph graph = controlSplitNode.graph();
         while (successors.hasNext()) {
             Position position = successors.nextPosition();
-            // create a new loop duplicate, connect it and simplify it
+            // create a new loop duplicate and connect it.
             LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
-            controlSplitClass.set(newControlSplit, position, BeginNode.begin(duplicateLoop.entryPoint()));
-            ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
-            graph.removeSplitPropagate(duplicatedControlSplit, (BeginNode) controlSplitClass.get(duplicatedControlSplit, position));
+            BeginNode newBegin = BeginNode.begin(duplicateLoop.entryPoint());
+            controlSplitClass.set(newControlSplit, position, newBegin);
+
+            // For each cloned ControlSplitNode, simplify the proper path
+            for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
+                ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
+                if (duplicatedControlSplit.isAlive()) {
+                    BeginNode survivingSuccessor = (BeginNode) controlSplitClass.get(duplicatedControlSplit, position);
+                    survivingSuccessor.replaceAtUsages(InputType.Guard, newBegin);
+                    graph.removeSplitPropagate(duplicatedControlSplit, survivingSuccessor);
+                }
+            }
         }
         // original loop is simplified last to avoid deleting controlSplitNode too early
-        graph.removeSplitPropagate(controlSplitNode, (BeginNode) controlSplitClass.get(controlSplitNode, firstPosition));
+        for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
+            if (controlSplitNode.isAlive()) {
+                BeginNode survivingSuccessor = (BeginNode) controlSplitClass.get(controlSplitNode, firstPosition);
+                survivingSuccessor.replaceAtUsages(InputType.Guard, originalLoopBegin);
+                graph.removeSplitPropagate(controlSplitNode, survivingSuccessor);
+            }
+        }
+
         // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
     }
 
@@ -119,17 +144,36 @@
         }
     }
 
-    public static ControlSplitNode findUnswitchable(LoopEx loop) {
+    public static List<ControlSplitNode> findUnswitchable(LoopEx loop) {
+        List<ControlSplitNode> controls = null;
+        ValueNode invariantValue = null;
         for (IfNode ifNode : loop.whole().nodes().filter(IfNode.class)) {
             if (loop.isOutsideLoop(ifNode.condition())) {
-                return ifNode;
+                if (controls == null) {
+                    invariantValue = ifNode.condition();
+                    controls = new ArrayList<>();
+                    controls.add(ifNode);
+                } else if (ifNode.condition() == invariantValue) {
+                    controls.add(ifNode);
+                }
             }
         }
-        for (SwitchNode switchNode : loop.whole().nodes().filter(SwitchNode.class)) {
-            if (switchNode.successors().count() > 1 && loop.isOutsideLoop(switchNode.value())) {
-                return switchNode;
+        if (controls == null) {
+            SwitchNode firstSwitch = null;
+            for (SwitchNode switchNode : loop.whole().nodes().filter(SwitchNode.class)) {
+                if (switchNode.successors().count() > 1 && loop.isOutsideLoop(switchNode.value())) {
+                    if (controls == null) {
+                        firstSwitch = switchNode;
+                        invariantValue = switchNode.value();
+                        controls = new ArrayList<>();
+                        controls.add(switchNode);
+                    } else if (switchNode.value() == invariantValue && firstSwitch.equalKeys(switchNode)) {
+                        // Only collect switches which test the same values in the same order
+                        controls.add(switchNode);
+                    }
+                }
             }
         }
-        return null;
+        return controls;
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
+import java.util.*;
+
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.NodeClass.NodeClassIterator;
@@ -34,6 +36,7 @@
 public class LoopTransformLowPhase extends Phase {
 
     private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
+    private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
 
     @Override
     protected void run(StructuredGraph graph) {
@@ -56,16 +59,18 @@
                     final LoopsData dataUnswitch = new LoopsData(graph);
                     for (LoopEx loop : dataUnswitch.loops()) {
                         if (LoopPolicies.shouldTryUnswitch(loop)) {
-                            ControlSplitNode controlSplit = LoopTransformations.findUnswitchable(loop);
-                            if (controlSplit != null && LoopPolicies.shouldUnswitch(loop, controlSplit)) {
-                                if (Debug.isLogEnabled()) {
-                                    logUnswitch(loop, controlSplit);
+                            List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
+                            if (controlSplits != null) {
+                                UNSWITCH_CANDIDATES.increment();
+                                if (LoopPolicies.shouldUnswitch(loop, controlSplits)) {
+                                    if (Debug.isLogEnabled()) {
+                                        logUnswitch(loop, controlSplits);
+                                    }
+                                    LoopTransformations.unswitch(loop, controlSplits);
+                                    UNSWITCHED.increment();
+                                    unswitched = true;
+                                    break;
                                 }
-                                LoopTransformations.unswitch(loop, controlSplit);
-                                UNSWITCHED.increment();
-                                Debug.dump(graph, "After unswitch %s", loop);
-                                unswitched = true;
-                                break;
                             }
                         }
                     }
@@ -74,17 +79,20 @@
         }
     }
 
-    private static void logUnswitch(LoopEx loop, ControlSplitNode controlSplit) {
+    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
         StringBuilder sb = new StringBuilder("Unswitching ");
-        sb.append(loop).append(" at ").append(controlSplit).append(" [");
-        NodeClassIterator it = controlSplit.successors().iterator();
-        while (it.hasNext()) {
-            sb.append(controlSplit.probability((BeginNode) it.next()));
-            if (it.hasNext()) {
-                sb.append(", ");
+        sb.append(loop).append(" at ");
+        for (ControlSplitNode controlSplit : controlSplits) {
+            sb.append(controlSplit).append(" [");
+            NodeClassIterator it = controlSplit.successors().iterator();
+            while (it.hasNext()) {
+                sb.append(controlSplit.probability((BeginNode) it.next()));
+                if (it.hasNext()) {
+                    sb.append(", ");
+                }
             }
+            sb.append("]");
         }
-        sb.append("]");
         Debug.log("%s", sb);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -38,16 +38,6 @@
         return y;
     }
 
-    protected void setX(ValueNode x) {
-        updateUsages(this.x, x);
-        this.x = x;
-    }
-
-    protected void setY(ValueNode y) {
-        updateUsages(this.y, y);
-        this.y = y;
-    }
-
     public BinaryOpLogicNode(ValueNode x, ValueNode y) {
         assert x != null && y != null && x.getKind() == y.getKind();
         this.x = x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -24,22 +24,39 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Extension})
 public abstract class CallTargetNode extends ValueNode implements LIRLowerable {
+    public enum InvokeKind {
+        Interface,
+        Special,
+        Static,
+        Virtual;
+
+        public boolean hasReceiver() {
+            return this != Static;
+        }
+    }
 
     @Input private final NodeInputList<ValueNode> arguments;
+    private ResolvedJavaMethod targetMethod;
+    private InvokeKind invokeKind;
 
-    public CallTargetNode(ValueNode[] arguments) {
+    public CallTargetNode(ValueNode[] arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind) {
         super(StampFactory.forVoid());
+        this.targetMethod = targetMethod;
+        this.invokeKind = invokeKind;
         this.arguments = new NodeInputList<>(this, arguments);
     }
 
-    public CallTargetNode(List<ValueNode> arguments) {
+    public CallTargetNode(List<ValueNode> arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind) {
         super(StampFactory.forVoid());
+        this.targetMethod = targetMethod;
+        this.invokeKind = invokeKind;
         this.arguments = new NodeInputList<>(this, arguments);
     }
 
@@ -58,4 +75,25 @@
     public void generate(NodeLIRBuilderTool gen) {
         // nop
     }
+
+    public void setTargetMethod(ResolvedJavaMethod method) {
+        targetMethod = method;
+    }
+
+    /**
+     * Gets the target method for this invocation instruction.
+     *
+     * @return the target method
+     */
+    public ResolvedJavaMethod targetMethod() {
+        return targetMethod;
+    }
+
+    public InvokeKind invokeKind() {
+        return invokeKind;
+    }
+
+    public void setInvokeKind(InvokeKind kind) {
+        this.invokeKind = kind;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -36,6 +36,4 @@
     }
 
     public abstract double probability(BeginNode successor);
-
-    public abstract void setProbability(BeginNode successor, double value);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -30,12 +30,12 @@
 
 public class DirectCallTargetNode extends LoweredCallTargetNode {
 
-    public DirectCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType) {
-        super(arguments, returnStamp, signature, target, callType);
+    public DirectCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(arguments, returnStamp, signature, target, callType, invokeKind);
     }
 
     @Override
     public String targetName() {
-        return target().format("Direct#%h.%n");
+        return targetMethod().format("Direct#%h.%n");
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Jul 30 10:39:39 2014 -0700
@@ -86,9 +86,10 @@
      * @param monitorIds one MonitorIdNode for each locked object
      * @param virtualObjectMappings a description of the current state for every virtual object
      */
-    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall, List<MonitorIdNode> monitorIds,
-                    List<EscapeObjectState> virtualObjectMappings) {
+    public FrameState(FrameState outerFrameState, ResolvedJavaMethod method, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall,
+                    List<MonitorIdNode> monitorIds, List<EscapeObjectState> virtualObjectMappings) {
         assert stackSize >= 0;
+        this.outerFrameState = outerFrameState;
         this.method = method;
         this.bci = bci;
         this.localsSize = localsSize;
@@ -109,13 +110,13 @@
      * @param bci marker bci, needs to be &lt; 0
      */
     public FrameState(int bci) {
-        this(null, bci, Collections.<ValueNode> emptyList(), 0, 0, false, false, Collections.<MonitorIdNode> emptyList(), Collections.<EscapeObjectState> emptyList());
+        this(null, null, bci, Collections.<ValueNode> emptyList(), 0, 0, false, false, Collections.<MonitorIdNode> emptyList(), Collections.<EscapeObjectState> emptyList());
         assert bci == BytecodeFrame.BEFORE_BCI || bci == BytecodeFrame.AFTER_BCI || bci == BytecodeFrame.AFTER_EXCEPTION_BCI || bci == BytecodeFrame.UNKNOWN_BCI ||
                         bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
     }
 
     public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks, MonitorIdNode[] monitorIds, boolean rethrowException, boolean duringCall) {
-        this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Arrays.asList(monitorIds), Collections.<EscapeObjectState> emptyList());
+        this(null, method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Arrays.asList(monitorIds), Collections.<EscapeObjectState> emptyList());
     }
 
     private static List<ValueNode> createValues(ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks) {
@@ -139,6 +140,10 @@
         return values;
     }
 
+    public NodeInputList<MonitorIdNode> monitorIds() {
+        return monitorIds;
+    }
+
     public FrameState outerFrameState() {
         return outerFrameState;
     }
@@ -187,9 +192,7 @@
      * Gets a copy of this frame state.
      */
     public FrameState duplicate(int newBci) {
-        FrameState other = graph().add(new FrameState(method, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings));
-        other.setOuterFrameState(outerFrameState());
-        return other;
+        return graph().add(new FrameState(outerFrameState(), method, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings));
     }
 
     /**
@@ -213,9 +216,7 @@
         for (EscapeObjectState state : virtualObjectMappings) {
             newVirtualMappings.add(state.duplicateWithVirtualState());
         }
-        FrameState other = graph().add(new FrameState(method, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, newVirtualMappings));
-        other.setOuterFrameState(newOuterFrameState);
-        return other;
+        return graph().add(new FrameState(newOuterFrameState, method, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, newVirtualMappings));
     }
 
     /**
@@ -255,9 +256,7 @@
         int newStackSize = copy.size() - localsSize;
         copy.addAll(values.subList(localsSize + stackSize, values.size()));
 
-        FrameState other = graph().add(new FrameState(newMethod, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
-        other.setOuterFrameState(outerFrameState());
-        return other;
+        return graph().add(new FrameState(outerFrameState(), newMethod, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FullInfopointNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Nodes of this type are inserted into the graph to denote points of interest to debugging.
+ */
+public class FullInfopointNode extends InfopointNode implements LIRLowerable, NodeWithState {
+    @Input(InputType.State) private FrameState state;
+
+    public FullInfopointNode(InfopointReason reason, FrameState state) {
+        super(reason);
+        this.state = state;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.visitFullInfopointNode(this);
+    }
+
+    public FrameState getState() {
+        return state;
+    }
+
+    @Override
+    public boolean verify() {
+        return state != null && super.verify();
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,10 +32,16 @@
 @NodeInfo(nameTemplate = "GuardPhi({i#values})", allowedUsageTypes = {InputType.Guard})
 public class GuardPhiNode extends PhiNode implements GuardingNode {
 
-    @OptionalInput(InputType.Guard) final NodeInputList<ValueNode> values = new NodeInputList<>(this);
+    @OptionalInput(InputType.Guard) final NodeInputList<ValueNode> values;
 
     public GuardPhiNode(MergeNode merge) {
         super(StampFactory.forVoid(), merge);
+        this.values = new NodeInputList<>(this);
+    }
+
+    public GuardPhiNode(MergeNode merge, ValueNode[] values) {
+        super(StampFactory.forVoid(), merge);
+        this.values = new NodeInputList<>(this, values);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -121,12 +121,6 @@
     }
 
     @Override
-    public void setProbability(BeginNode successor, double value) {
-        assert successor == trueSuccessor || successor == falseSuccessor;
-        setTrueSuccessorProbability(successor == trueSuccessor ? value : 1 - value);
-    }
-
-    @Override
     public void generate(NodeLIRBuilderTool gen) {
         gen.emitIf(this);
     }
@@ -265,14 +259,14 @@
                     IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
                     BeginNode falseSucc = ifNode2.falseSuccessor();
                     BeginNode trueSucc = ifNode2.trueSuccessor();
-                    IntegerBelowThanNode below = null;
+                    IntegerBelowNode below = null;
                     /*
                      * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
                      * <positive> into an unsigned compare.
                      */
                     if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.getY().stamp()).isPositive() &&
                                     sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
-                        below = graph().unique(new IntegerBelowThanNode(lessThan2.getX(), lessThan2.getY()));
+                        below = graph().unique(new IntegerBelowNode(lessThan2.getX(), lessThan2.getY()));
                         // swap direction
                         BeginNode tmp = falseSucc;
                         falseSucc = trueSucc;
@@ -287,7 +281,7 @@
                         Constant positive = lessThan2.getX().asConstant();
                         if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getKind().getMaxValue()) {
                             ConstantNode newLimit = ConstantNode.forIntegerKind(positive.getKind(), positive.asLong() + 1, graph());
-                            below = graph().unique(new IntegerBelowThanNode(lessThan.getX(), newLimit));
+                            below = graph().unique(new IntegerBelowNode(lessThan.getX(), newLimit));
                         }
                     }
                     if (below != null) {
@@ -485,24 +479,32 @@
             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
             MergeNode merge = trueEnd.merge();
             if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
-                Iterator<PhiNode> phis = merge.phis().iterator();
-                if (!phis.hasNext()) {
+                PhiNode singlePhi = null;
+                int distinct = 0;
+                for (PhiNode phi : merge.phis()) {
+                    ValueNode trueValue = phi.valueAt(trueEnd);
+                    ValueNode falseValue = phi.valueAt(falseEnd);
+                    if (trueValue != falseValue) {
+                        distinct++;
+                        singlePhi = phi;
+                    }
+                }
+                if (distinct == 0) {
+                    /*
+                     * Multiple phis but merging same values for true and false, so simply delete
+                     * the path
+                     */
                     tool.addToWorkList(condition());
                     removeThroughFalseBranch(tool);
                     return true;
-                } else {
-                    PhiNode singlePhi = phis.next();
-                    if (!phis.hasNext()) {
-                        // one phi at the merge of an otherwise empty if construct: try to convert
-                        // into a MaterializeNode
-                        ValueNode trueValue = singlePhi.valueAt(trueEnd);
-                        ValueNode falseValue = singlePhi.valueAt(falseEnd);
-                        ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
-                        if (conditional != null) {
-                            singlePhi.setValueAt(trueEnd, conditional);
-                            removeThroughFalseBranch(tool);
-                            return true;
-                        }
+                } else if (distinct == 1) {
+                    ValueNode trueValue = singlePhi.valueAt(trueEnd);
+                    ValueNode falseValue = singlePhi.valueAt(falseEnd);
+                    ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
+                    if (conditional != null) {
+                        singlePhi.setValueAt(trueEnd, conditional);
+                        removeThroughFalseBranch(tool);
+                        return true;
                     }
                 }
             }
@@ -512,14 +514,18 @@
             ReturnNode falseEnd = (ReturnNode) falseSuccessor().next();
             ValueNode trueValue = trueEnd.result();
             ValueNode falseValue = falseEnd.result();
-            ConditionalNode conditional = null;
+            ValueNode value = null;
             if (trueValue != null) {
-                conditional = canonicalizeConditionalCascade(trueValue, falseValue);
-                if (conditional == null) {
-                    return false;
+                if (trueValue == falseValue) {
+                    value = trueValue;
+                } else {
+                    value = canonicalizeConditionalCascade(trueValue, falseValue);
+                    if (value == null) {
+                        return false;
+                    }
                 }
             }
-            ReturnNode newReturn = graph().add(new ReturnNode(conditional));
+            ReturnNode newReturn = graph().add(new ReturnNode(value));
             replaceAtPredecessor(newReturn);
             GraphUtil.killCFG(this);
             return true;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,8 +32,9 @@
 
     @Input private ValueNode computedAddress;
 
-    public IndirectCallTargetNode(ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType) {
-        super(arguments, returnStamp, signature, target, callType);
+    public IndirectCallTargetNode(ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType,
+                    InvokeKind invokeKind) {
+        super(arguments, returnStamp, signature, target, callType, invokeKind);
         this.computedAddress = computedAddress;
     }
 
@@ -43,6 +44,6 @@
 
     @Override
     public String targetName() {
-        return target().format("Indirect#%h.%n");
+        return targetMethod().format("Indirect#%h.%n");
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,35 +24,16 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.spi.*;
 
-/**
- * Nodes of this type are inserted into the graph to denote points of interest to debugging.
- */
-public class InfopointNode extends FixedWithNextNode implements LIRLowerable, NodeWithState {
+public abstract class InfopointNode extends FixedWithNextNode {
+    private final InfopointReason reason;
 
-    public final InfopointReason reason;
-    @Input(InputType.State) private FrameState state;
-
-    public InfopointNode(InfopointReason reason, FrameState state) {
+    public InfopointNode(InfopointReason reason) {
         super(StampFactory.forVoid());
         this.reason = reason;
-        this.state = state;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool generator) {
-        generator.visitInfopointNode(this);
     }
 
-    public FrameState getState() {
-        return state;
+    public InfopointReason getReason() {
+        return reason;
     }
-
-    @Override
-    public boolean verify() {
-        return state != null && super.verify();
-    }
-
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Wed Jul 30 10:39:39 2014 -0700
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.CallTargetNode.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -89,6 +90,7 @@
     }
 
     default ValueNode getReceiver() {
+        assert getInvokeKind().hasReceiver();
         return callTarget().arguments().get(0);
     }
 
@@ -99,4 +101,8 @@
         }
         return receiverType;
     }
+
+    default InvokeKind getInvokeKind() {
+        return callTarget().invokeKind();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -201,12 +201,6 @@
     }
 
     @Override
-    public void setProbability(BeginNode successor, double value) {
-        assert successor == next || successor == exceptionEdge;
-        this.exceptionProbability = successor == next ? 1 - value : value;
-    }
-
-    @Override
     public boolean canDeoptimize() {
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoweredCallTargetNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoweredCallTargetNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,14 +32,12 @@
 
     private final Stamp returnStamp;
     private final JavaType[] signature;
-    private final ResolvedJavaMethod target;
     private final CallingConvention.Type callType;
 
-    public LoweredCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType) {
-        super(arguments);
+    public LoweredCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(arguments, target, invokeKind);
         this.returnStamp = returnStamp;
         this.signature = signature;
-        this.target = target;
         this.callType = callType;
     }
 
@@ -52,10 +50,6 @@
         return signature;
     }
 
-    public ResolvedJavaMethod target() {
-        return target;
-    }
-
     public CallingConvention.Type callType() {
         return callType;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -33,12 +33,19 @@
 @NodeInfo(nameTemplate = "MemoryPhi({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory})
 public class MemoryPhiNode extends PhiNode implements MemoryNode {
 
-    @Input(InputType.Memory) final NodeInputList<ValueNode> values = new NodeInputList<>(this);
+    @Input(InputType.Memory) final NodeInputList<ValueNode> values;
     private final LocationIdentity locationIdentity;
 
     public MemoryPhiNode(MergeNode merge, LocationIdentity locationIdentity) {
         super(StampFactory.forVoid(), merge);
         this.locationIdentity = locationIdentity;
+        this.values = new NodeInputList<>(this);
+    }
+
+    public MemoryPhiNode(MergeNode merge, LocationIdentity locationIdentity, ValueNode[] values) {
+        super(StampFactory.forVoid(), merge);
+        this.locationIdentity = locationIdentity;
+        this.values = new NodeInputList<>(this, values);
     }
 
     public LocationIdentity getLocationIdentity() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -137,10 +137,15 @@
         values().remove(index);
     }
 
-    public static final ValueNode NO_VALUE = new ValueNode(null) {
+    public static final ValueNode MULTIPLE_VALUES = new ValueNode(null) {
         // empty dummy class
     };
 
+    /**
+     * If all inputs are the same value, this value is returned, otherwise {@link #MULTIPLE_VALUES}.
+     * Note that {@code null} is a valid return value, since {@link GuardPhiNode}s can have
+     * {@code null} inputs.
+     */
     public ValueNode singleValue() {
         Iterator<ValueNode> iterator = values().iterator();
         ValueNode singleValue = iterator.next();
@@ -148,13 +153,18 @@
             ValueNode value = iterator.next();
             if (value != this) {
                 if (value != singleValue) {
-                    return NO_VALUE;
+                    return MULTIPLE_VALUES;
                 }
             }
         }
         return singleValue;
     }
 
+    /**
+     * If all inputs (but the first one) are the same value, this value is returned, otherwise
+     * {@link #MULTIPLE_VALUES}. Note that {@code null} is a valid return value, since
+     * {@link GuardPhiNode}s can have {@code null} inputs.
+     */
     public ValueNode singleBackValue() {
         assert merge() instanceof LoopBeginNode;
         Iterator<ValueNode> iterator = values().iterator();
@@ -162,7 +172,7 @@
         ValueNode singleValue = iterator.next();
         while (iterator.hasNext()) {
             if (iterator.next() != singleValue) {
-                return NO_VALUE;
+                return MULTIPLE_VALUES;
             }
         }
         return singleValue;
@@ -172,7 +182,7 @@
     public void simplify(SimplifierTool tool) {
         ValueNode singleValue = singleValue();
 
-        if (singleValue != NO_VALUE) {
+        if (singleValue != MULTIPLE_VALUES) {
             for (Node node : usages().snapshot()) {
                 if (node instanceof ProxyNode && ((ProxyNode) node).proxyPoint() instanceof LoopExitNode && ((LoopExitNode) ((ProxyNode) node).proxyPoint()).loopBegin() == merge) {
                     tool.addToWorkList(node.usages());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class SimpleInfopointNode extends InfopointNode implements LIRLowerable, IterableNodeType {
+    private BytecodePosition position;
+
+    public SimpleInfopointNode(InfopointReason reason, BytecodePosition position) {
+        super(reason);
+        this.position = position;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        generator.visitSimpleInfopointNode(this);
+    }
+
+    public BytecodePosition getPosition() {
+        return position;
+    }
+
+    public void addCaller(BytecodePosition caller) {
+        this.position = relink(this.position, caller);
+    }
+
+    private static BytecodePosition relink(BytecodePosition position, BytecodePosition link) {
+        if (position.getCaller() == null) {
+            return new BytecodePosition(link, position.getMethod(), position.getBCI());
+        } else {
+            return new BytecodePosition(relink(position.getCaller(), link), position.getMethod(), position.getBCI());
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -166,7 +166,7 @@
         } else {
             assert condition == Condition.BT;
             assert x.getKind().isNumericInteger();
-            comparison = new IntegerBelowThanNode(x, y);
+            comparison = new IntegerBelowNode(x, y);
         }
 
         return comparison;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -50,7 +50,7 @@
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         if (forX.isConstant() && forY.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(getX().asConstant(), getY().asConstant()));
+            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
         }
         return this;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.calc;
+
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+
+@NodeInfo(shortName = "|<|")
+public final class IntegerBelowNode extends CompareNode {
+
+    /**
+     * Constructs a new unsigned integer comparison node.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     */
+    public IntegerBelowNode(ValueNode x, ValueNode y) {
+        super(x, y);
+        assert x.stamp() instanceof IntegerStamp;
+        assert y.stamp() instanceof IntegerStamp;
+    }
+
+    @Override
+    public Condition condition() {
+        return Condition.BT;
+    }
+
+    @Override
+    public boolean unorderedIsTrue() {
+        return false;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode result = super.canonical(tool, forX, forY);
+        if (result != this) {
+            return result;
+        }
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            return LogicConstantNode.contradiction();
+        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (yStamp.isPositive()) {
+                if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
+                    return LogicConstantNode.tautology();
+                } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
+                    return LogicConstantNode.contradiction();
+                }
+            }
+        }
+        if (forX.isConstant() && forX.asConstant().asLong() == 0) {
+            // 0 |<| y is the same as 0 != y
+            return new LogicNegationNode(CompareNode.createCompareNode(Condition.EQ, forX, forY));
+        }
+        return this;
+    }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new IntegerBelowNode(newX, newY);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.calc;
-
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-
-@NodeInfo(shortName = "|<|")
-public final class IntegerBelowThanNode extends CompareNode {
-
-    /**
-     * Constructs a new unsigned integer comparison node.
-     *
-     * @param x the instruction producing the first input to the instruction
-     * @param y the instruction that produces the second input to this instruction
-     */
-    public IntegerBelowThanNode(ValueNode x, ValueNode y) {
-        super(x, y);
-        assert x.stamp() instanceof IntegerStamp;
-        assert y.stamp() instanceof IntegerStamp;
-    }
-
-    @Override
-    public Condition condition() {
-        return Condition.BT;
-    }
-
-    @Override
-    public boolean unorderedIsTrue() {
-        return false;
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        ValueNode result = super.canonical(tool, forX, forY);
-        if (result != this) {
-            return result;
-        }
-        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return LogicConstantNode.contradiction();
-        } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
-            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
-            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
-            if (yStamp.isPositive()) {
-                if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) {
-                    return LogicConstantNode.tautology();
-                } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) {
-                    return LogicConstantNode.contradiction();
-                }
-            }
-        }
-        if (forX.isConstant() && forX.asConstant().asLong() == 0) {
-            // 0 |<| y is the same as 0 != y
-            return new LogicNegationNode(CompareNode.createCompareNode(Condition.EQ, forX, forY));
-        }
-        return this;
-    }
-
-    @Override
-    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
-        return new IntegerBelowThanNode(newX, newY);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -91,7 +91,7 @@
         }
         if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
             if (IntegerStamp.sameSign((IntegerStamp) forX.stamp(), (IntegerStamp) forY.stamp())) {
-                return new IntegerBelowThanNode(forX, forY);
+                return new IntegerBelowNode(forX, forY);
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -29,6 +29,7 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(shortName = ">>")
 public final class RightShiftNode extends ShiftNode {
@@ -38,6 +39,11 @@
     }
 
     @Override
+    public boolean inferStamp() {
+        return updateStamp(StampTool.rightShift(getX().stamp(), getY().stamp()));
+    }
+
+    @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
         if (getKind() == Kind.Int) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Jul 30 10:39:39 2014 -0700
@@ -31,6 +31,12 @@
 import com.oracle.graal.nodes.*;
 
 public class ControlFlowGraph implements AbstractControlFlowGraph<Block> {
+    /**
+     * Don't allow probability values to be become too small as this makes frequency calculations
+     * large enough that they can overflow the range of a double. This commonly happens with
+     * infinite loops within infinite loops.
+     */
+    public static final double MIN_PROBABILITY = 0.000001;
 
     public final StructuredGraph graph;
 
@@ -221,8 +227,8 @@
                     }
                 }
             }
-            if (probability > 1. / Double.MIN_NORMAL) {
-                probability = 1. / Double.MIN_NORMAL;
+            if (probability > 1. / MIN_PROBABILITY) {
+                probability = 1. / MIN_PROBABILITY;
             }
             block.setPredecessors(predecessors);
             block.setProbability(probability);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -73,6 +73,12 @@
         this.initialization = initialization;
     }
 
+    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+        super(object, location, StampFactory.forVoid(), guard, barrierType, false, null);
+        this.value = value;
+        this.initialization = initialization;
+    }
+
     @Override
     public boolean isAllowedUsageType(InputType type) {
         return (type == InputType.Guard && getNullCheck()) ? true : super.isAllowedUsageType(type);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -42,7 +42,7 @@
     /**
      * Constructs a integer switch instruction. The keyProbabilities and keySuccessors array contain
      * key.length + 1 entries, the last entry describes the default (fall through) case.
-     * 
+     *
      * @param value the instruction producing the value being switched on
      * @param successors the list of successors
      * @param keys the sorted list of keys
@@ -68,7 +68,7 @@
     /**
      * Constructs a integer switch instruction. The keyProbabilities and keySuccessors array contain
      * key.length + 1 entries, the last entry describes the default (fall through) case.
-     * 
+     *
      * @param value the instruction producing the value being switched on
      * @param successorCount the number of successors
      * @param keys the sorted list of keys
@@ -86,7 +86,7 @@
 
     /**
      * Gets the key at the specified index.
-     * 
+     *
      * @param i the index
      * @return the key at that index
      */
@@ -101,6 +101,15 @@
     }
 
     @Override
+    public boolean equalKeys(SwitchNode switchNode) {
+        if (!(switchNode instanceof IntegerSwitchNode)) {
+            return false;
+        }
+        IntegerSwitchNode other = (IntegerSwitchNode) switchNode;
+        return Arrays.equals(keys, other.keys);
+    }
+
+    @Override
     public void generate(NodeLIRBuilderTool gen) {
         gen.emitSwitch(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -33,7 +33,7 @@
  * Loads an object's {@linkplain Representation#ObjectHub hub}. The object is not null-checked by
  * this operation.
  */
-public final class LoadHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable.Unary<ValueNode>, Virtualizable {
+public final class LoadHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, Virtualizable {
 
     @Input private ValueNode value;
 
@@ -62,10 +62,10 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject) {
+    public ValueNode canonical(CanonicalizerTool tool) {
         MetaAccessProvider metaAccess = tool.getMetaAccess();
-        if (metaAccess != null && forObject.stamp() instanceof ObjectStamp) {
-            ObjectStamp stamp = (ObjectStamp) forObject.stamp();
+        if (metaAccess != null && getValue().stamp() instanceof ObjectStamp) {
+            ObjectStamp stamp = (ObjectStamp) getValue().stamp();
 
             ResolvedJavaType exactType;
             if (stamp.isExactType()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -37,12 +35,14 @@
 
     @Successor private final NodeSuccessorList<BeginNode> successors;
     @Input private ValueNode value;
-    private double[] keyProbabilities;
-    private int[] keySuccessors;
+
+    // do not change the contents of these arrays:
+    private final double[] keyProbabilities;
+    private final int[] keySuccessors;
 
     /**
      * Constructs a new Switch.
-     * 
+     *
      * @param value the instruction that provides the value to be switched over
      * @param successors the list of successors of this switch
      */
@@ -87,33 +87,6 @@
         return sum;
     }
 
-    @Override
-    public void setProbability(BeginNode successor, double value) {
-        double changeInProbability = 0;
-        int nonZeroProbabilityCases = 0;
-        for (int i = 0; i < keySuccessors.length; i++) {
-            if (successors.get(keySuccessors[i]) == successor) {
-                changeInProbability += keyProbabilities[i] - value;
-                keyProbabilities[i] = value;
-            } else if (keyProbabilities[i] > 0) {
-                nonZeroProbabilityCases++;
-            }
-        }
-
-        if (nonZeroProbabilityCases > 0) {
-            double changePerEntry = changeInProbability / nonZeroProbabilityCases;
-            if (changePerEntry != 0) {
-                for (int i = 0; i < keyProbabilities.length; i++) {
-                    if (keyProbabilities[i] > 0) {
-                        keyProbabilities[i] = keyProbabilities[i] + changePerEntry;
-                    }
-                }
-            }
-        }
-
-        assertProbabilities();
-    }
-
     public ValueNode value() {
         return value;
     }
@@ -131,6 +104,11 @@
     public abstract Constant keyAt(int i);
 
     /**
+     * Returns true if the switch has the same keys in the same order as this switch.
+     */
+    public abstract boolean equalKeys(SwitchNode switchNode);
+
+    /**
      * Returns the index of the successor belonging to the key at the specified index.
      */
     public int keySuccessorIndex(int i) {
@@ -172,7 +150,7 @@
 
     /**
      * Gets the successor corresponding to the default (fall through) case.
-     * 
+     *
      * @return the default successor
      */
     public BeginNode defaultSuccessor() {
@@ -181,11 +159,4 @@
         }
         return defaultSuccessorIndex() == -1 ? null : successors.get(defaultSuccessorIndex());
     }
-
-    @Override
-    public void afterClone(Node other) {
-        SwitchNode oldSwitch = (SwitchNode) other;
-        keyProbabilities = Arrays.copyOf(oldSwitch.keyProbabilities, oldSwitch.keyProbabilities.length);
-        keySuccessors = Arrays.copyOf(oldSwitch.keySuccessors, oldSwitch.keySuccessors.length);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -42,6 +42,10 @@
         super(object, value, location, barrierType, initialization);
     }
 
+    public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+        super(object, value, location, barrierType, guard, initialization);
+    }
+
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object()));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -54,7 +54,7 @@
              */
             LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) predecessor()).getLocationIdentity();
             BeginNode entry = graph().add(new KillingBeginNode(locationsKilledByInvoke));
-            LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(StampFactory.declaredNonNull(tool.getMetaAccess().lookupJavaType(Throwable.class))));
+            LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp()));
 
             loadException.setStateAfter(stateAfter());
             replaceAtUsages(InputType.Value, loadException);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -30,47 +30,14 @@
 import com.oracle.graal.nodes.type.*;
 
 public class MethodCallTargetNode extends CallTargetNode implements IterableNodeType, Canonicalizable {
-
-    public enum InvokeKind {
-        Interface,
-        Special,
-        Static,
-        Virtual
-    }
-
     private final JavaType returnType;
-    private ResolvedJavaMethod targetMethod;
-    private InvokeKind invokeKind;
 
     /**
      * @param arguments
      */
     public MethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType) {
-        super(arguments);
-        this.invokeKind = invokeKind;
+        super(arguments, targetMethod, invokeKind);
         this.returnType = returnType;
-        this.targetMethod = targetMethod;
-    }
-
-    /**
-     * Gets the target method for this invocation instruction.
-     *
-     * @return the target method
-     */
-    public ResolvedJavaMethod targetMethod() {
-        return targetMethod;
-    }
-
-    public InvokeKind invokeKind() {
-        return invokeKind;
-    }
-
-    public void setInvokeKind(InvokeKind kind) {
-        this.invokeKind = kind;
-    }
-
-    public void setTargetMethod(ResolvedJavaMethod method) {
-        targetMethod = method;
     }
 
     /**
@@ -106,13 +73,13 @@
         for (Node n : usages()) {
             assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n);
         }
-        if (invokeKind == InvokeKind.Special || invokeKind == InvokeKind.Static) {
-            assertFalse(targetMethod.isAbstract(), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod);
+        if (invokeKind() == InvokeKind.Special || invokeKind() == InvokeKind.Static) {
+            assertFalse(targetMethod().isAbstract(), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod());
         }
-        if (invokeKind == InvokeKind.Static) {
-            assertTrue(targetMethod.isStatic(), "static calls are only allowed for static methods (%s)", targetMethod);
+        if (invokeKind() == InvokeKind.Static) {
+            assertTrue(targetMethod().isStatic(), "static calls are only allowed for static methods (%s)", targetMethod());
         } else {
-            assertFalse(targetMethod.isStatic(), "static calls are only allowed for non-static methods (%s)", targetMethod);
+            assertFalse(targetMethod().isStatic(), "static calls are only allowed for non-static methods (%s)", targetMethod());
         }
         return super.verify();
     }
@@ -128,12 +95,12 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) {
+        if (invokeKind() == InvokeKind.Interface || invokeKind() == InvokeKind.Virtual) {
             // attempt to devirtualize the call
 
             // check for trivial cases (e.g. final methods, nonvirtual methods)
-            if (targetMethod.canBeStaticallyBound()) {
-                invokeKind = InvokeKind.Special;
+            if (targetMethod().canBeStaticallyBound()) {
+                setInvokeKind(InvokeKind.Special);
                 return this;
             }
 
@@ -145,29 +112,29 @@
                  * either the holder class is exact, or the receiver object has an exact type, or
                  * it's an array type
                  */
-                ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod, invoke().getContextType());
+                ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod(), invoke().getContextType());
                 if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver) || type.isArray())) {
-                    invokeKind = InvokeKind.Special;
-                    targetMethod = resolvedMethod;
+                    setInvokeKind(InvokeKind.Special);
+                    setTargetMethod(resolvedMethod);
                     return this;
                 }
                 if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
                     ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
                     if (uniqueConcreteType != null) {
-                        ResolvedJavaMethod methodFromUniqueType = uniqueConcreteType.resolveMethod(targetMethod, invoke().getContextType());
+                        ResolvedJavaMethod methodFromUniqueType = uniqueConcreteType.resolveMethod(targetMethod(), invoke().getContextType());
                         if (methodFromUniqueType != null) {
                             tool.assumptions().recordConcreteSubtype(type, uniqueConcreteType);
-                            invokeKind = InvokeKind.Special;
-                            targetMethod = methodFromUniqueType;
+                            setInvokeKind(InvokeKind.Special);
+                            setTargetMethod(methodFromUniqueType);
                             return this;
                         }
                     }
 
-                    ResolvedJavaMethod uniqueConcreteMethod = type.findUniqueConcreteMethod(targetMethod);
+                    ResolvedJavaMethod uniqueConcreteMethod = type.findUniqueConcreteMethod(targetMethod());
                     if (uniqueConcreteMethod != null) {
-                        tool.assumptions().recordConcreteMethod(targetMethod, type, uniqueConcreteMethod);
-                        invokeKind = InvokeKind.Special;
-                        targetMethod = uniqueConcreteMethod;
+                        tool.assumptions().recordConcreteMethod(targetMethod(), type, uniqueConcreteMethod);
+                        setInvokeKind(InvokeKind.Special);
+                        setTargetMethod(uniqueConcreteMethod);
                         return this;
                     }
                 }
@@ -178,7 +145,7 @@
 
     @Override
     public Stamp returnStamp() {
-        Kind returnKind = targetMethod.getSignature().getReturnKind();
+        Kind returnKind = targetMethod().getSignature().getReturnKind();
         if (returnKind == Kind.Object && returnType instanceof ResolvedJavaType) {
             return StampFactory.declared((ResolvedJavaType) returnType);
         } else {
@@ -200,7 +167,7 @@
 
     public static MethodCallTargetNode find(StructuredGraph graph, ResolvedJavaMethod method) {
         for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.class)) {
-            if (target.targetMethod.equals(method)) {
+            if (target.targetMethod().equals(method)) {
                 return target;
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -44,7 +44,7 @@
     /**
      * Constructs a type switch instruction. The keyProbabilities array contain key.length + 1
      * entries. The last entry in every array describes the default case.
-     * 
+     *
      * @param value the instruction producing the value being switched on, the object hub
      * @param successors the list of successors
      * @param keys the list of types
@@ -57,6 +57,21 @@
         assert keySuccessors.length == keyProbabilities.length;
         this.keys = keys;
         assert assertValues();
+        assert assertKeys();
+    }
+
+    /**
+     * Don't allow duplicate keys
+     */
+    private boolean assertKeys() {
+        for (int i = 0; i < keys.length; i++) {
+            for (int j = 0; j < keys.length; j++) {
+                if (i == j)
+                    continue;
+                assert !keys[i].equals(keys[j]);
+            }
+        }
+        return true;
     }
 
     @Override
@@ -87,6 +102,15 @@
         return keys[index].getEncoding(Representation.ObjectHub);
     }
 
+    @Override
+    public boolean equalKeys(SwitchNode switchNode) {
+        if (!(switchNode instanceof TypeSwitchNode)) {
+            return false;
+        }
+        TypeSwitchNode other = (TypeSwitchNode) switchNode;
+        return Arrays.equals(keys, other.keys);
+    }
+
     public ResolvedJavaType typeAt(int index) {
         return keys[index];
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Wed Jul 30 10:39:39 2014 -0700
@@ -60,7 +60,9 @@
 
     void visitBreakpointNode(BreakpointNode i);
 
-    void visitInfopointNode(InfopointNode i);
+    void visitFullInfopointNode(FullInfopointNode i);
+
+    void visitSimpleInfopointNode(SimpleInfopointNode i);
 
     LIRGeneratorTool getLIRGeneratorTool();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Wed Jul 30 10:39:39 2014 -0700
@@ -252,6 +252,29 @@
         return stampForMask(stamp1.getBits(), newDownMask, newUpMask);
     }
 
+    public static Stamp rightShift(Stamp value, Stamp shift) {
+        if (value instanceof IntegerStamp && shift instanceof IntegerStamp) {
+            return rightShift((IntegerStamp) value, (IntegerStamp) shift);
+        }
+        return value.illegal();
+    }
+
+    public static Stamp rightShift(IntegerStamp value, IntegerStamp shift) {
+        int bits = value.getBits();
+        if (shift.lowerBound() == shift.upperBound()) {
+            int extraBits = 64 - bits;
+            long shiftMask = bits > 32 ? 0x3FL : 0x1FL;
+            long shiftCount = shift.lowerBound() & shiftMask;
+            long defaultMask = IntegerStamp.defaultMask(bits);
+            // shifting back and forth performs sign extension
+            long downMask = (value.downMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
+            long upMask = (value.upMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
+            return new IntegerStamp(bits, value.lowerBound() >> shiftCount, value.upperBound() >> shiftCount, downMask, upMask);
+        }
+        long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
+        return stampForMask(bits, 0, mask);
+    }
+
     public static Stamp unsignedRightShift(Stamp value, Stamp shift) {
         if (value instanceof IntegerStamp && shift instanceof IntegerStamp) {
             return unsignedRightShift((IntegerStamp) value, (IntegerStamp) shift);
@@ -264,19 +287,12 @@
         if (shift.lowerBound() == shift.upperBound()) {
             long shiftMask = bits > 32 ? 0x3FL : 0x1FL;
             long shiftCount = shift.lowerBound() & shiftMask;
-            if (shiftCount != 0) {
-                long lowerBound;
-                long upperBound;
-                long downMask = value.downMask() >>> shiftCount;
-                long upMask = value.upMask() >>> shiftCount;
-                if (value.lowerBound() < 0) {
-                    lowerBound = downMask;
-                    upperBound = upMask;
-                } else {
-                    lowerBound = value.lowerBound() >>> shiftCount;
-                    upperBound = value.upperBound() >>> shiftCount;
-                }
-                return new IntegerStamp(bits, lowerBound, upperBound, downMask, upMask);
+            long downMask = value.downMask() >>> shiftCount;
+            long upMask = value.upMask() >>> shiftCount;
+            if (value.lowerBound() < 0) {
+                return new IntegerStamp(bits, downMask, upMask, downMask, upMask);
+            } else {
+                return new IntegerStamp(bits, value.lowerBound() >>> shiftCount, value.upperBound() >>> shiftCount, downMask, upMask);
             }
         }
         long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Wed Jul 30 10:39:39 2014 -0700
@@ -174,7 +174,7 @@
         }
 
         ValueNode singleValue = phiNode.singleValue();
-        if (singleValue != PhiNode.NO_VALUE) {
+        if (singleValue != PhiNode.MULTIPLE_VALUES) {
             Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
             Collection<ProxyNode> proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot();
             phiNode.graph().replaceFloating(phiNode, singleValue);
@@ -343,7 +343,7 @@
                 v = ((ValueProxy) v).getOriginalNode();
             } else if (v instanceof PhiNode) {
                 v = ((PhiNode) v).singleValue();
-                if (v == PhiNode.NO_VALUE) {
+                if (v == PhiNode.MULTIPLE_VALUES) {
                     v = null;
                 }
             } else {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -49,9 +49,15 @@
     private final boolean canonicalizeReads;
     private final CustomCanonicalizer customCanonicalizer;
 
-    public interface CustomCanonicalizer {
+    public static abstract class CustomCanonicalizer {
 
-        Node canonicalize(Node node);
+        public Node canonicalize(Node node) {
+            return node;
+        }
+
+        @SuppressWarnings("unused")
+        public void simplify(Node node, SimplifierTool tool) {
+        }
     }
 
     public CanonicalizerPhase(boolean canonicalizeReads) {
@@ -88,19 +94,19 @@
      * @param workingSet the initial working set of nodes on which the canonicalizer works, should
      *            be an auto-grow node bitmap
      */
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet) {
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet) {
         applyIncremental(graph, context, workingSet, true);
     }
 
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet, boolean dumpGraph) {
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, boolean dumpGraph) {
         new Instance(context, canonicalizeReads, workingSet, customCanonicalizer).apply(graph, dumpGraph);
     }
 
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet, Mark newNodesMark) {
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark) {
         applyIncremental(graph, context, workingSet, newNodesMark, true);
     }
 
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<Node> workingSet, Mark newNodesMark, boolean dumpGraph) {
+    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark, boolean dumpGraph) {
         new Instance(context, canonicalizeReads, workingSet, newNodesMark, customCanonicalizer).apply(graph, dumpGraph);
     }
 
@@ -109,7 +115,7 @@
         private final Mark newNodesMark;
         private final PhaseContext context;
         private final CustomCanonicalizer customCanonicalizer;
-        private final Iterable<Node> initWorkingSet;
+        private final Iterable<? extends Node> initWorkingSet;
         private final boolean canonicalizeReads;
 
         private NodeWorkList workList;
@@ -119,7 +125,7 @@
             this(context, canonicalizeReads, null, null, customCanonicalizer);
         }
 
-        private Instance(PhaseContext context, boolean canonicalizeReads, Iterable<Node> workingSet, CustomCanonicalizer customCanonicalizer) {
+        private Instance(PhaseContext context, boolean canonicalizeReads, Iterable<? extends Node> workingSet, CustomCanonicalizer customCanonicalizer) {
             this(context, canonicalizeReads, workingSet, null, customCanonicalizer);
         }
 
@@ -127,7 +133,7 @@
             this(context, canonicalizeReads, null, newNodesMark, customCanonicalizer);
         }
 
-        private Instance(PhaseContext context, boolean canonicalizeReads, Iterable<Node> workingSet, Mark newNodesMark, CustomCanonicalizer customCanonicalizer) {
+        private Instance(PhaseContext context, boolean canonicalizeReads, Iterable<? extends Node> workingSet, Mark newNodesMark, CustomCanonicalizer customCanonicalizer) {
             super("Canonicalizer");
             this.newNodesMark = newNodesMark;
             this.context = context;
@@ -225,6 +231,9 @@
             if (!result && customCanonicalizer != null) {
                 Node canonical = customCanonicalizer.canonicalize(node);
                 result = performReplacement(node, canonical);
+                if (!result) {
+                    customCanonicalizer.simplify(node, tool);
+                }
             }
             return result;
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -22,15 +22,30 @@
  */
 package com.oracle.graal.phases.common;
 
+import com.oracle.graal.graph.Graph.NodeEventScope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.util.*;
+import com.oracle.graal.phases.tiers.*;
 
-public class CleanTypeProfileProxyPhase extends Phase {
+public class CleanTypeProfileProxyPhase extends BasePhase<PhaseContext> {
+
+    private CanonicalizerPhase canonicalizer;
+
+    public CleanTypeProfileProxyPhase(CanonicalizerPhase canonicalizer) {
+        this.canonicalizer = canonicalizer;
+    }
 
     @Override
-    protected void run(StructuredGraph graph) {
-        for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) {
-            graph.replaceFloating(proxy, proxy.getValue());
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        HashSetNodeEventListener listener = new HashSetNodeEventListener();
+        try (NodeEventScope s = graph.trackNodeEvents(listener)) {
+            for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) {
+                graph.replaceFloating(proxy, proxy.getValue());
+            }
+        }
+        if (!listener.getNodes().isEmpty()) {
+            canonicalizer.applyIncremental(graph, context, listener.getNodes());
         }
         assert graph.getNodes(TypeProfileProxyNode.class).count() == 0;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,10 +32,10 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -446,12 +446,12 @@
         }
 
         private GuardedStamp computeGuardedStamp(GuardNode guard) {
-            if (guard.condition() instanceof IntegerBelowThanNode) {
+            if (guard.condition() instanceof IntegerBelowNode) {
                 if (guard.negated()) {
                     // Not sure how to reason about negated guards
                     return null;
                 }
-                IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition();
+                IntegerBelowNode below = (IntegerBelowNode) guard.condition();
                 if (below.getX().getKind() == Kind.Int && below.getX().isConstant() && !below.getY().isConstant()) {
                     Stamp stamp = StampTool.unsignedCompare(below.getX().stamp(), below.getY().stamp());
                     if (stamp != null) {
@@ -520,8 +520,8 @@
             }
 
             GuardNode existingGuard = null;
-            if (guard.condition() instanceof IntegerBelowThanNode) {
-                IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition();
+            if (guard.condition() instanceof IntegerBelowNode) {
+                IntegerBelowNode below = (IntegerBelowNode) guard.condition();
                 IntegerStamp xStamp = (IntegerStamp) below.getX().stamp();
                 IntegerStamp yStamp = (IntegerStamp) below.getY().stamp();
                 GuardedStamp cstamp = state.valueConstraints.get(below.getX());
@@ -769,7 +769,7 @@
                 }
 
                 if (replacement != null) {
-                    if (!(replacementAnchor instanceof BeginNode)) {
+                    if (replacementAnchor != null && !(replacementAnchor instanceof BeginNode)) {
                         ValueAnchorNode anchor = graph.add(new ValueAnchorNode(replacementAnchor));
                         graph.addBeforeFixed(ifNode, anchor);
                     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -47,6 +47,7 @@
  *
  */
 public class ConvertDeoptimizeToGuardPhase extends Phase {
+    private SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false);
 
     private static BeginNode findBeginNode(FixedNode startNode) {
         return GraphUtil.predecessorIterable(startNode).filter(BeginNode.class).first();
@@ -58,10 +59,9 @@
         if (graph.getNodes(DeoptimizeNode.class).isEmpty()) {
             return;
         }
-        SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false);
         for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) {
             assert d.isAlive();
-            visitDeoptBegin(BeginNode.prevBegin(d), d.action(), d.reason(), graph, simplifierTool);
+            visitDeoptBegin(BeginNode.prevBegin(d), d.action(), d.reason(), graph);
         }
 
         for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.class)) {
@@ -94,7 +94,7 @@
                         }
                         if (xs[i].getKind() != Kind.Object && ys[i].getKind() != Kind.Object &&
                                         compare.condition().foldCondition(xs[i], ys[i], null, compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
-                            visitDeoptBegin(BeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), graph, simplifierTool);
+                            visitDeoptBegin(BeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), graph);
                         }
                     }
                 }
@@ -104,7 +104,7 @@
         new DeadCodeEliminationPhase().apply(graph);
     }
 
-    private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, StructuredGraph graph, SimplifierTool simplifierTool) {
+    private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, StructuredGraph graph) {
         if (deoptBegin instanceof MergeNode) {
             MergeNode mergeNode = (MergeNode) deoptBegin;
             Debug.log("Visiting %s", mergeNode);
@@ -112,11 +112,11 @@
             while (mergeNode.isAlive()) {
                 AbstractEndNode end = mergeNode.forwardEnds().first();
                 BeginNode newBeginNode = findBeginNode(end);
-                visitDeoptBegin(newBeginNode, deoptAction, deoptReason, graph, simplifierTool);
+                visitDeoptBegin(newBeginNode, deoptAction, deoptReason, graph);
             }
             assert next.isAlive();
             BeginNode newBeginNode = findBeginNode(next);
-            visitDeoptBegin(newBeginNode, deoptAction, deoptReason, graph, simplifierTool);
+            visitDeoptBegin(newBeginNode, deoptAction, deoptReason, graph);
             return;
         } else if (deoptBegin.predecessor() instanceof IfNode) {
             IfNode ifNode = (IfNode) deoptBegin.predecessor();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -209,7 +209,7 @@
 
     }
 
-    private static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure<Set<LocationIdentity>> {
+    public static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure<Set<LocationIdentity>> {
 
         private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
 
@@ -261,7 +261,7 @@
 
     }
 
-    private static class FloatingReadClosure extends NodeIteratorClosure<MemoryMapImpl> {
+    public static class FloatingReadClosure extends NodeIteratorClosure<MemoryMapImpl> {
 
         private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
         private boolean createFloatingReads;
@@ -372,7 +372,7 @@
             Map<LocationIdentity, MemoryPhiNode> phis = new HashMap<>();
 
             if (updateExistingPhis) {
-                for (MemoryPhiNode phi : loop.phis().filter(MemoryPhiNode.class)) {
+                for (MemoryPhiNode phi : loop.phis().filter(MemoryPhiNode.class).snapshot()) {
                     if (modifiedLocations.contains(phi.getLocationIdentity())) {
                         phi.values().clear();
                         phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(phi.getLocationIdentity())));
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -89,7 +89,8 @@
 
         @Override
         protected FrameState merge(MergeNode merge, List<FrameState> states) {
-            return merge.stateAfter() != null ? merge.stateAfter() : singleFrameState(merge, states);
+            FrameState singleFrameState = singleFrameState(states);
+            return singleFrameState == null ? merge.stateAfter() : singleFrameState;
         }
 
         @Override
@@ -123,7 +124,7 @@
         return true;
     }
 
-    private static FrameState singleFrameState(@SuppressWarnings("unused") MergeNode merge, List<FrameState> states) {
+    private static FrameState singleFrameState(List<FrameState> states) {
         FrameState singleState = states.get(0);
         for (int i = 1; i < states.size(); ++i) {
             if (states.get(i) != singleState) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -34,9 +34,11 @@
 
     @Override
     protected void run(StructuredGraph graph) {
+        Stamp nonNull = StampFactory.objectNonNull();
         for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
             if (param.stamp() instanceof ObjectStamp) {
-                param.setStamp(StampFactory.declaredNonNull(((ObjectStamp) param.stamp()).type()));
+                ObjectStamp paramStamp = (ObjectStamp) param.stamp();
+                param.setStamp(paramStamp.join(nonNull));
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java	Wed Jul 30 10:39:39 2014 -0700
@@ -306,8 +306,8 @@
      *
      */
     private MethodCallTargetNode deverbosifyInputsCopyOnWrite(MethodCallTargetNode parent) {
-        final MethodCallTargetNode.InvokeKind ik = parent.invokeKind();
-        final boolean shouldTryDevirt = (ik == MethodCallTargetNode.InvokeKind.Interface || ik == MethodCallTargetNode.InvokeKind.Virtual);
+        final CallTargetNode.InvokeKind ik = parent.invokeKind();
+        final boolean shouldTryDevirt = (ik == CallTargetNode.InvokeKind.Interface || ik == CallTargetNode.InvokeKind.Virtual);
         boolean shouldDowncastReceiver = shouldTryDevirt;
         MethodCallTargetNode changed = null;
         for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
@@ -546,10 +546,9 @@
      * MethodCallTargetNode} as described above may enable two optimizations:
      * <ul>
      * <li>
-     * devirtualization of an
-     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind#Interface} or
-     * {@link com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind#Virtual} callsite
-     * (devirtualization made possible after narrowing the type of the receiver)</li>
+     * devirtualization of an {@link com.oracle.graal.nodes.CallTargetNode.InvokeKind#Interface} or
+     * {@link com.oracle.graal.nodes.CallTargetNode.InvokeKind#Virtual} callsite (devirtualization
+     * made possible after narrowing the type of the receiver)</li>
      * <li>
      * (future work) actual-argument-aware inlining, ie, to specialize callees on the types of
      * arguments other than the receiver (examples: multi-methods, the inlining problem, lambdas as
@@ -572,7 +571,7 @@
         }
         FlowUtil.replaceInPlace(invoke.asNode(), invoke.callTarget(), deverbosifyInputsCopyOnWrite((MethodCallTargetNode) invoke.callTarget()));
         MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-        if (callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Virtual) {
+        if (callTarget.invokeKind() != CallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != CallTargetNode.InvokeKind.Virtual) {
             return;
         }
         ValueNode receiver = callTarget.receiver();
@@ -600,7 +599,7 @@
         }
         if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
             metricMethodResolved.increment();
-            callTarget.setInvokeKind(MethodCallTargetNode.InvokeKind.Special);
+            callTarget.setInvokeKind(CallTargetNode.InvokeKind.Special);
             callTarget.setTargetMethod(method);
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Wed Jul 30 10:39:39 2014 -0700
@@ -39,10 +39,10 @@
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -314,8 +314,9 @@
             }
         }
 
+        processSimpleInfopoints(invoke, inlineGraph, duplicates);
         if (stateAfter != null) {
-            processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge);
+            processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1);
             int callerLockDepth = stateAfter.nestedLockDepth();
             if (callerLockDepth != 0) {
                 for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
@@ -353,7 +354,25 @@
         return duplicates;
     }
 
-    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge) {
+    private static void processSimpleInfopoints(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates) {
+        if (inlineGraph.getNodes(SimpleInfopointNode.class).isEmpty()) {
+            return;
+        }
+        BytecodePosition pos = new BytecodePosition(toBytecodePosition(invoke.stateAfter()), invoke.asNode().graph().method(), invoke.bci());
+        for (SimpleInfopointNode original : inlineGraph.getNodes(SimpleInfopointNode.class)) {
+            SimpleInfopointNode duplicate = (SimpleInfopointNode) duplicates.get(original);
+            duplicate.addCaller(pos);
+        }
+    }
+
+    private static BytecodePosition toBytecodePosition(FrameState fs) {
+        if (fs == null) {
+            return null;
+        }
+        return new BytecodePosition(toBytecodePosition(fs.outerFrameState()), fs.method(), fs.bci);
+    }
+
+    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge, boolean alwaysDuplicateStateAfter) {
         FrameState stateAtReturn = invoke.stateAfter();
         FrameState outerFrameState = null;
         Kind invokeReturnKind = invoke.asNode().getKind();
@@ -366,7 +385,7 @@
                      * return value (top of stack)
                      */
                     FrameState stateAfterReturn = stateAtReturn;
-                    if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) {
+                    if (invokeReturnKind != Kind.Void && (alwaysDuplicateStateAfter || frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0))) {
                         stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
                     }
                     frameState.replaceAndDelete(stateAfterReturn);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Wed Jul 30 10:39:39 2014 -0700
@@ -27,12 +27,12 @@
 import com.oracle.graal.api.code.Assumptions;
 import com.oracle.graal.api.meta.MetaAccessProvider;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.util.Providers;
 import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
  * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Wed Jul 30 10:39:39 2014 -0700
@@ -34,10 +34,10 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -78,6 +78,15 @@
         this.methodProbabilities = computeMethodProbabilities();
         this.maximumMethodProbability = maximumMethodProbability();
         assert maximumMethodProbability > 0;
+        assert assertUniqueTypes(ptypes);
+    }
+
+    private static boolean assertUniqueTypes(ArrayList<ProfiledType> ptypes) {
+        Set<ResolvedJavaType> set = new HashSet<>();
+        for (ProfiledType ptype : ptypes) {
+            set.add(ptype.getType());
+        }
+        return set.size() == ptypes.size();
     }
 
     private double[] computeMethodProbabilities() {
@@ -383,15 +392,22 @@
         ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
         double[] keyProbabilities = new double[ptypes.size() + 1];
         int[] keySuccessors = new int[ptypes.size() + 1];
+        double totalProbability = notRecordedTypeProbability;
         for (int i = 0; i < ptypes.size(); i++) {
             keys[i] = ptypes.get(i).getType();
             keyProbabilities[i] = ptypes.get(i).getProbability();
+            totalProbability += keyProbabilities[i];
             keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
             assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
         }
         keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
         keySuccessors[keySuccessors.length - 1] = successors.length - 1;
 
+        // Normalize the probabilities.
+        for (int i = 0; i < keyProbabilities.length; i++) {
+            keyProbabilities[i] /= totalProbability;
+        }
+
         TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
         FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
         pred.setNext(typeSwitch);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Wed Jul 30 10:39:39 2014 -0700
@@ -29,12 +29,12 @@
 import com.oracle.graal.compiler.common.calc.Condition;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.CompareNode;
 import com.oracle.graal.nodes.extended.LoadHubNode;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
 import com.oracle.graal.phases.util.Providers;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
  * Represents an inlining opportunity for which profiling information suggests a monomorphic
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Wed Jul 30 10:39:39 2014 -0700
@@ -166,11 +166,11 @@
         MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
 
-        if (callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
+        if (callTarget.invokeKind() == CallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
             return getExactInlineInfo(invoke, targetMethod);
         }
 
-        assert callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Virtual || callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Interface;
+        assert callTarget.invokeKind() == CallTargetNode.InvokeKind.Virtual || callTarget.invokeKind() == CallTargetNode.InvokeKind.Interface;
 
         ResolvedJavaType holder = targetMethod.getDeclaringClass();
         if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -112,7 +112,8 @@
     }
 
     protected CharSequence createName() {
-        String s = BasePhase.this.getClass().getSimpleName();
+        String className = BasePhase.this.getClass().getName();
+        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
         if (s.endsWith("Phase")) {
             s = s.substring(0, s.length() - "Phase".length());
         }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Wed Jul 30 10:39:39 2014 -0700
@@ -114,6 +114,7 @@
             ControlSplitNode split = (ControlSplitNode) current.predecessor();
             probability = split.probability((BeginNode) current) * applyAsDouble(split);
         }
+        assert !Double.isNaN(probability) && !Double.isInfinite(probability) : current + " " + probability;
         cache.put(current, probability);
         return probability;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Wed Jul 30 10:39:39 2014 -0700
@@ -160,8 +160,8 @@
                     FrameState pendingStateAfter = null;
                     for (final ScheduledNode node : list) {
                         FrameState stateAfter = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : null;
-                        if (node instanceof InfopointNode) {
-                            stateAfter = ((InfopointNode) node).getState();
+                        if (node instanceof FullInfopointNode) {
+                            stateAfter = ((FullInfopointNode) node).getState();
                         }
 
                         if (pendingStateAfter != null && node instanceof FixedNode) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Wed Jul 30 10:39:39 2014 -0700
@@ -129,10 +129,12 @@
     private void writeGraph(Graph graph, SchedulePhase predefinedSchedule) throws IOException {
         SchedulePhase schedule = predefinedSchedule;
         if (schedule == null) {
-            try {
-                schedule = new SchedulePhase();
-                schedule.apply((StructuredGraph) graph);
-            } catch (Throwable t) {
+            if (PrintIdealGraphSchedule.getValue()) {
+                try {
+                    schedule = new SchedulePhase();
+                    schedule.apply((StructuredGraph) graph);
+                } catch (Throwable t) {
+                }
             }
         }
         ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
@@ -410,7 +412,11 @@
             NodeClass nodeClass = node.getNodeClass();
             node.getDebugProperties(props);
             if (probabilities != null && node instanceof FixedNode) {
-                props.put("probability", probabilities.applyAsDouble((FixedNode) node));
+                try {
+                    props.put("probability", probabilities.applyAsDouble((FixedNode) node));
+                } catch (Throwable t) {
+                    props.put("probability", t);
+                }
             }
             writeInt(getNodeId(node));
             writePoolObject(nodeClass);
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Wed Jul 30 10:39:39 2014 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.printer;
 
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
 import java.io.*;
 import java.util.*;
 import java.util.Map.Entry;
@@ -87,10 +89,12 @@
         Set<Node> noBlockNodes = new HashSet<>();
         SchedulePhase schedule = predefinedSchedule;
         if (schedule == null && tryToSchedule) {
-            try {
-                schedule = new SchedulePhase();
-                schedule.apply((StructuredGraph) graph);
-            } catch (Throwable t) {
+            if (PrintIdealGraphSchedule.getValue()) {
+                try {
+                    schedule = new SchedulePhase();
+                    schedule.apply((StructuredGraph) graph);
+                } catch (Throwable t) {
+                }
             }
         }
         ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -33,6 +33,7 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.replacements.nodes.*;
 
 public class BitOpNodesTest extends GraalCompilerTest {
 
@@ -186,8 +187,11 @@
 
     @Test
     public void testScanReverseInt() {
-        ValueNode result = parseAndInline("scanReverseIntSnippet");
-        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 16, 20), result.stamp());
+        /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */
+        ValueNode result = parseAndInline("scanReverseIntSnippet", BitScanReverseNode.class);
+        if (result != null) {
+            Assert.assertEquals(StampFactory.forInteger(Kind.Int, 16, 20), result.stamp());
+        }
     }
 
     public static int scanReverseLongConstantSnippet() {
@@ -208,8 +212,11 @@
 
     @Test
     public void testScanReverseLong() {
-        ValueNode result = parseAndInline("scanReverseLongSnippet");
-        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 48, 64), result.stamp());
+        /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */
+        ValueNode result = parseAndInline("scanReverseLongSnippet", BitScanReverseNode.class);
+        if (result != null) {
+            Assert.assertEquals(StampFactory.forInteger(Kind.Int, 48, 64), result.stamp());
+        }
     }
 
     public static int scanReverseLongEmptySnippet(long v) {
@@ -220,11 +227,26 @@
 
     @Test
     public void testScanReverseLongEmpty() {
-        ValueNode result = parseAndInline("scanReverseLongEmptySnippet");
-        Assert.assertEquals(StampFactory.forInteger(Kind.Int, 24, 64), result.stamp());
+        /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */
+        ValueNode result = parseAndInline("scanReverseLongEmptySnippet", BitScanReverseNode.class);
+        if (result != null) {
+            Assert.assertEquals(StampFactory.forInteger(Kind.Int, 24, 64), result.stamp());
+        }
     }
 
     private ValueNode parseAndInline(String name) {
+        return parseAndInline(name, null);
+    }
+
+    /**
+     * Parse and optimize {@code name}. If {@code expectedClass} is non-null and a node of that type
+     * isn't found simply return null. Otherwise return the node returned by the graph.
+     *
+     * @param name
+     * @param expectedClass
+     * @return the returned value or null if {@code expectedClass} is not found in the graph.
+     */
+    private ValueNode parseAndInline(String name, Class<? extends ValueNode> expectedClass) {
         StructuredGraph graph = parse(name);
         HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
@@ -232,6 +254,11 @@
         new InliningPhase(canonicalizer).apply(graph, context);
         canonicalizer.apply(graph, context);
         Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        if (expectedClass != null) {
+            if (graph.getNodes().filter(expectedClass).count() == 0) {
+                return null;
+            }
+        }
         return graph.getNodes(ReturnNode.class).first().result();
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Wed Jul 30 10:39:39 2014 -0700
@@ -646,7 +646,7 @@
             }
         }
 
-        return tool.createGuard(n, graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+        return tool.createGuard(n, graph.unique(new IntegerBelowNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
     }
 
     protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Wed Jul 30 10:39:39 2014 -0700
@@ -31,9 +31,9 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.util.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Wed Jul 30 10:39:39 2014 -0700
@@ -39,7 +39,7 @@
         if (i == 0) {
             return 32;
         }
-        return 31 - BitScanReverseNode.scan(i);
+        return 31 - BitScanReverseNode.unsafeScan(i);
     }
 
     @MethodSubstitution
@@ -47,7 +47,7 @@
         if (i == 0) {
             return 32;
         }
-        return BitScanForwardNode.scan(i);
+        return BitScanForwardNode.unsafeScan(i);
     }
 
     @MethodSubstitution
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Wed Jul 30 10:39:39 2014 -0700
@@ -39,7 +39,7 @@
         if (i == 0) {
             return 64;
         }
-        return 63 - BitScanReverseNode.scan(i);
+        return 63 - BitScanReverseNode.unsafeScan(i);
     }
 
     @MethodSubstitution
@@ -47,7 +47,7 @@
         if (i == 0) {
             return 64;
         }
-        return BitScanForwardNode.scan(i);
+        return BitScanForwardNode.unsafeScan(i);
     }
 
     @MethodSubstitution
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Jul 30 10:39:39 2014 -0700
@@ -45,8 +45,8 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -63,27 +63,53 @@
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (forValue.isConstant()) {
             Constant c = forValue.asConstant();
-            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
+            if (c.asLong() != 0) {
+                return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
+            }
         }
         return this;
     }
 
-    @NodeIntrinsic
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return number of trailing zeros or -1 if {@code v} == 0.
+     */
     public static int scan(long v) {
         if (v == 0) {
             return -1;
         }
-        int index = 0;
-        while (((1L << index) & v) == 0) {
-            ++index;
-        }
-        return index;
+        return Long.numberOfTrailingZeros(v);
+    }
+
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return number of trailing zeros or -1 if {@code v} == 0.
+     */
+    public static int scan(int v) {
+        return scan(0xffffffffL & v);
     }
 
+    /**
+     * Raw intrinsic for bsf instruction.
+     *
+     * @param v
+     * @return number of trailing zeros or an undefined value if {@code v} == 0.
+     */
     @NodeIntrinsic
-    public static int scan(int v) {
-        return scan(v & 0xFFFFFFFFL);
-    }
+    public static native int unsafeScan(long v);
+
+    /**
+     * Raw intrinsic for bsf instruction.
+     *
+     * @param v
+     * @return number of trailing zeros or an undefined value if {@code v} == 0.
+     */
+    @NodeIntrinsic
+    public static native int unsafeScan(int v);
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -61,34 +61,50 @@
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (forValue.isConstant()) {
             Constant c = forValue.asConstant();
-            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
+            if (c.asLong() != 0) {
+                return ConstantNode.forInt(forValue.getKind() == Kind.Int ? scan(c.asInt()) : scan(c.asLong()));
+            }
         }
         return this;
     }
 
-    @NodeIntrinsic
-    public static int scan(int v) {
-        if (v == 0) {
-            return -1;
-        }
-        int index = 31;
-        while (((1 << index) & v) == 0) {
-            --index;
-        }
-        return index;
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return index of first set bit or -1 if {@code v} == 0.
+     */
+    public static int scan(long v) {
+        return 63 - Long.numberOfLeadingZeros(v);
     }
 
+    /**
+     * Utility method with defined return value for 0.
+     *
+     * @param v
+     * @return index of first set bit or -1 if {@code v} == 0.
+     */
+    public static int scan(int v) {
+        return 31 - Integer.numberOfLeadingZeros(v);
+    }
+
+    /**
+     * Raw intrinsic for bsr instruction.
+     *
+     * @param v
+     * @return index of first set bit or an undefined value if {@code v} == 0.
+     */
     @NodeIntrinsic
-    public static int scan(long v) {
-        if (v == 0) {
-            return -1;
-        }
-        int index = 63;
-        while (((1L << index) & v) == 0) {
-            --index;
-        }
-        return index;
-    }
+    public static native int unsafeScan(int v);
+
+    /**
+     * Raw intrinsic for bsr instruction.
+     *
+     * @param v
+     * @return index of first set bit or an undefined value if {@code v} == 0.
+     */
+    @NodeIntrinsic
+    public static native int unsafeScan(long v);
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -31,9 +31,9 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Wed Jul 30 10:39:39 2014 -0700
@@ -29,6 +29,7 @@
 
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.stream.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
@@ -41,6 +42,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
@@ -52,6 +54,7 @@
 import com.oracle.graal.printer.*;
 import com.oracle.graal.runtime.*;
 import com.oracle.graal.truffle.*;
+import com.oracle.graal.word.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.SlowPath;
 import com.oracle.truffle.api.frame.*;
@@ -245,33 +248,31 @@
     }
 
     @SlowPath
-    public Iterable<FrameInstance> getStackTrace() {
+    @Override
+    public <T> T iterateFrames(FrameInstanceVisitor<T> visitor) {
         initStackIntrospection();
-        final Iterator<InspectedFrame> frames = stackIntrospection.getStackTrace(anyFrameMethod, anyFrameMethod, 1).iterator();
-        class FrameIterator implements Iterator<FrameInstance> {
 
-            public boolean hasNext() {
-                return frames.hasNext();
-            }
+        InspectedFrameVisitor<T> inspectedFrameVisitor = new InspectedFrameVisitor<T>() {
+            private boolean skipNext = false;
 
-            public FrameInstance next() {
-                InspectedFrame frame = frames.next();
-                if (frame.getMethod().equals(callNodeMethod[0])) {
-                    assert frames.hasNext();
-                    InspectedFrame calltarget2 = frames.next();
-                    assert calltarget2.getMethod().equals(callTargetMethod[0]);
-                    return new HotSpotFrameInstance.CallNodeFrame(frame);
+            public T visitFrame(InspectedFrame frame) {
+                if (skipNext) {
+                    assert frame.isMethod(callTargetMethod[0]);
+                    skipNext = false;
+                    return null;
+                }
+
+                if (frame.isMethod(callNodeMethod[0])) {
+                    skipNext = true;
+                    return visitor.visitFrame(new HotSpotFrameInstance.CallNodeFrame(frame));
                 } else {
-                    assert frame.getMethod().equals(callTargetMethod[0]);
-                    return new HotSpotFrameInstance.CallTargetFrame(frame, false);
+                    assert frame.isMethod(callTargetMethod[0]);
+                    return visitor.visitFrame(new HotSpotFrameInstance.CallTargetFrame(frame, false));
                 }
-            }
-        }
-        return new Iterable<FrameInstance>() {
-            public Iterator<FrameInstance> iterator() {
-                return new FrameIterator();
+
             }
         };
+        return stackIntrospection.iterateFrames(anyFrameMethod, anyFrameMethod, 1, inspectedFrameVisitor);
     }
 
     private void initStackIntrospection() {
@@ -280,15 +281,17 @@
         }
     }
 
+    @Override
+    public FrameInstance getCallerFrame() {
+        return iterateFrames(frame -> frame);
+    }
+
     @SlowPath
+    @Override
     public FrameInstance getCurrentFrame() {
         initStackIntrospection();
-        Iterator<InspectedFrame> frames = stackIntrospection.getStackTrace(callTargetMethod, callTargetMethod, 0).iterator();
-        if (frames.hasNext()) {
-            return new HotSpotFrameInstance.CallTargetFrame(frames.next(), true);
-        } else {
-            return null;
-        }
+
+        return stackIntrospection.iterateFrames(callTargetMethod, callTargetMethod, 0, frame -> new HotSpotFrameInstance.CallTargetFrame(frame, true));
     }
 
     public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) {
@@ -342,4 +345,25 @@
     public void reinstallStubs() {
         installOptimizedCallTargetCallMethod();
     }
+
+    public void notifyTransferToInterpreter() {
+        CompilerAsserts.neverPartOfCompilation();
+        if (TraceTruffleTransferToInterpreter.getValue()) {
+            Word thread = CurrentJavaThreadNode.get(HotSpotGraalRuntime.runtime().getTarget().wordKind);
+            boolean deoptimized = thread.readByte(HotSpotGraalRuntime.runtime().getConfig().pendingTransferToInterpreterOffset) != 0;
+            if (deoptimized) {
+                thread.writeByte(HotSpotGraalRuntime.runtime().getConfig().pendingTransferToInterpreterOffset, (byte) 0);
+
+                logTransferToInterpreter();
+            }
+        }
+    }
+
+    private static void logTransferToInterpreter() {
+        final int skip = 2;
+        final int limit = 20;
+        StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+        String suffix = stackTrace.length > skip + limit ? "\n  ..." : "";
+        TTY.out().out().println(Arrays.stream(stackTrace).skip(skip).limit(limit).map(StackTraceElement::toString).collect(Collectors.joining("\n  ", "", suffix)));
+    }
 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -164,7 +164,7 @@
             canonicalizer.apply(graph, context);
 
             // Additional inlining.
-            PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerInfopointDefault());
+            PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault());
             graphBuilderSuite.appendPhase(canonicalizer);
             graphBuilderSuite.appendPhase(new DeadCodeEliminationPhase());
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Wed Jul 30 10:39:39 2014 -0700
@@ -195,7 +195,6 @@
     private Object callBoundary(Object[] args) {
         if (CompilerDirectives.inInterpreter()) {
             // We are called and we are still in Truffle interpreter mode.
-            CompilerDirectives.transferToInterpreter();
             interpreterCall();
         } else {
             // We come here from compiled code (i.e., we have been inlined).
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Jul 30 10:39:39 2014 -0700
@@ -39,8 +39,8 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 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.util.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -122,20 +122,7 @@
             new VerifyFrameDoesNotEscapePhase().apply(graph, false);
 
             if (TraceTruffleCompilationHistogram.getValue() && constantReceivers != null) {
-                DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes");
-                for (Constant c : constantReceivers) {
-                    String javaName = providers.getMetaAccess().lookupJavaType(c).toJavaName(false);
-
-                    // The DSL uses nested classes with redundant names - only show the inner class
-                    int index = javaName.indexOf('$');
-                    if (index != -1) {
-                        javaName = javaName.substring(index + 1);
-                    }
-
-                    histogram.add(javaName);
-
-                }
-                new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram);
+                createHistogram();
             }
 
             canonicalizer.apply(graph, baseContext);
@@ -176,6 +163,23 @@
         return graph;
     }
 
+    private void createHistogram() {
+        DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes");
+        for (Constant c : constantReceivers) {
+            String javaName = providers.getMetaAccess().lookupJavaType(c).toJavaName(false);
+
+            // The DSL uses nested classes with redundant names - only show the inner class
+            int index = javaName.indexOf('$');
+            if (index != -1) {
+                javaName = javaName.substring(index + 1);
+            }
+
+            histogram.add(javaName);
+
+        }
+        new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram);
+    }
+
     private void expandTree(StructuredGraph graph, Assumptions assumptions) {
         PhaseContext phaseContext = new PhaseContext(providers, assumptions);
         TruffleExpansionLogger expansionLogger = null;
@@ -207,26 +211,7 @@
                         }
 
                         if (inlineGraph != null) {
-                            try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) {
-
-                                int nodeCountBefore = graph.getNodeCount();
-                                if (TraceTruffleExpansion.getValue()) {
-                                    expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
-                                }
-                                List<Node> canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot();
-                                Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false, canonicalizedNodes);
-                                if (TraceTruffleExpansion.getValue()) {
-                                    expansionLogger.postExpand(inlined);
-                                }
-                                if (Debug.isDumpEnabled()) {
-                                    int nodeCountAfter = graph.getNodeCount();
-                                    Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
-                                }
-                                AbstractInlineInfo.getInlinedParameterUsages(canonicalizedNodes, inlineGraph, inlined);
-                                canonicalizer.applyIncremental(graph, phaseContext, canonicalizedNodes);
-
-                                changed = true;
-                            }
+                            changed = expandTreeInline(graph, phaseContext, expansionLogger, methodCallTargetNode, inlineGraph);
                         }
                     }
                 }
@@ -242,6 +227,28 @@
         }
     }
 
+    private boolean expandTreeInline(StructuredGraph graph, PhaseContext phaseContext, TruffleExpansionLogger expansionLogger, MethodCallTargetNode methodCallTargetNode, StructuredGraph inlineGraph) {
+        try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) {
+            int nodeCountBefore = graph.getNodeCount();
+            if (TraceTruffleExpansion.getValue()) {
+                expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
+            }
+            List<Node> canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot();
+            Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false, canonicalizedNodes);
+            if (TraceTruffleExpansion.getValue()) {
+                expansionLogger.postExpand(inlined);
+            }
+            if (Debug.isDumpEnabled()) {
+                int nodeCountAfter = graph.getNodeCount();
+                Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
+            }
+            AbstractInlineInfo.getInlinedParameterUsages(canonicalizedNodes, inlineGraph, inlined);
+            canonicalizer.applyIncremental(graph, phaseContext, canonicalizedNodes);
+
+            return true;
+        }
+    }
+
     private StructuredGraph parseGraph(final ResolvedJavaMethod targetMethod, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final PhaseContext phaseContext,
                     boolean ignoreSlowPath) {
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Wed Jul 30 10:39:39 2014 -0700
@@ -30,7 +30,7 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.Node.Child;
 
-final class PartialEvaluatorCanonicalizer implements CanonicalizerPhase.CustomCanonicalizer {
+final class PartialEvaluatorCanonicalizer extends CanonicalizerPhase.CustomCanonicalizer {
 
     private final MetaAccessProvider metaAccess;
     private final ConstantReflectionProvider constantReflection;
@@ -43,27 +43,35 @@
     @Override
     public Node canonicalize(Node node) {
         if (node instanceof LoadFieldNode) {
-            LoadFieldNode loadFieldNode = (LoadFieldNode) node;
-            if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) {
-                if (loadFieldNode.field().isFinal() || (loadFieldNode.getKind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
-                                loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
-                    Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
-                    assert verifyFieldValue(loadFieldNode.field(), constant);
-                    return ConstantNode.forConstant(constant, metaAccess);
-                }
-            }
+            return canonicalizeLoadField((LoadFieldNode) node);
         } else if (node instanceof LoadIndexedNode) {
-            LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node;
-            if (loadIndexedNode.array().isConstant() && loadIndexedNode.index().isConstant()) {
-                int index = loadIndexedNode.index().asConstant().asInt();
+            return canonicalizeLoadIndex((LoadIndexedNode) node);
+        }
+        return node;
+    }
 
-                Constant constant = constantReflection.readArrayElement(loadIndexedNode.array().asConstant(), index);
-                if (constant != null) {
-                    return ConstantNode.forConstant(constant, metaAccess);
-                }
+    private Node canonicalizeLoadField(LoadFieldNode loadFieldNode) {
+        if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) {
+            if (loadFieldNode.field().isFinal() || (loadFieldNode.getKind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
+                            loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
+                Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
+                assert verifyFieldValue(loadFieldNode.field(), constant);
+                return ConstantNode.forConstant(constant, metaAccess);
             }
         }
-        return node;
+        return loadFieldNode;
+    }
+
+    private Node canonicalizeLoadIndex(LoadIndexedNode loadIndexedNode) {
+        if (loadIndexedNode.array().isConstant() && loadIndexedNode.index().isConstant()) {
+            int index = loadIndexedNode.index().asConstant().asInt();
+
+            Constant constant = constantReflection.readArrayElement(loadIndexedNode.array().asConstant(), index);
+            if (constant != null) {
+                return ConstantNode.forConstant(constant, metaAccess);
+            }
+        }
+        return loadIndexedNode;
     }
 
     private boolean verifyFieldValue(ResolvedJavaField field, Constant constant) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Wed Jul 30 10:39:39 2014 -0700
@@ -29,6 +29,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Graph.Mark;
@@ -37,8 +38,8 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
@@ -97,7 +98,6 @@
         return graph;
     }
 
-    @SuppressWarnings("unused")
     public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer,
                     boolean ignoreSlowPath) {
 
@@ -124,24 +124,7 @@
         }
 
         if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) {
-            List<Long> lastUsedList = new ArrayList<>();
-            for (long l : lastUsed.values()) {
-                lastUsedList.add(l);
-            }
-            Collections.sort(lastUsedList);
-            long mid = lastUsedList.get(lastUsedList.size() / 2);
-
-            List<List<Object>> toRemoveList = new ArrayList<>();
-            for (Entry<List<Object>, Long> entry : lastUsed.entrySet()) {
-                if (entry.getValue() < mid) {
-                    toRemoveList.add(entry.getKey());
-                }
-            }
-
-            for (List<Object> entry : toRemoveList) {
-                cache.remove(entry);
-                lastUsed.remove(entry);
-            }
+            lookupExceedsMaxSize();
         }
 
         lastUsed.put(key, counter++);
@@ -183,42 +166,11 @@
                 boolean inliningProgress = false;
                 for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
                     if (!graph.getMark().equals(mark)) {
-                        // Make sure macro substitutions such as
-                        // CompilerDirectives.transferToInterpreter get processed first.
-                        for (Node newNode : graph.getNewNodes(mark)) {
-                            if (newNode instanceof MethodCallTargetNode) {
-                                MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
-                                Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
-                                if (macroSubstitution != null) {
-                                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
-                                } else {
-                                    tryCutOffRuntimeExceptionsAndErrors(methodCallTargetNode);
-                                }
-                            }
-                        }
-                        mark = graph.getMark();
+                        mark = lookupProcessMacroSubstitutions(graph, mark);
                     }
                     if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) {
                         inliningProgress = true;
-                        List<Node> canonicalizerUsages = new ArrayList<Node>();
-                        for (Node n : methodCallTarget.invoke().asNode().usages()) {
-                            if (n instanceof Canonicalizable) {
-                                canonicalizerUsages.add(n);
-                            }
-                        }
-                        List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
-                        Mark beforeInvokeMark = graph.getMark();
-                        expandInvoke(methodCallTarget);
-                        for (Node arg : argumentSnapshot) {
-                            if (arg != null && arg.recordsUsages()) {
-                                for (Node argUsage : arg.usages()) {
-                                    if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
-                                        canonicalizerUsages.add(argUsage);
-                                    }
-                                }
-                            }
-                        }
-                        canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages);
+                        lookupDoInline(graph, phaseContext, canonicalizerPhase, methodCallTarget);
                     }
                 }
 
@@ -240,7 +192,66 @@
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
+    }
 
+    private void lookupExceedsMaxSize() {
+        List<Long> lastUsedList = new ArrayList<>();
+        for (long l : lastUsed.values()) {
+            lastUsedList.add(l);
+        }
+        Collections.sort(lastUsedList);
+        long mid = lastUsedList.get(lastUsedList.size() / 2);
+
+        List<List<Object>> toRemoveList = new ArrayList<>();
+        for (Entry<List<Object>, Long> entry : lastUsed.entrySet()) {
+            if (entry.getValue() < mid) {
+                toRemoveList.add(entry.getKey());
+            }
+        }
+
+        for (List<Object> entry : toRemoveList) {
+            cache.remove(entry);
+            lastUsed.remove(entry);
+        }
+    }
+
+    private Mark lookupProcessMacroSubstitutions(final StructuredGraph graph, Mark mark) throws GraalInternalError {
+        // Make sure macro substitutions such as
+        // CompilerDirectives.transferToInterpreter get processed first.
+        for (Node newNode : graph.getNewNodes(mark)) {
+            if (newNode instanceof MethodCallTargetNode) {
+                MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
+                Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
+                if (macroSubstitution != null) {
+                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
+                } else {
+                    tryCutOffRuntimeExceptionsAndErrors(methodCallTargetNode);
+                }
+            }
+        }
+        return graph.getMark();
+    }
+
+    private void lookupDoInline(final StructuredGraph graph, final PhaseContext phaseContext, CanonicalizerPhase canonicalizerPhase, MethodCallTargetNode methodCallTarget) {
+        List<Node> canonicalizerUsages = new ArrayList<>();
+        for (Node n : methodCallTarget.invoke().asNode().usages()) {
+            if (n instanceof Canonicalizable) {
+                canonicalizerUsages.add(n);
+            }
+        }
+        List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
+        Mark beforeInvokeMark = graph.getMark();
+        expandInvoke(methodCallTarget);
+        for (Node arg : argumentSnapshot) {
+            if (arg != null && arg.recordsUsages()) {
+                for (Node argUsage : arg.usages()) {
+                    if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
+                        canonicalizerUsages.add(argUsage);
+                    }
+                }
+            }
+        }
+        canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages);
     }
 
     private void expandInvoke(MethodCallTargetNode methodCallTargetNode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed Jul 30 10:39:39 2014 -0700
@@ -78,10 +78,8 @@
         this.suites = backend.getSuites().getDefaultSuites();
 
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
-        GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault();
-        eagerConfig.setSkippedExceptionTypes(skippedExceptionTypes);
-        this.config = GraphBuilderConfiguration.getDefault();
-        this.config.setSkippedExceptionTypes(skippedExceptionTypes);
+        GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
+        this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes);
 
         this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations);
 
@@ -143,22 +141,27 @@
         }
 
         if (TraceTruffleCompilation.getValue()) {
-            int calls = OptimizedCallUtils.countCalls(compilable);
-            int inlinedCalls = OptimizedCallUtils.countCallsInlined(compilable);
-            int dispatchedCalls = calls - inlinedCalls;
-            Map<String, Object> properties = new LinkedHashMap<>();
-            OptimizedCallTargetLog.addASTSizeProperty(compilable, properties);
-            properties.put("Time", String.format("%5.0f(%4.0f+%-4.0f)ms", //
-                            (timeCompilationFinished - timeCompilationStarted) / 1e6, //
-                            (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, //
-                            (timeCompilationFinished - timePartialEvaluationFinished) / 1e6));
-            properties.put("CallNodes", String.format("I %5d/D %5d", inlinedCalls, dispatchedCalls));
-            properties.put("GraalNodes", String.format("%5d/%5d", nodeCountPartialEval, nodeCountLowered));
-            properties.put("CodeSize", compilationResult.getTargetCodeSize());
-            properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection()));
+            printTruffleCompilation(compilable, timeCompilationStarted, timePartialEvaluationFinished, nodeCountPartialEval, compilationResult, timeCompilationFinished, nodeCountLowered);
+        }
+    }
 
-            OptimizedCallTargetLog.logOptimizingDone(compilable, properties);
-        }
+    private static void printTruffleCompilation(final OptimizedCallTarget compilable, long timeCompilationStarted, long timePartialEvaluationFinished, int nodeCountPartialEval,
+                    CompilationResult compilationResult, long timeCompilationFinished, int nodeCountLowered) {
+        int calls = OptimizedCallUtils.countCalls(compilable);
+        int inlinedCalls = OptimizedCallUtils.countCallsInlined(compilable);
+        int dispatchedCalls = calls - inlinedCalls;
+        Map<String, Object> properties = new LinkedHashMap<>();
+        OptimizedCallTargetLog.addASTSizeProperty(compilable, properties);
+        properties.put("Time", String.format("%5.0f(%4.0f+%-4.0f)ms", //
+                        (timeCompilationFinished - timeCompilationStarted) / 1e6, //
+                        (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, //
+                        (timeCompilationFinished - timePartialEvaluationFinished) / 1e6));
+        properties.put("CallNodes", String.format("I %5d/D %5d", inlinedCalls, dispatchedCalls));
+        properties.put("GraalNodes", String.format("%5d/%5d", nodeCountPartialEval, nodeCountLowered));
+        properties.put("CodeSize", compilationResult.getTargetCodeSize());
+        properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection()));
+
+        OptimizedCallTargetLog.logOptimizingDone(compilable, properties);
     }
 
     private static String formatSourceSection(SourceSection sourceSection) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Wed Jul 30 10:39:39 2014 -0700
@@ -119,6 +119,8 @@
     public static final OptionValue<Boolean> TraceTruffleInlining = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleSplitting = new OptionValue<>(false);
+    @Option(help = "Print stack trace on transfer to interpreter")
+    public static final OptionValue<Boolean> TraceTruffleTransferToInterpreter = new StableOptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> TruffleCallTargetProfiling = new StableOptionValue<>(false);
     // @formatter:on
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -54,19 +54,7 @@
             return new IntegerAddExactNode(forY, forX);
         }
         if (forX.isConstant()) {
-            Constant xConst = forX.asConstant();
-            Constant yConst = forY.asConstant();
-            assert xConst.getKind() == yConst.getKind();
-            try {
-                if (xConst.getKind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.addExact(xConst.asInt(), yConst.asInt()));
-                } else {
-                    assert xConst.getKind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.addExact(xConst.asLong(), yConst.asLong()));
-                }
-            } catch (ArithmeticException ex) {
-                // The operation will result in an overflow exception, so do not canonicalize.
-            }
+            return canonicalXconstant(forX, forY);
         } else if (forY.isConstant()) {
             long c = forY.asConstant().asLong();
             if (c == 0) {
@@ -76,6 +64,23 @@
         return this;
     }
 
+    private ValueNode canonicalXconstant(ValueNode forX, ValueNode forY) {
+        Constant xConst = forX.asConstant();
+        Constant yConst = forY.asConstant();
+        assert xConst.getKind() == yConst.getKind();
+        try {
+            if (xConst.getKind() == Kind.Int) {
+                return ConstantNode.forInt(ExactMath.addExact(xConst.asInt(), yConst.asInt()));
+            } else {
+                assert xConst.getKind() == Kind.Long;
+                return ConstantNode.forLong(ExactMath.addExact(xConst.asLong(), yConst.asLong()));
+            }
+        } catch (ArithmeticException ex) {
+            // The operation will result in an overflow exception, so do not canonicalize.
+        }
+        return this;
+    }
+
     @Override
     public IntegerExactArithmeticSplitNode createSplit(BeginNode next, BeginNode deopt) {
         return graph().add(new IntegerAddExactSplitNode(stamp(), getX(), getY(), next, deopt));
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -48,11 +48,6 @@
         return successor == next ? 1 : 0;
     }
 
-    @Override
-    public void setProbability(BeginNode successor, double value) {
-        assert probability(successor) == value;
-    }
-
     public BeginNode getNext() {
         return next;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -47,19 +47,7 @@
             return new IntegerMulExactNode(forY, forX);
         }
         if (forX.isConstant()) {
-            Constant xConst = forX.asConstant();
-            Constant yConst = forY.asConstant();
-            assert xConst.getKind() == yConst.getKind();
-            try {
-                if (xConst.getKind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.multiplyExact(xConst.asInt(), yConst.asInt()));
-                } else {
-                    assert xConst.getKind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.multiplyExact(xConst.asLong(), yConst.asLong()));
-                }
-            } catch (ArithmeticException ex) {
-                // The operation will result in an overflow exception, so do not canonicalize.
-            }
+            return canonicalXconstant(forX, forY);
         } else if (forY.isConstant()) {
             long c = forY.asConstant().asLong();
             if (c == 1) {
@@ -72,6 +60,23 @@
         return this;
     }
 
+    private ValueNode canonicalXconstant(ValueNode forX, ValueNode forY) {
+        Constant xConst = forX.asConstant();
+        Constant yConst = forY.asConstant();
+        assert xConst.getKind() == yConst.getKind();
+        try {
+            if (xConst.getKind() == Kind.Int) {
+                return ConstantNode.forInt(ExactMath.multiplyExact(xConst.asInt(), yConst.asInt()));
+            } else {
+                assert xConst.getKind() == Kind.Long;
+                return ConstantNode.forLong(ExactMath.multiplyExact(xConst.asLong(), yConst.asLong()));
+            }
+        } catch (ArithmeticException ex) {
+            // The operation will result in an overflow exception, so do not canonicalize.
+        }
+        return this;
+    }
+
     @Override
     public IntegerExactArithmeticSplitNode createSplit(BeginNode next, BeginNode deopt) {
         return graph().add(new IntegerMulExactSplitNode(stamp(), getX(), getY(), next, deopt));
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -55,19 +55,7 @@
             return ConstantNode.forIntegerStamp(stamp(), 0);
         }
         if (forX.isConstant() && forY.isConstant()) {
-            Constant xConst = forX.asConstant();
-            Constant yConst = forY.asConstant();
-            assert xConst.getKind() == yConst.getKind();
-            try {
-                if (xConst.getKind() == Kind.Int) {
-                    return ConstantNode.forInt(ExactMath.subtractExact(xConst.asInt(), yConst.asInt()));
-                } else {
-                    assert xConst.getKind() == Kind.Long;
-                    return ConstantNode.forLong(ExactMath.subtractExact(xConst.asLong(), yConst.asLong()));
-                }
-            } catch (ArithmeticException ex) {
-                // The operation will result in an overflow exception, so do not canonicalize.
-            }
+            return canonicalXYconstant(forX, forY);
         } else if (forY.isConstant()) {
             long c = forY.asConstant().asLong();
             if (c == 0) {
@@ -77,6 +65,23 @@
         return this;
     }
 
+    private ValueNode canonicalXYconstant(ValueNode forX, ValueNode forY) {
+        Constant xConst = forX.asConstant();
+        Constant yConst = forY.asConstant();
+        assert xConst.getKind() == yConst.getKind();
+        try {
+            if (xConst.getKind() == Kind.Int) {
+                return ConstantNode.forInt(ExactMath.subtractExact(xConst.asInt(), yConst.asInt()));
+            } else {
+                assert xConst.getKind() == Kind.Long;
+                return ConstantNode.forLong(ExactMath.subtractExact(xConst.asLong(), yConst.asLong()));
+            }
+        } catch (ArithmeticException ex) {
+            // The operation will result in an overflow exception, so do not canonicalize.
+        }
+        return this;
+    }
+
     @Override
     public IntegerExactArithmeticSplitNode createSplit(BeginNode next, BeginNode deopt) {
         return graph().add(new IntegerSubExactSplitNode(stamp(), getX(), getY(), next, deopt));
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -24,11 +24,9 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class NeverPartOfCompilationNode extends MacroNode implements IterableNodeType {
+public class NeverPartOfCompilationNode extends MacroStateSplitNode implements IterableNodeType {
 
     private final String message;
 
@@ -44,9 +42,4 @@
     public final String getMessage() {
         return message + " " + arguments.toString();
     }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        throw GraphUtil.approxSourceException(this, new VerificationError(getMessage()));
-    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -35,9 +35,6 @@
  * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean)}.
  */
 public class CustomizedUnsafeStoreMacroNode extends NeverPartOfCompilationNode implements Canonicalizable, StateSplit {
-
-    @Input(InputType.State) private FrameState stateAfter;
-
     private static final int ARGUMENT_COUNT = 4;
     private static final int OBJECT_ARGUMENT_INDEX = 0;
     private static final int OFFSET_ARGUMENT_INDEX = 1;
@@ -47,7 +44,6 @@
     public CustomizedUnsafeStoreMacroNode(Invoke invoke) {
         super(invoke, "The location argument could not be resolved to a constant.");
         assert arguments.size() == ARGUMENT_COUNT;
-        this.stateAfter = invoke.stateAfter();
     }
 
     @Override
@@ -64,21 +60,8 @@
                 locationIdentity = ObjectLocationIdentity.create(locationArgument.asConstant());
             }
 
-            return new UnsafeStoreNode(objectArgument, offsetArgument, valueArgument, this.getTargetMethod().getSignature().getParameterKind(VALUE_ARGUMENT_INDEX), locationIdentity, stateAfter);
+            return new UnsafeStoreNode(objectArgument, offsetArgument, valueArgument, this.getTargetMethod().getSignature().getParameterKind(VALUE_ARGUMENT_INDEX), locationIdentity, stateAfter());
         }
         return this;
     }
-
-    @Override
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        this.stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
-        return true;
-    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -24,8 +24,8 @@
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.inlining.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Wed Jul 30 10:39:39 2014 -0700
@@ -41,12 +41,12 @@
 
     @MethodSubstitution
     public static void transferToInterpreter() {
-        DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.UnreachedCode);
+        DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter);
     }
 
     @MethodSubstitution
     public static void transferToInterpreterAndInvalidate() {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.UnreachedCode);
+        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter);
     }
 
     @MethodSubstitution
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Wed Jul 30 10:39:39 2014 -0700
@@ -33,32 +33,32 @@
  */
 public final class VirtualObjectState extends EscapeObjectState implements Node.ValueNumberable {
 
-    @Input private final NodeInputList<ValueNode> fieldValues;
+    @Input private final NodeInputList<ValueNode> values;
 
-    public NodeInputList<ValueNode> fieldValues() {
-        return fieldValues;
+    public NodeInputList<ValueNode> values() {
+        return values;
     }
 
-    public VirtualObjectState(VirtualObjectNode object, ValueNode[] fieldValues) {
+    public VirtualObjectState(VirtualObjectNode object, ValueNode[] values) {
         super(object);
-        assert object.entryCount() == fieldValues.length;
-        this.fieldValues = new NodeInputList<>(this, fieldValues);
+        assert object.entryCount() == values.length;
+        this.values = new NodeInputList<>(this, values);
     }
 
-    public VirtualObjectState(VirtualObjectNode object, List<ValueNode> fieldValues) {
+    public VirtualObjectState(VirtualObjectNode object, List<ValueNode> values) {
         super(object);
-        assert object.entryCount() == fieldValues.size();
-        this.fieldValues = new NodeInputList<>(this, fieldValues);
+        assert object.entryCount() == values.size();
+        this.values = new NodeInputList<>(this, values);
     }
 
     @Override
     public VirtualObjectState duplicateWithVirtualState() {
-        return graph().addWithoutUnique(new VirtualObjectState(object(), fieldValues));
+        return graph().addWithoutUnique(new VirtualObjectState(object(), values));
     }
 
     @Override
     public void applyToNonVirtual(NodeClosure<? super ValueNode> closure) {
-        for (ValueNode value : fieldValues) {
+        for (ValueNode value : values) {
             closure.apply(this, value);
         }
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Wed Jul 30 10:39:39 2014 -0700
@@ -82,7 +82,7 @@
                     Debug.log(" ==== effects for %s", context);
                     effects.apply(graph, obsoleteNodes);
                     if (TraceEscapeAnalysis.getValue()) {
-                        Debug.dump(graph, EffectsClosure.this.getClass().getSimpleName() + " - after processing %s", context);
+                        Debug.dump(5, graph, "After processing EffectsList for %s", context);
                     }
                 }
             }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Jul 30 10:39:39 2014 -0700
@@ -38,7 +38,8 @@
     }
 
     public void addCounterAfter(final String group, final String name, final int increment, final boolean addContext, final FixedWithNextNode position) {
-        add("add counter after", graph -> DynamicCounterNode.addCounterBefore(group, name, increment, addContext, position.next()));
+        FixedNode nextPosition = position.next();
+        add("add counter after", graph -> DynamicCounterNode.addCounterBefore(group, name, increment, addContext, nextPosition));
     }
 
     public void addWeakCounterCounterBefore(final String group, final String name, final int increment, final boolean addContext, final ValueNode checkedValue, final FixedNode position) {
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -185,7 +185,7 @@
 
         Invoke invoke = callTargetNode.invoke();
         if (!callTargetNode.isStatic()) {
-            assert callTargetNode.receiver().getKind() == wordKind : "changeToWord() missed the receiver";
+            assert callTargetNode.receiver().getKind() == wordKind : "changeToWord() missed the receiver " + callTargetNode.receiver();
             targetMethod = wordImplType.resolveMethod(targetMethod, invoke.getContextType());
         }
         Operation operation = targetMethod.getAnnotation(Word.Operation.class);
@@ -355,7 +355,7 @@
         if (condition == Condition.EQ || condition == Condition.NE) {
             comparison = new IntegerEqualsNode(a, b);
         } else if (condition.isUnsigned()) {
-            comparison = new IntegerBelowThanNode(a, b);
+            comparison = new IntegerBelowNode(a, b);
         } else {
             comparison = new IntegerLessThanNode(a, b);
         }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Wed Jul 30 10:39:39 2014 -0700
@@ -73,9 +73,7 @@
                 } else if (usage instanceof StoreFieldNode) {
                     verify(!isWord(node) || ((StoreFieldNode) usage).object() != node, node, usage, "cannot store to word value");
                 } else if (usage instanceof CheckCastNode) {
-                    boolean expectWord = isWord(node);
-                    verify(isWord(node) == expectWord, node, usage, "word cannot be cast to object, and vice versa");
-                    verify(isWord(((CheckCastNode) usage).type()) == expectWord, node, usage, "word cannot be cast to object, and vice versa");
+                    verify(isWord(((CheckCastNode) usage).type()) == isWord(node), node, usage, "word cannot be cast to object, and vice versa");
                 } else if (usage instanceof LoadIndexedNode) {
                     verify(!isWord(node) || ((LoadIndexedNode) usage).array() != node, node, usage, "cannot load from word value");
                     verify(!isWord(node) || ((LoadIndexedNode) usage).index() != node, node, usage, "cannot use word value as index");
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -95,4 +95,50 @@
             return 21;
         }
     }
+
+    @Test
+    public void testMultipleChildrenFields() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestChildNode firstChild = new TestChildNode();
+        TestChildNode secondChild = new TestChildNode();
+        TestChildNode thirdChild = new TestChildNode();
+        TestChildNode forthChild = new TestChildNode();
+        TestRootNode rootNode = new TestRoot2Node(new TestChildNode[]{firstChild, secondChild}, new TestChildNode[]{thirdChild, forthChild});
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Assert.assertEquals(rootNode, firstChild.getParent());
+        Assert.assertEquals(rootNode, secondChild.getParent());
+        Assert.assertEquals(rootNode, thirdChild.getParent());
+        Assert.assertEquals(rootNode, forthChild.getParent());
+        Iterator<Node> iterator = rootNode.getChildren().iterator();
+        Assert.assertEquals(firstChild, iterator.next());
+        Assert.assertEquals(secondChild, iterator.next());
+        Assert.assertEquals(thirdChild, iterator.next());
+        Assert.assertEquals(forthChild, iterator.next());
+        Assert.assertFalse(iterator.hasNext());
+        Object result = target.call();
+        Assert.assertEquals(2 * 42, result);
+    }
+
+    class TestRoot2Node extends TestRootNode {
+        @Children private final TestChildNode[] children1;
+        @Children private final TestChildNode[] children2;
+
+        public TestRoot2Node(TestChildNode[] children1, TestChildNode[] children2) {
+            super(new TestChildNode[0]);
+            this.children1 = children1;
+            this.children2 = children2;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            int sum = 0;
+            for (int i = 0; i < children1.length; ++i) {
+                sum += children1[i].execute();
+            }
+            for (int i = 0; i < children2.length; ++i) {
+                sum += children2[i].execute();
+            }
+            return sum;
+        }
+    }
 }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java	Wed Jul 30 10:39:39 2014 -0700
@@ -40,6 +40,7 @@
 public class ThreadSafetyTest {
 
     @Test
+    @Ignore("sporadic failures with \"expected:<1000000> but was:<999999>\"")
     public void test() throws InterruptedException {
         TruffleRuntime runtime = Truffle.getRuntime();
         TestRootNode rootNode1 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new ConstNode(42)))))));
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Wed Jul 30 10:39:39 2014 -0700
@@ -65,6 +65,9 @@
      * insert a transfer to the interpreter.
      */
     public static void transferToInterpreter() {
+        if (inInterpreter()) {
+            Truffle.getRuntime().notifyTransferToInterpreter();
+        }
     }
 
     /**
@@ -72,6 +75,9 @@
      * insert a transfer to the interpreter, invalidating the currently executing machine code.
      */
     public static void transferToInterpreterAndInvalidate() {
+        if (inInterpreter()) {
+            Truffle.getRuntime().notifyTransferToInterpreter();
+        }
     }
 
     /**
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Wed Jul 30 10:39:39 2014 -0700
@@ -109,9 +109,21 @@
      * {@link CallTarget}s. Iteration starts at the caller frame, i.e., it does not include the
      * current frame.
      *
-     * @return a lazy collection of {@link FrameInstance}.
+     * Iteration continues as long as {@link FrameInstanceVisitor#visitFrame}, which is invoked for
+     * every {@link FrameInstance}, returns null. Any non-null result of the visitor indicates that
+     * frame iteration should stop.
+     *
+     * @param visitor the visitor that is called for every matching frame.
+     * @return the last result returned by the visitor (which is non-null to indicate that iteration
+     *         should stop), or null if the whole stack was iterated.
      */
-    Iterable<FrameInstance> getStackTrace();
+    <T> T iterateFrames(FrameInstanceVisitor<T> visitor);
+
+    /**
+     * Accesses the caller frame. This is a convenience method that returns the first frame that is
+     * passed to the visitor of {@link #iterateFrames}.
+     */
+    FrameInstance getCallerFrame();
 
     /**
      * Accesses the current frame, i.e., the frame of the closest {@link CallTarget}. It is
@@ -119,4 +131,8 @@
      */
     FrameInstance getCurrentFrame();
 
+    /**
+     * Internal API method. Do not use.
+     */
+    void notifyTransferToInterpreter();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstanceVisitor.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.frame;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Callback interface for {@link TruffleRuntime#iterateFrames}. Implementations of
+ * {@link #visitFrame} return null to indicate that frame iteration should continue and the next
+ * caller frame should be visited; and return any non-null value to indicate that frame iteration
+ * should stop.
+ */
+public interface FrameInstanceVisitor<T> {
+
+    T visitFrame(FrameInstance frameInstance);
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Wed Jul 30 10:39:39 2014 -0700
@@ -114,11 +114,28 @@
         getThreadLocalStackTrace().removeFirst();
     }
 
-    public Iterable<FrameInstance> getStackTrace() {
-        return getThreadLocalStackTrace();
+    @Override
+    public <T> T iterateFrames(FrameInstanceVisitor<T> visitor) {
+        T result = null;
+        for (FrameInstance frameInstance : getThreadLocalStackTrace()) {
+            result = visitor.visitFrame(frameInstance);
+            if (result != null) {
+                return result;
+            }
+        }
+        return result;
     }
 
+    @Override
+    public FrameInstance getCallerFrame() {
+        return getThreadLocalStackTrace().peekFirst();
+    }
+
+    @Override
     public FrameInstance getCurrentFrame() {
         return currentFrames.get();
     }
+
+    public void notifyTransferToInterpreter() {
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java	Wed Jul 30 10:39:39 2014 -0700
@@ -56,7 +56,24 @@
     /**
      * Marker for a location where ordinary "stepping" should halt.
      */
-    STATEMENT("statement", "basic unit of the language, suitable for \"stepping\" in a debugger");
+    STATEMENT("statement", "basic unit of the language, suitable for \"stepping\" in a debugger"),
+
+    /**
+     * Marker for the start of the body of a method.
+     */
+    START_METHOD("start-method", "start of the body of a method"),
+
+    /**
+     * Marker for the start of the body of a loop.
+     */
+    START_LOOP("start-loop", "start of the body of a loop"),
+
+    /**
+     * Marker that is attached to some arbitrary locations that appear often-enough in an AST so
+     * that a location with this tag is regularly executed. Could be the start of method and loop
+     * bodies. May be used to implement some kind of safepoint functionality.
+     */
+    PERIODIC("periodic", "arbitrary locations that appear often-enough in an AST so that a location with this tag is regularly executed");
 
     private final String name;
     private final String description;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java	Wed Jul 30 10:39:39 2014 -0700
@@ -66,7 +66,6 @@
 
         p.print(nodeName(node));
 
-        String sep = "";
         p.print("(");
 
         final SourceSection src = node.getSourceSection();
@@ -76,15 +75,7 @@
             }
         }
         if (node instanceof SyntaxTagged) {
-            final SyntaxTagged taggedNode = (SyntaxTagged) node;
-            p.print("[");
-            String prefix = "";
-            for (SyntaxTag tag : taggedNode.getSyntaxTags()) {
-                p.print(prefix);
-                prefix = ",";
-                p.print(tag.toString());
-            }
-            p.print("]");
+            printSyntaxTagged(p, (SyntaxTagged) node);
         }
 
         ArrayList<NodeField> childFields = new ArrayList<>();
@@ -119,23 +110,9 @@
                         p.print(field.getName());
                         p.print(" = null ");
                     } else if (field.getKind() == NodeFieldKind.CHILD) {
-                        final Node valueNode = (Node) value;
-                        printNewLine(p, level, valueNode == markNode);
-                        p.print(field.getName());
-                        p.print(" = ");
-                        printTree(p, valueNode, maxDepth, markNode, level + 1);
+                        printChild(p, maxDepth, markNode, level, field, value);
                     } else if (field.getKind() == NodeFieldKind.CHILDREN) {
-                        printNewLine(p, level);
-                        p.print(field.getName());
-                        Node[] children = (Node[]) value;
-                        p.print(" = [");
-                        sep = "";
-                        for (Node child : children) {
-                            p.print(sep);
-                            sep = ", ";
-                            printTree(p, child, maxDepth, markNode, level + 1);
-                        }
-                        p.print("]");
+                        printChildren(p, maxDepth, markNode, level, field, value);
                     } else {
                         printNewLine(p, level);
                         p.print(field.getName());
@@ -147,6 +124,39 @@
         }
     }
 
+    private static void printSyntaxTagged(PrintWriter p, final SyntaxTagged taggedNode) {
+        p.print("[");
+        String prefix = "";
+        for (SyntaxTag tag : taggedNode.getSyntaxTags()) {
+            p.print(prefix);
+            prefix = ",";
+            p.print(tag.toString());
+        }
+        p.print("]");
+    }
+
+    private static void printChildren(PrintWriter p, int maxDepth, Node markNode, int level, NodeField field, Object value) {
+        printNewLine(p, level);
+        p.print(field.getName());
+        Node[] children = (Node[]) value;
+        p.print(" = [");
+        String sep = "";
+        for (Node child : children) {
+            p.print(sep);
+            sep = ", ";
+            printTree(p, child, maxDepth, markNode, level + 1);
+        }
+        p.print("]");
+    }
+
+    private static void printChild(PrintWriter p, int maxDepth, Node markNode, int level, NodeField field, Object value) {
+        final Node valueNode = (Node) value;
+        printNewLine(p, level, valueNode == markNode);
+        p.print(field.getName());
+        p.print(" = ");
+        printTree(p, valueNode, maxDepth, markNode, level + 1);
+    }
+
     private static void printNewLine(PrintWriter p, int level, boolean mark) {
         p.println();
         for (int i = 0; i < level; i++) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Jul 30 10:39:39 2014 -0700
@@ -252,53 +252,58 @@
 
         private final class NodeIterator implements Iterator<Node> {
             private final Node node;
-            private int fieldIndex;
-            private int arrayIndex;
+            private final int childrenCount;
+            private int index;
 
             protected NodeIterator(Node node) {
                 this.node = node;
+                this.index = 0;
+                this.childrenCount = childrenCount();
+            }
+
+            private int childrenCount() {
+                int nodeCount = childOffsets.length;
+                for (long fieldOffset : childrenOffsets) {
+                    Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset));
+                    if (children != null) {
+                        nodeCount += children.length;
+                    }
+                }
+                return nodeCount;
+            }
+
+            private Node nodeAt(int idx) {
+                int nodeCount = childOffsets.length;
+                if (idx < nodeCount) {
+                    return (Node) unsafe.getObject(node, childOffsets[idx]);
+                } else {
+                    for (long fieldOffset : childrenOffsets) {
+                        Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset);
+                        if (idx < nodeCount + nodeArray.length) {
+                            return nodeArray[idx - nodeCount];
+                        }
+                        nodeCount += nodeArray.length;
+                    }
+                }
+                return null;
             }
 
             private void forward() {
-                if (fieldIndex < childOffsets.length) {
-                    fieldIndex++;
-                } else if (fieldIndex < childOffsets.length + childrenOffsets.length) {
-                    if (arrayIndex + 1 < currentChildrenArrayLength()) {
-                        arrayIndex++;
-                    } else {
-                        arrayIndex = 0;
-                        do {
-                            fieldIndex++;
-                        } while (fieldIndex < childOffsets.length + childrenOffsets.length && currentChildrenArrayLength() == 0);
-                    }
+                if (index < childrenCount) {
+                    index++;
                 }
             }
 
             public boolean hasNext() {
-                return fieldIndex < childOffsets.length || (fieldIndex < childOffsets.length + childrenOffsets.length && arrayIndex < currentChildrenArrayLength());
-            }
-
-            private Node[] currentChildrenArray() {
-                assert fieldIndex >= childOffsets.length && fieldIndex < childOffsets.length + childrenOffsets.length;
-                return (Node[]) unsafe.getObject(node, childrenOffsets[fieldIndex - childOffsets.length]);
-            }
-
-            private int currentChildrenArrayLength() {
-                Node[] childrenArray = currentChildrenArray();
-                return childrenArray != null ? childrenArray.length : 0;
+                return index < childrenCount;
             }
 
             public Node next() {
-                Node next;
-                if (fieldIndex < childOffsets.length) {
-                    next = (Node) unsafe.getObject(node, childOffsets[fieldIndex]);
-                } else if (fieldIndex < childOffsets.length + childrenOffsets.length) {
-                    next = currentChildrenArray()[arrayIndex];
-                } else {
-                    throw new NoSuchElementException();
+                try {
+                    return nodeAt(index);
+                } finally {
+                    forward();
                 }
-                forward();
-                return next;
             }
 
             public void remove() {
@@ -795,15 +800,7 @@
                     p.print(" = ");
                     printTree(p, (Node) value, level + 1);
                 } else if (field.getKind() == NodeFieldKind.CHILDREN) {
-                    Node[] children = (Node[]) value;
-                    p.print(" = [");
-                    sep = "";
-                    for (Node child : children) {
-                        p.print(sep);
-                        sep = ", ";
-                        printTree(p, child, level + 1);
-                    }
-                    p.print("]");
+                    printChildren(p, level, value);
                 }
             }
             printNewLine(p, level - 1);
@@ -811,6 +808,19 @@
         }
     }
 
+    private static void printChildren(PrintWriter p, int level, Object value) {
+        String sep;
+        Node[] children = (Node[]) value;
+        p.print(" = [");
+        sep = "";
+        for (Node child : children) {
+            p.print(sep);
+            sep = ", ";
+            printTree(p, child, level + 1);
+        }
+        p.print("]");
+    }
+
     private static void printNewLine(PrintWriter p, int level) {
         p.println();
         for (int i = 0; i < level; i++) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderDeserializer.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderDeserializer.java	Wed Jul 30 10:39:39 2014 -0700
@@ -171,66 +171,74 @@
 
                 int cpi = buffer.get();
                 if (cpi == VariableLengthIntBuffer.NULL) {
-                    if (fieldClass == int.class) {
-                        unsafe.putInt(nodeInstance, offset, 0);
-                    } else if (fieldClass == long.class) {
-                        unsafe.putLong(nodeInstance, offset, 0L);
-                    } else if (fieldClass == float.class) {
-                        unsafe.putFloat(nodeInstance, offset, 0.0F);
-                    } else if (fieldClass == double.class) {
-                        unsafe.putDouble(nodeInstance, offset, 0.0D);
-                    } else if (fieldClass == byte.class) {
-                        unsafe.putByte(nodeInstance, offset, (byte) 0);
-                    } else if (fieldClass == short.class) {
-                        unsafe.putShort(nodeInstance, offset, (short) 0);
-                    } else if (fieldClass == char.class) {
-                        unsafe.putChar(nodeInstance, offset, (char) 0);
-                    } else if (fieldClass == boolean.class) {
-                        unsafe.putBoolean(nodeInstance, offset, false);
-                    } else {
-                        unsafe.putObject(nodeInstance, offset, null);
-                    }
+                    deserializeDataFieldsLengthNull(nodeInstance, fieldClass, offset);
                 } else {
-                    if (fieldClass == int.class) {
-                        unsafe.putInt(nodeInstance, offset, cp.getInt(cpi));
-                    } else if (fieldClass == long.class) {
-                        unsafe.putLong(nodeInstance, offset, cp.getLong(cpi));
-                    } else if (fieldClass == float.class) {
-                        unsafe.putFloat(nodeInstance, offset, cp.getFloat(cpi));
-                    } else if (fieldClass == double.class) {
-                        unsafe.putDouble(nodeInstance, offset, cp.getDouble(cpi));
-                    } else if (fieldClass == byte.class) {
-                        unsafe.putByte(nodeInstance, offset, (byte) cp.getInt(cpi));
-                    } else if (fieldClass == short.class) {
-                        unsafe.putShort(nodeInstance, offset, (short) cp.getInt(cpi));
-                    } else if (fieldClass == char.class) {
-                        unsafe.putChar(nodeInstance, offset, (char) cp.getInt(cpi));
-                    } else if (fieldClass == boolean.class) {
-                        unsafe.putBoolean(nodeInstance, offset, cp.getInt(cpi) == 1 ? true : false);
-                    } else if (fieldClass == Integer.class) {
-                        unsafe.putObject(nodeInstance, offset, cp.getInt(cpi));
-                    } else if (fieldClass == Long.class) {
-                        unsafe.putObject(nodeInstance, offset, cp.getLong(cpi));
-                    } else if (fieldClass == Float.class) {
-                        unsafe.putObject(nodeInstance, offset, cp.getFloat(cpi));
-                    } else if (fieldClass == Double.class) {
-                        unsafe.putObject(nodeInstance, offset, cp.getDouble(cpi));
-                    } else if (fieldClass == Byte.class) {
-                        unsafe.putObject(nodeInstance, offset, (byte) cp.getInt(cpi));
-                    } else if (fieldClass == Short.class) {
-                        unsafe.putObject(nodeInstance, offset, (short) cp.getInt(cpi));
-                    } else if (fieldClass == Character.class) {
-                        unsafe.putObject(nodeInstance, offset, (char) cp.getInt(cpi));
-                    } else if (fieldClass == Boolean.class) {
-                        unsafe.putObject(nodeInstance, offset, cp.getInt(cpi) == 1 ? Boolean.TRUE : Boolean.FALSE);
-                    } else {
-                        unsafe.putObject(nodeInstance, offset, cp.getObject(fieldClass, cpi));
-                    }
+                    deserializeDataFieldsDefault(nodeInstance, fieldClass, offset, cpi);
                 }
             }
         }
     }
 
+    private void deserializeDataFieldsDefault(Node nodeInstance, Class<?> fieldClass, long offset, int cpi) {
+        if (fieldClass == int.class) {
+            unsafe.putInt(nodeInstance, offset, cp.getInt(cpi));
+        } else if (fieldClass == long.class) {
+            unsafe.putLong(nodeInstance, offset, cp.getLong(cpi));
+        } else if (fieldClass == float.class) {
+            unsafe.putFloat(nodeInstance, offset, cp.getFloat(cpi));
+        } else if (fieldClass == double.class) {
+            unsafe.putDouble(nodeInstance, offset, cp.getDouble(cpi));
+        } else if (fieldClass == byte.class) {
+            unsafe.putByte(nodeInstance, offset, (byte) cp.getInt(cpi));
+        } else if (fieldClass == short.class) {
+            unsafe.putShort(nodeInstance, offset, (short) cp.getInt(cpi));
+        } else if (fieldClass == char.class) {
+            unsafe.putChar(nodeInstance, offset, (char) cp.getInt(cpi));
+        } else if (fieldClass == boolean.class) {
+            unsafe.putBoolean(nodeInstance, offset, cp.getInt(cpi) == 1 ? true : false);
+        } else if (fieldClass == Integer.class) {
+            unsafe.putObject(nodeInstance, offset, cp.getInt(cpi));
+        } else if (fieldClass == Long.class) {
+            unsafe.putObject(nodeInstance, offset, cp.getLong(cpi));
+        } else if (fieldClass == Float.class) {
+            unsafe.putObject(nodeInstance, offset, cp.getFloat(cpi));
+        } else if (fieldClass == Double.class) {
+            unsafe.putObject(nodeInstance, offset, cp.getDouble(cpi));
+        } else if (fieldClass == Byte.class) {
+            unsafe.putObject(nodeInstance, offset, (byte) cp.getInt(cpi));
+        } else if (fieldClass == Short.class) {
+            unsafe.putObject(nodeInstance, offset, (short) cp.getInt(cpi));
+        } else if (fieldClass == Character.class) {
+            unsafe.putObject(nodeInstance, offset, (char) cp.getInt(cpi));
+        } else if (fieldClass == Boolean.class) {
+            unsafe.putObject(nodeInstance, offset, cp.getInt(cpi) == 1 ? Boolean.TRUE : Boolean.FALSE);
+        } else {
+            unsafe.putObject(nodeInstance, offset, cp.getObject(fieldClass, cpi));
+        }
+    }
+
+    private static void deserializeDataFieldsLengthNull(Node nodeInstance, Class<?> fieldClass, long offset) {
+        if (fieldClass == int.class) {
+            unsafe.putInt(nodeInstance, offset, 0);
+        } else if (fieldClass == long.class) {
+            unsafe.putLong(nodeInstance, offset, 0L);
+        } else if (fieldClass == float.class) {
+            unsafe.putFloat(nodeInstance, offset, 0.0F);
+        } else if (fieldClass == double.class) {
+            unsafe.putDouble(nodeInstance, offset, 0.0D);
+        } else if (fieldClass == byte.class) {
+            unsafe.putByte(nodeInstance, offset, (byte) 0);
+        } else if (fieldClass == short.class) {
+            unsafe.putShort(nodeInstance, offset, (short) 0);
+        } else if (fieldClass == char.class) {
+            unsafe.putChar(nodeInstance, offset, (char) 0);
+        } else if (fieldClass == boolean.class) {
+            unsafe.putBoolean(nodeInstance, offset, false);
+        } else {
+            unsafe.putObject(nodeInstance, offset, null);
+        }
+    }
+
     private void deserializeChildFields(Node parent, NodeField[] nodeFields) {
         for (int i = nodeFields.length - 1; i >= 0; i--) {
             NodeField field = nodeFields[i];
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderSerializer.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderSerializer.java	Wed Jul 30 10:39:39 2014 -0700
@@ -115,28 +115,7 @@
                 } else if (fieldClass == boolean.class) {
                     cpi = cp.putInt(unsafe.getBoolean(node, offset) ? 1 : 0);
                 } else {
-                    Object value = unsafe.getObject(node, offset);
-                    if (value == null) {
-                        cpi = VariableLengthIntBuffer.NULL;
-                    } else if (fieldClass == Integer.class) {
-                        cpi = cp.putInt((Integer) value);
-                    } else if (fieldClass == Long.class) {
-                        cpi = cp.putLong((Long) value);
-                    } else if (fieldClass == Float.class) {
-                        cpi = cp.putFloat((Float) value);
-                    } else if (fieldClass == Double.class) {
-                        cpi = cp.putDouble((Double) value);
-                    } else if (fieldClass == Byte.class) {
-                        cpi = cp.putInt((Byte) value);
-                    } else if (fieldClass == Short.class) {
-                        cpi = cp.putInt((Short) value);
-                    } else if (fieldClass == Character.class) {
-                        cpi = cp.putInt((Character) value);
-                    } else if (fieldClass == Boolean.class) {
-                        cpi = cp.putInt((Boolean) value ? 1 : 0);
-                    } else {
-                        cpi = cp.putObject(fieldClass, value);
-                    }
+                    cpi = serializeDataFieldsObject(node, fieldClass, offset);
                 }
 
                 buffer.put(cpi);
@@ -144,6 +123,31 @@
         }
     }
 
+    private int serializeDataFieldsObject(Node node, Class<?> fieldClass, long offset) {
+        Object value = unsafe.getObject(node, offset);
+        if (value == null) {
+            return VariableLengthIntBuffer.NULL;
+        } else if (fieldClass == Integer.class) {
+            return cp.putInt((Integer) value);
+        } else if (fieldClass == Long.class) {
+            return cp.putLong((Long) value);
+        } else if (fieldClass == Float.class) {
+            return cp.putFloat((Float) value);
+        } else if (fieldClass == Double.class) {
+            return cp.putDouble((Double) value);
+        } else if (fieldClass == Byte.class) {
+            return cp.putInt((Byte) value);
+        } else if (fieldClass == Short.class) {
+            return cp.putInt((Short) value);
+        } else if (fieldClass == Character.class) {
+            return cp.putInt((Character) value);
+        } else if (fieldClass == Boolean.class) {
+            return cp.putInt((Boolean) value ? 1 : 0);
+        } else {
+            return cp.putObject(fieldClass, value);
+        }
+    }
+
     private void serializeChildrenFields(VariableLengthIntBuffer buffer, Node nodeInstance, NodeField[] nodeFields) throws UnsupportedConstantPoolTypeException {
         for (int i = 0; i < nodeFields.length; i++) {
             NodeField field = nodeFields[i];
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed Jul 30 10:39:39 2014 -0700
@@ -152,7 +152,7 @@
         if (sourceCallback != null) {
             sourceCallback.startLoading(source);
         }
-        Parser.parseSL(context, source);
+        Parser.parseSL(context, source, null);
         if (sourceCallback != null) {
             sourceCallback.endLoading(source);
         }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Wed Jul 30 10:39:39 2014 -0700
@@ -50,6 +50,6 @@
     private static void doDefineFunction(SLContext context, String code) {
         Source source = Source.fromText(code, "[defineFunction]");
         /* The same parsing code as for parsing the initial source. */
-        Parser.parseSL(context, source);
+        Parser.parseSL(context, source, null);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java	Wed Jul 30 10:39:39 2014 -0700
@@ -41,7 +41,7 @@
 
     @Specialization
     public String change() {
-        FrameInstance frameInstance = Truffle.getRuntime().getStackTrace().iterator().next();
+        FrameInstance frameInstance = Truffle.getRuntime().getCallerFrame();
         Frame frame = frameInstance.getFrame(FrameAccess.READ_WRITE, false);
         FrameSlot slot = frame.getFrameDescriptor().findOrAddFrameSlot("hello");
         frame.setObject(slot, "world");
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Wed Jul 30 10:39:39 2014 -0700
@@ -50,13 +50,11 @@
     @SlowPath
     private static String createStackTrace() {
         StringBuilder str = new StringBuilder();
-        Iterable<FrameInstance> frames = Truffle.getRuntime().getStackTrace();
 
-        if (frames != null) {
-            for (FrameInstance frame : frames) {
-                dumpFrame(str, frame.getCallTarget(), frame.getFrame(FrameAccess.READ_ONLY, true), frame.isVirtualFrame());
-            }
-        }
+        Truffle.getRuntime().iterateFrames(frameInstance -> {
+            dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true), frameInstance.isVirtualFrame());
+            return null;
+        });
         return str.toString();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.factory;
+
+import java.io.*;
+
+import com.oracle.truffle.sl.nodes.instrument.*;
+import com.oracle.truffle.sl.runtime.*;
+
+public final class SLContextFactory {
+
+    private static SLASTProber astProber;
+
+    private SLContextFactory() {
+
+    }
+
+    public static SLContext create() {
+        final SLContext slContext = new SLContext(new BufferedReader(new InputStreamReader(System.in)), System.out);
+        slContext.initialize();
+        slContext.setVisualizer(new SLDefaultVisualizer());
+        astProber = new SLASTProber();
+        slContext.setASTNodeProber(astProber);
+        return slContext;
+    }
+
+    public static void addNodeProber(SLNodeProber nodeProber) {
+        astProber.addNodeProber(nodeProber);
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Wed Jul 30 10:39:39 2014 -0700
@@ -42,4 +42,8 @@
      * Execute this node as as statement, where no return value is necessary.
      */
     public abstract void executeVoid(VirtualFrame frame);
+
+    public SLStatementNode getNonWrapperNode() {
+        return this;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTPrinter.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.instrument;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * SLASTPrinter is used to print for SL's internal Truffle AST. This is used by
+ * {@link SLDefaultVisualizer} to provide a means of displaying the internal Truffle AST
+ */
+public final class SLASTPrinter implements ASTPrinter {
+    public SLASTPrinter() {
+    }
+
+    public void printTree(PrintWriter p, Node node, int maxDepth, Node markNode) {
+        printTree(p, node, maxDepth, markNode, 1);
+        p.println();
+        p.flush();
+    }
+
+    public String printTreeToString(Node node, int maxDepth, Node markNode) {
+        StringWriter out = new StringWriter();
+        printTree(new PrintWriter(out), node, maxDepth, markNode);
+        return out.toString();
+    }
+
+    public String printTreeToString(Node node, int maxDepth) {
+        return printTreeToString(node, maxDepth, null);
+    }
+
+    private static void printTree(PrintWriter p, Node node, int maxDepth, Node markNode, int level) {
+        if (node == null) {
+            p.print("null");
+            return;
+        }
+
+        p.print(nodeName(node));
+
+        String sep = "";
+        p.print("(");
+
+        final SourceSection src = node.getSourceSection();
+        if (src != null) {
+            if (!(src instanceof NullSourceSection)) {
+                p.print(src.getSource().getName() + ":" + src.getStartLine());
+            } else if (src instanceof NullSourceSection) {
+                final NullSourceSection nullSection = (NullSourceSection) src;
+                p.print(nullSection.getShortDescription());
+            }
+        }
+        if (node instanceof SyntaxTagged) {
+            final SyntaxTagged taggedNode = (SyntaxTagged) node;
+            p.print("[");
+            String prefix = "";
+            for (SyntaxTag tag : taggedNode.getSyntaxTags()) {
+                p.print(prefix);
+                prefix = ",";
+                p.print(tag.toString());
+            }
+            p.print("]");
+        }
+
+        ArrayList<NodeField> childFields = new ArrayList<>();
+
+        for (NodeField field : NodeClass.get(node.getClass()).getFields()) {
+            if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
+                childFields.add(field);
+            } else if (field.getKind() == NodeFieldKind.DATA) {
+                // p.print(sep);
+                // sep = ", ";
+                //
+                // final String fieldName = field.getName();
+                // switch (fieldName) {
+                //
+                // }
+                // p.print(fieldName);
+                // p.print(" = ");
+                // p.print(field.loadValue(node));
+            }
+        }
+        p.print(")");
+
+        if (level <= maxDepth) {
+
+            if (childFields.size() != 0) {
+                p.print(" {");
+                for (NodeField field : childFields) {
+
+                    Object value = field.loadValue(node);
+                    if (value == null) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        p.print(" = null ");
+                    } else if (field.getKind() == NodeFieldKind.CHILD) {
+                        final Node valueNode = (Node) value;
+                        printNewLine(p, level, valueNode == markNode);
+                        p.print(field.getName());
+                        p.print(" = ");
+                        printTree(p, valueNode, maxDepth, markNode, level + 1);
+                    } else if (field.getKind() == NodeFieldKind.CHILDREN) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        Node[] children = (Node[]) value;
+                        p.print(" = [");
+                        sep = "";
+                        for (Node child : children) {
+                            p.print(sep);
+                            sep = ", ";
+                            printTree(p, child, maxDepth, markNode, level + 1);
+                        }
+                        p.print("]");
+                    } else {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                    }
+                }
+                printNewLine(p, level - 1);
+                p.print("}");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level, boolean mark) {
+        p.println();
+        for (int i = 0; i < level; i++) {
+            if (mark && i == 0) {
+                p.print(" -->");
+            } else {
+                p.print("    ");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level) {
+        printNewLine(p, level, false);
+    }
+
+    private static String nodeName(Node node) {
+        return node.getClass().getSimpleName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTProber.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.instrument;
+
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+
+/**
+ * SLASTProber contains the collection of {@link SLNodeProber}s and methods to attach the probers to
+ * nodes.
+ */
+public final class SLASTProber implements ASTProber, SLNodeProber {
+
+    private ArrayList<SLNodeProber> nodeProbers = new ArrayList<>();
+
+    public SLASTProber() {
+    }
+
+    /**
+     * Adds a {@link SLNodeProber} to this SLASTProber. Probes must be of type {@link SLNodeProber}
+     * and must not already have been added.
+     *
+     * @param nodeProber the {@link SLNodeProber} to add.
+     */
+    public void addNodeProber(ASTNodeProber nodeProber) {
+        if (nodeProber instanceof SLNodeProber) {
+            assert !nodeProbers.contains(nodeProber);
+            nodeProbers.add((SLNodeProber) nodeProber);
+        } else {
+            throw new IllegalArgumentException("invalid prober for SL implementation");
+        }
+    }
+
+    /**
+     * Unimplemented, does nothing.
+     */
+    public Node probeAs(Node astNode, SyntaxTag tag, Object... args) {
+        return astNode;
+    }
+
+    /**
+     * Attaches the current probers to the given {@link SLStatementNode} as a statement.
+     *
+     * @param node The {@link SLStatementNode} to attach the stored set of probers to.
+     */
+    @Override
+    public SLStatementNode probeAsStatement(SLStatementNode node) {
+        SLStatementNode result = node;
+        for (SLNodeProber nodeProber : nodeProbers) {
+            result = nodeProber.probeAsStatement(result);
+        }
+        return result;
+    }
+
+    /**
+     * Attaches the current probers to the given {@link SLExpressionNode} as a call. This will wrap
+     * the passed in node in an {@link SLExpressionWrapper}, tag it as a call and attach an
+     * instrument to it.
+     *
+     * @param node The {@link SLExpressionNode} to attach the stored set of probers to.
+     * @param callName The name of the call ???
+     *
+     */
+    @Override
+    public SLExpressionNode probeAsCall(SLExpressionNode node, String callName) {
+        SLExpressionNode result = node;
+        for (SLNodeProber nodeProber : nodeProbers) {
+            result = nodeProber.probeAsCall(node, callName);
+        }
+        return result;
+    }
+
+    /**
+     * Attaches the current probers to the given {@link SLExpressionNode} as an assignment. This
+     * will wrap the passed in node in an {@link SLExpressionWrapper}, tag it as an assignment and
+     * attach an instrument to it.
+     *
+     * @param node The {@link SLExpressionNode} to attached the stored set of probers to.
+     * @param localName The name of the assignment ???
+     *
+     */
+    @Override
+    public SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName) {
+        SLExpressionNode result = node;
+        for (SLNodeProber nodeProber : nodeProbers) {
+            result = nodeProber.probeAsLocalAssignment(result, localName);
+        }
+        return result;
+    }
+
+    public ASTNodeProber getCombinedNodeProber() {
+        return nodeProbers.isEmpty() ? null : this;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLDefaultVisualizer.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.instrument;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * SLDefaultVisualizer provides methods to get the names of SL's internal Truffle AST nodes.
+ *
+ */
+public class SLDefaultVisualizer extends DefaultVisualizer {
+
+    private final SLASTPrinter astPrinter;
+
+    public SLDefaultVisualizer() {
+        this.astPrinter = new SLASTPrinter();
+    }
+
+    @Override
+    public ASTPrinter getASTPrinter() {
+        return astPrinter;
+    }
+
+    @Override
+    public String displayMethodName(Node node) {
+
+        if (node == null) {
+            return null;
+        }
+        RootNode root = node.getRootNode();
+        if (root instanceof SLRootNode) {
+            SLRootNode slRootNode = (SLRootNode) root;
+            return slRootNode.toString();
+
+        }
+        return "unknown";
+    }
+
+    @Override
+    public String displayCallTargetName(CallTarget callTarget) {
+        if (callTarget instanceof RootCallTarget) {
+            final RootCallTarget rootCallTarget = (RootCallTarget) callTarget;
+            SLRootNode slRootNode = (SLRootNode) rootCallTarget.getRootNode();
+            return slRootNode.toString();
+        }
+        return callTarget.toString();
+    }
+
+    @Override
+    public String displayValue(ExecutionContext context, Object value) {
+        if (value == SLNull.SINGLETON) {
+            return "null";
+        }
+        return value.toString();
+    }
+
+    @Override
+    public String displayIdentifier(FrameSlot slot) {
+
+        final Object id = slot.getIdentifier();
+        return id.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.instrument;
+
+import java.math.*;
+
+import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * SLExpressionWrapper is a Truffle AST node that gets inserted as the parent to the node that it is
+ * wrapping. Any debugging instruments are attached to this wrapper through {@link Probe}s (which
+ * themselves contain the instruments. It is through this mechanism that tools can interact directly
+ * with the AST. <br/>
+ * {@link SLExpressionWrapper} specifically wraps {@link SLExpressionNode}s and overrides the
+ * various execute functions in {@link SLExpressionNode} to operate on the child of the wrapper
+ * instead of the wrapper itself.
+ *
+ */
+public final class SLExpressionWrapper extends SLExpressionNode implements Wrapper {
+    @Child private SLExpressionNode child;
+
+    private final Probe probe;
+
+    public SLExpressionWrapper(SLContext context, SLExpressionNode child) {
+        super(child.getSourceSection());
+        assert !(child instanceof SLExpressionWrapper);
+        this.child = insert(child);
+        this.probe = context.getProbe(child.getSourceSection());
+    }
+
+    @Override
+    public SLExpressionNode getNonWrapperNode() {
+        return child;
+    }
+
+    @Override
+    public Node getChild() {
+        return child;
+    }
+
+    @Override
+    public Probe getProbe() {
+        return probe;
+    }
+
+    @Override
+    @SlowPath
+    public boolean isTaggedAs(SyntaxTag tag) {
+        return probe.isTaggedAs(tag);
+    }
+
+    @Override
+    @SlowPath
+    public Iterable<SyntaxTag> getSyntaxTags() {
+        return probe.getSyntaxTags();
+    }
+
+    @SlowPath
+    public void tagAs(SyntaxTag tag) {
+        probe.tagAs(tag);
+    }
+
+    @Override
+    public Object executeGeneric(VirtualFrame frame) {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        probe.enter(child, frame);
+        Object result;
+
+        try {
+            result = child.executeGeneric(frame);
+            probe.leave(child, frame, result);
+        } catch (Exception e) {
+            probe.leaveExceptional(child, frame, e);
+            throw (e);
+        }
+        return result;
+    }
+
+    @Override
+    public long executeLong(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectLong(executeGeneric(frame));
+    }
+
+    @Override
+    public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectBigInteger(executeGeneric(frame));
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectBoolean(executeGeneric(frame));
+    }
+
+    @Override
+    public String executeString(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        return SLTypesGen.SLTYPES.expectString(executeGeneric(frame));
+    }
+
+    @Override
+    public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        probe.enter(child, frame);
+        SLFunction result;
+
+        try {
+            result = child.executeFunction(frame);
+            probe.leave(child, frame, result);
+        } catch (Exception e) {
+            probe.leaveExceptional(child, frame, e);
+            throw (e);
+        }
+        return result;
+    }
+
+    @Override
+    public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
+        return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLNodeProber.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.instrument;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.sl.nodes.*;
+
+public interface SLNodeProber extends ASTNodeProber {
+
+    SLStatementNode probeAsStatement(SLStatementNode result);
+
+    SLExpressionNode probeAsCall(SLExpressionNode node, String callName);
+
+    SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Wed Jul 30 10:39:39 2014 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.instrument;
+
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * SLStatmentWrapper is a Truffle AST node that gets inserted as the parent to the node that it is
+ * wrapping. Any debugging instruments are attached to this wrapper through {@link Probe}s (which
+ * themselves contain the instruments). It is through this mechanism that tools can interact
+ * directly with the AST. <br/>
+ * SLStatmentWrapper specifically wraps {@link SLStatementWrapper}s and overrides the executeVoid
+ * function of {@link SLStatementNode} to operate on the child of the wrapper instead of the wrapper
+ * itself.
+ *
+ */
+public final class SLStatementWrapper extends SLStatementNode implements Wrapper {
+
+    @Child private SLStatementNode child;
+
+    private final Probe probe;
+
+    public SLStatementWrapper(SLContext context, SLStatementNode child) {
+        super(child.getSourceSection());
+        assert !(child instanceof SLStatementWrapper);
+        this.child = insert(child);
+        this.probe = context.getProbe(child.getSourceSection());
+    }
+
+    @Override
+    public SLStatementNode getNonWrapperNode() {
+        return child;
+    }
+
+    public Node getChild() {
+        return child;
+    }
+
+    public Probe getProbe() {
+        return probe;
+    }
+
+    @SlowPath
+    public boolean isTaggedAs(SyntaxTag tag) {
+        return probe.isTaggedAs(tag);
+    }
+
+    @SlowPath
+    public Iterable<SyntaxTag> getSyntaxTags() {
+        return probe.getSyntaxTags();
+    }
+
+    @SlowPath
+    public void tagAs(SyntaxTag tag) {
+        probe.tagAs(tag);
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        this.tagAs(StandardSyntaxTag.STATEMENT);
+        probe.enter(child, frame);
+
+        try {
+            child.executeVoid(frame);
+            probe.leave(child, frame);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probe.leaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Wed Jul 30 10:39:39 2014 -0700
@@ -33,6 +33,7 @@
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.runtime.*;
 
 // Checkstyle: stop
@@ -51,9 +52,9 @@
     public final Errors errors;
     private final SLNodeFactory factory;
     -->declarations
-    public Parser(SLContext context, Source source) {
+    public Parser(SLContext context, Source source, SLNodeProber astProber) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source);
+        this.factory = new SLNodeFactory(context, source, astProber);
         errors = new Errors();
     }
 
@@ -134,8 +135,8 @@
 -->initialization
     };
 
-    public static void parseSL(SLContext context, Source source) {
-        Parser parser = new Parser(context, source);
+    public static void parseSL(SLContext context, Source source, SLNodeProber astProber) {
+        Parser parser = new Parser(context, source, astProber);
         parser.Parse();
         if (parser.errors.errors.size() > 0) {
             StringBuilder msg = new StringBuilder("Error(s) parsing script:\n");
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Wed Jul 30 10:39:39 2014 -0700
@@ -30,6 +30,7 @@
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.runtime.*;
 
 // Checkstyle: stop
@@ -52,10 +53,10 @@
     public final Scanner scanner;
     public final Errors errors;
     private final SLNodeFactory factory;
-    
-    public Parser(SLContext context, Source source) {
+
+    public Parser(SLContext context, Source source, SLNodeProber astProber) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source);
+        this.factory = new SLNodeFactory(context, source, astProber);
         errors = new Errors();
     }
 
@@ -133,41 +134,41 @@
 	void Function() {
 		Expect(4);
 		Expect(1);
-		factory.startFunction(t); 
+		factory.startFunction(t);
 		Expect(5);
 		if (la.kind == 1) {
 			Get();
-			factory.addFormalParameter(t); 
+			factory.addFormalParameter(t);
 			while (la.kind == 6) {
 				Get();
 				Expect(1);
-				factory.addFormalParameter(t); 
+				factory.addFormalParameter(t);
 			}
 		}
 		Expect(7);
 		SLStatementNode body = Block(false);
-		factory.finishFunction(body); 
+		factory.finishFunction(body);
 	}
 
 	SLStatementNode  Block(boolean inLoop) {
 		SLStatementNode  result;
 		factory.startBlock();
-		List<SLStatementNode> body = new ArrayList<>(); 
+		List<SLStatementNode> body = new ArrayList<>();
 		Expect(8);
-		int lBracePos = t.charPos; 
+		int lBracePos = t.charPos;
 		while (StartOf(1)) {
 			SLStatementNode s = Statement(inLoop);
-			body.add(s); 
+			body.add(s);
 		}
 		Expect(9);
-		int length = (t.charPos + t.val.length()) - lBracePos; 
-		result = factory.finishBlock(body, lBracePos, length); 
+		int length = (t.charPos + t.val.length()) - lBracePos;
+		result = factory.finishBlock(body, lBracePos, length);
 		return result;
 	}
 
 	SLStatementNode  Statement(boolean inLoop) {
 		SLStatementNode  result;
-		result = null; 
+		result = null;
 		switch (la.kind) {
 		case 13: {
 			result = WhileStatement();
@@ -175,13 +176,13 @@
 		}
 		case 10: {
 			Get();
-			if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } 
+			if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); }
 			Expect(11);
 			break;
 		}
 		case 12: {
 			Get();
-			if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } 
+			if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); }
 			Expect(11);
 			break;
 		}
@@ -207,11 +208,11 @@
 		SLStatementNode  result;
 		Expect(13);
 		Expect(5);
-		Token whileToken = t; 
+		Token whileToken = t;
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode body = Block(true);
-		result = factory.createWhile(whileToken, condition, body); 
+		result = factory.createWhile(whileToken, condition, body);
 		return result;
 	}
 
@@ -219,16 +220,16 @@
 		SLStatementNode  result;
 		Expect(14);
 		Expect(5);
-		Token ifToken = t; 
+		Token ifToken = t;
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode thenPart = Block(inLoop);
-		SLStatementNode elsePart = null; 
+		SLStatementNode elsePart = null;
 		if (la.kind == 15) {
 			Get();
 			elsePart = Block(inLoop);
 		}
-		result = factory.createIf(ifToken, condition, thenPart, elsePart); 
+		result = factory.createIf(ifToken, condition, thenPart, elsePart);
 		return result;
 	}
 
@@ -236,11 +237,11 @@
 		SLStatementNode  result;
 		Expect(16);
 		Token returnToken = t;
-		SLExpressionNode value = null; 
+		SLExpressionNode value = null;
 		if (StartOf(2)) {
 			value = Expression();
 		}
-		result = factory.createReturn(returnToken, value); 
+		result = factory.createReturn(returnToken, value);
 		Expect(11);
 		return result;
 	}
@@ -250,9 +251,9 @@
 		result = LogicTerm();
 		while (la.kind == 17) {
 			Get();
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = LogicTerm();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -262,9 +263,9 @@
 		result = LogicFactor();
 		while (la.kind == 18) {
 			Get();
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = LogicFactor();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -299,9 +300,9 @@
 				break;
 			}
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Arithmetic();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -315,9 +316,9 @@
 			} else {
 				Get();
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Term();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
@@ -331,48 +332,48 @@
 			} else {
 				Get();
 			}
-			Token op = t; 
+			Token op = t;
 			SLExpressionNode right = Factor();
-			result = factory.createBinary(op, result, right); 
+			result = factory.createBinary(op, result, right);
 		}
 		return result;
 	}
 
 	SLExpressionNode  Factor() {
 		SLExpressionNode  result;
-		result = null; 
+		result = null;
 		if (la.kind == 1) {
 			Get();
-			Token nameToken = t; 
+			Token nameToken = t;
 			if (la.kind == 5) {
 				Get();
 				List<SLExpressionNode> parameters = new ArrayList<>();
-				SLExpressionNode parameter; 
+				SLExpressionNode parameter;
 				if (StartOf(2)) {
 					parameter = Expression();
-					parameters.add(parameter); 
+					parameters.add(parameter);
 					while (la.kind == 6) {
 						Get();
 						parameter = Expression();
-						parameters.add(parameter); 
+						parameters.add(parameter);
 					}
 				}
 				Expect(7);
-				Token finalToken = t; 
-				result = factory.createCall(nameToken, parameters, finalToken); 
+				Token finalToken = t;
+				result = factory.createCall(nameToken, parameters, finalToken);
 			} else if (la.kind == 29) {
 				Get();
 				SLExpressionNode value = Expression();
-				result = factory.createAssignment(nameToken, value); 
+				result = factory.createAssignment(nameToken, value);
 			} else if (StartOf(4)) {
-				result = factory.createRead(nameToken); 
+				result = factory.createRead(nameToken);
 			} else SynErr(32);
 		} else if (la.kind == 2) {
 			Get();
-			result = factory.createStringLiteral(t); 
+			result = factory.createStringLiteral(t);
 		} else if (la.kind == 3) {
 			Get();
-			result = factory.createNumericLiteral(t); 
+			result = factory.createNumericLiteral(t);
 		} else if (la.kind == 5) {
 			Get();
 			result = Expression();
@@ -401,8 +402,8 @@
 
     };
 
-    public static void parseSL(SLContext context, Source source) {
-        Parser parser = new Parser(context, source);
+    public static void parseSL(SLContext context, Source source, SLNodeProber astProber) {
+        Parser parser = new Parser(context, source, astProber);
         parser.Parse();
         if (parser.errors.errors.size() > 0) {
             StringBuilder msg = new StringBuilder("Error(s) parsing script:\n");
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Wed Jul 30 10:39:39 2014 -0700
@@ -32,6 +32,7 @@
 import com.oracle.truffle.sl.nodes.call.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
 import com.oracle.truffle.sl.nodes.expression.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.nodes.local.*;
 import com.oracle.truffle.sl.runtime.*;
 
@@ -72,9 +73,12 @@
     /* State while parsing a block. */
     private LexicalScope lexicalScope;
 
-    public SLNodeFactory(SLContext context, Source source) {
+    private final SLNodeProber prober;
+
+    public SLNodeFactory(SLContext context, Source source, SLNodeProber prober) {
         this.context = context;
         this.source = source;
+        this.prober = prober;
     }
 
     public void startFunction(Token nameToken) {
@@ -179,6 +183,14 @@
     public SLStatementNode createIf(Token t, SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) {
         final int start = t.charPos;
         final int end = elsePartNode == null ? thenPartNode.getSourceSection().getCharEndIndex() : elsePartNode.getSourceSection().getCharEndIndex();
+
+        // if (prober != null) {
+        // SLStatementNode wrappedThenNode = prober.probeAsStatement(thenPartNode);
+        // // SLStatementNode wrappedElseNode = prober.probeAsStatement(elsePartNode);
+        // return new SLIfNode(source.createSection(t.val, start, end - start), conditionNode,
+        // wrappedThenNode, elsePartNode);
+        // }
+
         return new SLIfNode(source.createSection(t.val, start, end - start), conditionNode, thenPartNode, elsePartNode);
     }
 
@@ -227,6 +239,10 @@
         final int endPos = finalToken.charPos + finalToken.val.length();
         final SourceSection src = source.createSection(nameToken.val, startPos, endPos - startPos);
         SLExpressionNode functionNode = createRead(nameToken);
+        if (prober != null) {
+            SLExpressionNode wrappedNode = prober.probeAsCall(functionNode, nameToken.val);
+            return SLInvokeNode.create(src, wrappedNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()]));
+        }
         return SLInvokeNode.create(src, functionNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()]));
     }
 
@@ -235,6 +251,10 @@
         lexicalScope.locals.put(nameToken.val, frameSlot);
         final int start = nameToken.charPos;
         final int length = valueNode.getSourceSection().getCharEndIndex() - start;
+        if (prober != null) {
+            final SLExpressionNode wrappedNode = prober.probeAsLocalAssignment(valueNode, nameToken.val);
+            return SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), wrappedNode, frameSlot);
+        }
         return SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), valueNode, frameSlot);
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Wed Jul 30 09:36:32 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Wed Jul 30 10:39:39 2014 -0700
@@ -29,8 +29,11 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.nodes.local.*;
 import com.oracle.truffle.sl.parser.*;
 
@@ -49,6 +52,7 @@
     private final PrintStream output;
     private final SLFunctionRegistry functionRegistry;
     private SourceCallback sourceCallback = null;
+    private SLASTProber astProber;
 
     public SLContext(BufferedReader input, PrintStream output) {
         this.input = input;
@@ -133,4 +137,28 @@
         /* Register the builtin function in our function registry. */
         getFunctionRegistry().register(name, rootNode);
     }
+
+    public void executeMain(Source source) {
+
+        if (sourceCallback != null) {
+            sourceCallback.startLoading(source);
+        }
+
+        Parser.parseSL(this, source, astProber);
+
+        if (sourceCallback != null) {
+            sourceCallback.endLoading(source);
+        }
+
+        SLFunction main = getFunctionRegistry().lookup("main");
+        if (main.getCallTarget() == null) {
+            throw new SLException("No function main() defined in SL source file.");
+        }
+        main.getCallTarget().call();
+    }
+
+    public void setASTNodeProber(SLASTProber astProber) {
+        // TODO Auto-generated method stub
+        this.astProber = astProber;
+    }
 }
--- a/mx/mx_graal.py	Wed Jul 30 09:36:32 2014 -0700
+++ b/mx/mx_graal.py	Wed Jul 30 10:39:39 2014 -0700
@@ -484,17 +484,30 @@
         if exists(toDelete):
             os.unlink(toDelete)
 
+def _makeHotspotGeneratedSourcesDir():
+    hsSrcGenDir = join(mx.project('com.oracle.graal.hotspot').source_gen_dir(), 'hotspot')
+    if not exists(hsSrcGenDir):
+        os.makedirs(hsSrcGenDir)
+    return hsSrcGenDir
+
+
 def _update_graalRuntime_inline_hpp(graalJar):
     p = mx.project('com.oracle.graal.hotspot.sourcegen')
     mainClass = 'com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp'
     if exists(join(p.output_dir(), mainClass.replace('.', os.sep) + '.class')):
-        hsSrcGenDir = join(mx.project('com.oracle.graal.hotspot').source_gen_dir(), 'hotspot')
-        if not exists(hsSrcGenDir):
-            os.makedirs(hsSrcGenDir)
-
+        graalRuntime_inline_hpp = join(_makeHotspotGeneratedSourcesDir(), 'graalRuntime.inline.hpp')
         tmp = StringIO.StringIO()
         mx.run_java(['-cp', '{}{}{}'.format(graalJar, os.pathsep, p.output_dir()), mainClass], out=tmp.write)
-        mx.update_file(join(hsSrcGenDir, 'graalRuntime.inline.hpp'), tmp.getvalue())
+        mx.update_file(graalRuntime_inline_hpp, tmp.getvalue())
+
+def _checkVMIsNewerThanGeneratedSources(jdk, vm, bld):
+    if isGraalEnabled(vm) and (not _installed_jdks or _installed_jdks == _graal_home):
+        vmLib = mx.TimeStampFile(join(_vmLibDirInJdk(jdk), vm, mx.add_lib_prefix(mx.add_lib_suffix('jvm'))))
+        for name in ['graalRuntime.inline.hpp', 'HotSpotVMConfig.inline.hpp']:
+            genSrc = join(_makeHotspotGeneratedSourcesDir(), name)
+            if vmLib.isOlderThan(genSrc):
+                mx.log('The VM ' + vmLib.path + ' is older than ' + genSrc)
+                mx.abort('You need to run "mx --vm ' + vm + ' --vmbuild ' + bld + ' build"')
 
 def _installGraalJarInJdks(graalDist):
     graalJar = graalDist.path
@@ -618,6 +631,35 @@
     mx.log('')
     mx.log('Note that these variables can be given persistent values in the file ' + join(_graal_home, 'mx', 'env') + ' (see \'mx about\').')
 
+cached_graal_version = None
+
+def graal_version(dev_suffix='dev'):
+    global cached_graal_version
+
+    if not cached_graal_version:
+        # extract latest release tag for graal
+        try:
+            tags = [x.split() for x in subprocess.check_output(['hg', '-R', _graal_home, 'tags']).split('\n') if x.startswith("graal-")]
+            current_revision = subprocess.check_output(['hg', '-R', _graal_home, 'id', '-i']).strip()
+        except:
+            # not a mercurial repository or hg commands are not available.
+            tags = None
+
+        if tags and current_revision:
+            sorted_tags = sorted(tags, key=lambda e: [int(x) for x in e[0][len("graal-"):].split('.')], reverse=True)
+            most_recent_tag_name, most_recent_tag_revision = sorted_tags[0]
+            most_recent_tag_version = most_recent_tag_name[len("graal-"):]
+
+            if current_revision == most_recent_tag_revision:
+                cached_graal_version = most_recent_tag_version
+            else:
+                major, minor = map(int, most_recent_tag_version.split('.'))
+                cached_graal_version = str(major) + '.' + str(minor + 1) + '-' + dev_suffix
+        else:
+            cached_graal_version = 'unknown-{}-{}'.format(platform.node(), time.strftime('%Y-%m-%d_%H-%M-%S_%Z'))
+
+    return cached_graal_version
+
 def build(args, vm=None):
     """build the VM binary
 
@@ -778,22 +820,9 @@
                 setMakeVar('INCLUDE_GRAAL', 'false')
                 setMakeVar('ALT_OUTPUTDIR', join(_graal_home, 'build-nograal', mx.get_os()), env=env)
             else:
-                # extract latest release tag for graal
-                try:
-                    tags = [x.split(' ')[0] for x in subprocess.check_output(['hg', '-R', _graal_home, 'tags']).split('\n') if x.startswith("graal-")]
-                except:
-                    # not a mercurial repository or hg commands are not available.
-                    tags = None
-
-                if tags:
-                    # extract the most recent tag
-                    tag = sorted(tags, key=lambda e: [int(x) for x in e[len("graal-"):].split('.')], reverse=True)[0]
-                    setMakeVar('USER_RELEASE_SUFFIX', tag)
-                    setMakeVar('GRAAL_VERSION', tag[len("graal-"):])
-                else:
-                    version = 'unknown-{}-{}'.format(platform.node(), time.strftime('%Y-%m-%d_%H-%M-%S_%Z'))
-                    setMakeVar('USER_RELEASE_SUFFIX', 'graal-' + version)
-                    setMakeVar('GRAAL_VERSION', version)
+                version = graal_version()
+                setMakeVar('USER_RELEASE_SUFFIX', 'graal-' + version)
+                setMakeVar('GRAAL_VERSION', version)
                 setMakeVar('INCLUDE_GRAAL', 'true')
             setMakeVar('INSTALL', 'y', env=env)
             if mx.get_os() == 'solaris':
@@ -885,6 +914,7 @@
     build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product'
     jdk = _jdk(build, vmToCheck=vm, installGraalJar=False)
     _updateInstalledGraalOptionsFile(jdk)
+    _checkVMIsNewerThanGeneratedSources(jdk, vm, build)
     mx.expand_project_in_args(args)
     if _make_eclipse_launch:
         mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True))
@@ -1054,7 +1084,7 @@
             graalDist = mx.distribution('GRAAL')
             graalJarCp = set([d.output_dir() for d in graalDist.sorted_deps()])
             cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e not in graalJarCp])
-            vmArgs = vmArgs + ['-XX:-UseGraalClassLoader']
+            vmArgs = ['-XX:-UseGraalClassLoader'] + vmArgs
 
         if len(testclasses) == 1:
             # Execute Junit directly when one test is being run. This simplifies
@@ -1473,6 +1503,12 @@
             mx.logv('[This execution may take a while as the NetBeans platform needs to be downloaded]')
         mx.run(['ant', '-f', join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'), '-l', fp.name, 'run'], env=env)
 
+def install(args):
+    """install Truffle into your local Maven repository"""
+    mx.archive(["@TRUFFLE"])
+    mx.run(['mvn', 'install:install-file', '-DgroupId=com.oracle', '-DartifactId=truffle', '-Dversion=' + graal_version('SNAPSHOT'), '-Dpackaging=jar', '-Dfile=truffle.jar'])
+    mx.run(['mvn', 'install:install-file', '-DgroupId=com.oracle', '-DartifactId=truffle-dsl-processor', '-Dversion=' + graal_version('SNAPSHOT'), '-Dpackaging=jar', '-Dfile=truffle-dsl-processor.jar'])
+
 def c1visualizer(args):
     """run the Cl Compiler Visualizer"""
     libpath = join(_graal_home, 'lib')
@@ -1481,10 +1517,14 @@
     else:
         executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer')
 
-    archive = join(libpath, 'c1visualizer_2014-04-22.zip')
-    if not exists(executable) or not exists(archive):
-        if not exists(archive):
-            mx.download(archive, ['https://java.net/downloads/c1visualizer/c1visualizer_2014-04-22.zip'])
+    # Check whether the current C1Visualizer installation is the up-to-date
+    if exists(executable) and not exists(mx.library('C1VISUALIZER_DIST').get_path(resolve=False)):
+        mx.log('Updating C1Visualizer')
+        shutil.rmtree(join(libpath, 'c1visualizer'))
+
+    archive = mx.library('C1VISUALIZER_DIST').get_path(resolve=True)
+
+    if not exists(executable):
         zf = zipfile.ZipFile(archive, 'r')
         zf.extractall(libpath)
 
@@ -1827,8 +1867,20 @@
         flavor = 'att'
     lib = mx.add_lib_suffix('hsdis-' + _arch())
     path = join(_graal_home, 'lib', lib)
+
+    sha1s = {
+        'att/hsdis-amd64.dll' : 'bcbd535a9568b5075ab41e96205e26a2bac64f72',
+        'att/hsdis-amd64.so' : '58919ba085d4ef7a513f25bae75e7e54ee73c049',
+        'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30',
+        'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192',
+        'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2',
+    }
+
     if not exists(path):
-        mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib])
+        flavoredLib = flavor + "/" + lib
+        sha1 = sha1s[flavoredLib]
+        sha1path = path + '.sha1'
+        mx.download_file_with_sha1('hsdis', path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavoredLib], sha1, sha1path, True, True, sources=False)
     if copyToDir is not None and exists(copyToDir):
         shutil.copy(path, copyToDir)
 
@@ -1844,10 +1896,8 @@
 
     args = parser.parse_args(args)
 
-    path = join(_graal_home, 'lib', 'hcfdis-1.jar')
-    if not exists(path):
-        mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hcfdis-2.jar'])
-    mx.run_java(['-jar', path] + args.files)
+    path = mx.library('HCFDIS').get_path(resolve=True)
+    mx.run_java(['-cp', path, 'com.oracle.max.hcfdis.HexCodeFileDis'] + args.files)
 
     if args.map is not None:
         addressRE = re.compile(r'0[xX]([A-Fa-f0-9]+)')
@@ -1904,11 +1954,7 @@
 
 def jol(args):
     """Java Object Layout"""
-    jolurl = "http://lafo.ssw.uni-linz.ac.at/truffle/jol/jol-internals.jar"
-    joljar = "lib/jol-internals.jar"
-    if not exists(joljar):
-        mx.download(joljar, [jolurl])
-
+    joljar = mx.library('JOL_INTERNALS').get_path(resolve=True)
     candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s))
     if len(candidates) > 10:
         print "Found %d candidates. Please be more precise." % (len(candidates))
@@ -2054,8 +2100,7 @@
         if not exists(findbugsLib):
             tmp = tempfile.mkdtemp(prefix='findbugs-download-tmp', dir=_graal_home)
             try:
-                findbugsDist = join(tmp, 'findbugs.zip')
-                mx.download(findbugsDist, ['http://lafo.ssw.uni-linz.ac.at/graal-external-deps/findbugs-3.0.0.zip', 'http://sourceforge.net/projects/findbugs/files/findbugs/3.0.0/findbugs-3.0.0.zip'])
+                findbugsDist = mx.library('FINDBUGS_DIST').get_path(resolve=True)
                 with zipfile.ZipFile(findbugsDist) as zf:
                     candidates = [e for e in zf.namelist() if e.endswith('/lib/findbugs.jar')]
                     assert len(candidates) == 1, candidates
@@ -2123,6 +2168,7 @@
         'hsdis': [hsdis, '[att]'],
         'hcfdis': [hcfdis, ''],
         'igv' : [igv, ''],
+        'install' : [install, ''],
         'jdkhome': [print_jdkhome, ''],
         'jmh': [jmh, '[VM options] [filters|JMH-args-as-json...]'],
         'dacapo': [dacapo, '[VM options] benchmarks...|"all" [DaCapo options]'],
--- a/mx/projects	Wed Jul 30 09:36:32 2014 -0700
+++ b/mx/projects	Wed Jul 30 10:39:39 2014 -0700
@@ -20,8 +20,24 @@
 library@HAMCREST@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/hamcrest-core-1.3-sources.jar,http://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar
 library@HAMCREST@sourceSha1=1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b
 
-library@CHECKSTYLE@path=lib/checkstyle-5.5-all.jar
-library@CHECKSTYLE@urls=jar:http://sourceforge.net/projects/checkstyle/files/checkstyle/5.5/checkstyle-5.5-bin.zip/download!/checkstyle-5.5/checkstyle-5.5-all.jar
+#library@CHECKSTYLE@path=lib/checkstyle-5.5-all.jar
+#library@CHECKSTYLE@urls=jar:http://sourceforge.net/projects/checkstyle/files/checkstyle/5.5/checkstyle-5.5-bin.zip/download!/checkstyle-5.5/checkstyle-5.5-all.jar
+
+library@HCFDIS@path=lib/hcfdis-2.jar
+library@HCFDIS@urls=http://lafo.ssw.uni-linz.ac.at/hcfdis-2.jar
+library@HCFDIS@sha1=bc8b2253436485e9dbaf81771c259ccfa1a24c80
+
+library@FINDBUGS_DIST@path=lib/findbugs-dist-3.0.0.zip
+library@FINDBUGS_DIST@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/findbugs-3.0.0.zip,http://sourceforge.net/projects/findbugs/files/findbugs/3.0.0/findbugs-3.0.0.zip/download
+library@FINDBUGS_DIST@sha1=6e56d67f238dbcd60acb88a81655749aa6419c5b
+
+library@C1VISUALIZER_DIST@path=lib/c1visualizer_2014-04-22.zip
+library@C1VISUALIZER_DIST@urls=https://java.net/downloads/c1visualizer/c1visualizer_2014-04-22.zip
+library@C1VISUALIZER_DIST@sha1=220488d87affb569b893c7201f8ce5d2b0e03141
+
+library@JOL_INTERNALS@path=lib/jol-internals.jar
+library@JOL_INTERNALS@urls=http://lafo.ssw.uni-linz.ac.at/truffle/jol/jol-internals.jar
+library@JOL_INTERNALS@sha1=508bcd26a4d7c4c44048990c6ea789a3b11a62dc
 
 library@FINDBUGS@path=lib/findbugs-3.0.0.jar
 library@FINDBUGS@urls=jar:http://lafo.ssw.uni-linz.ac.at/graal-external-deps/findbugs-3.0.0.zip!/findbugs-3.0.0/lib/findbugs.jar,jar:http://sourceforge.net/projects/findbugs/files/findbugs/3.0.0/findbugs-3.0.0.zip/download!/findbugs-3.0.0/lib/findbugs.jar
@@ -43,19 +59,19 @@
 library@DACAPO_SCALA@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/dacapo-scala-0.1.0-20120216.jar,http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar
 library@DACAPO_SCALA@sha1=59b64c974662b5cf9dbd3cf9045d293853dd7a51
 
-library@OKRA@path=lib/okra-1.9.jar
-library@OKRA@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar
-library@OKRA@sha1=df450b04882e6b5a365299e2cbf1622038ae880e
-library@OKRA@sourcePath=lib/okra-1.9-src.jar
-library@OKRA@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9-src.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar
-library@OKRA@sourceSha1=41dcda5197ca4d87bc94e4d7b5a90e7f22667756
+library@OKRA@path=lib/okra-1.10.jar
+library@OKRA@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.10.jar
+library@OKRA@sha1=96eb3c0ec808ed944ba88d1eb9311058fe0f3d1e
+library@OKRA@sourcePath=lib/okra-1.10-src.jar
+library@OKRA@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-src.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.10-src.jar
+library@OKRA@sourceSha1=75751bb148fcebaba78ff590f883a114b2b09176
 
-library@OKRA_WITH_SIM@path=lib/okra-1.9-with-sim.jar
-library@OKRA_WITH_SIM@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9-with-sim.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar
-library@OKRA_WITH_SIM@sha1=816fa24814cf51c02f9c05477447bb55a152b388
-library@OKRA_WITH_SIM@sourcePath=lib/okra-1.9-with-sim-src.jar
-library@OKRA_WITH_SIM@sourceSha1=1628919457999a8479d9f39845865de527dbd523
-library@OKRA_WITH_SIM@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.9-with-sim-src.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar
+library@OKRA_WITH_SIM@path=lib/okra-1.10-with-sim.jar
+library@OKRA_WITH_SIM@urls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-with-sim.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.10-with-sim.jar
+library@OKRA_WITH_SIM@sha1=7b8db879f1dbcf571290add78d9af24e15a2a50d
+library@OKRA_WITH_SIM@sourcePath=lib/okra-1.10-with-sim-src.jar
+library@OKRA_WITH_SIM@sourceSha1=7eefd94f16a3e3fd3b8f470cf91e265c6f5e7767
+library@OKRA_WITH_SIM@sourceUrls=http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-with-sim-src.jar,http://cr.openjdk.java.net/~tdeneau/okra-1.10-with-sim-src.jar
 
 library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar
 library@JAVA_ALLOCATION_INSTRUMENTER@sourcePath=lib/java-allocation-instrumenter.jar
@@ -776,7 +792,7 @@
 project@com.oracle.truffle.sl@sourceDirs=src
 project@com.oracle.truffle.sl@dependencies=com.oracle.truffle.api.dsl
 project@com.oracle.truffle.sl@checkstyle=com.oracle.graal.graph
-project@com.oracle.truffle.sl@javaCompliance=1.7
+project@com.oracle.truffle.sl@javaCompliance=1.8
 project@com.oracle.truffle.sl@annotationProcessors=com.oracle.truffle.dsl.processor
 project@com.oracle.truffle.sl@workingSets=Truffle,SimpleLanguage
 
@@ -785,7 +801,7 @@
 project@com.oracle.truffle.sl.test@sourceDirs=src
 project@com.oracle.truffle.sl.test@dependencies=com.oracle.truffle.sl,JUNIT
 project@com.oracle.truffle.sl.test@checkstyle=com.oracle.graal.graph
-project@com.oracle.truffle.sl.test@javaCompliance=1.7
+project@com.oracle.truffle.sl.test@javaCompliance=1.8
 project@com.oracle.truffle.sl.test@workingSets=Truffle,SimpleLanguage,Test
 
 # graal.truffle
--- a/mxtool/mx.py	Wed Jul 30 09:36:32 2014 -0700
+++ b/mxtool/mx.py	Wed Jul 30 10:39:39 2014 -0700
@@ -487,10 +487,39 @@
         return join(prefix, path)
     return path
 
-def _download_file_with_sha1(name, path, urls, sha1, sha1path, resolve, mustExist, sources=False):
+def sha1OfFile(path):
+    with open(path, 'rb') as f:
+        d = hashlib.sha1()
+        while True:
+            buf = f.read(4096)
+            if not buf:
+                break
+            d.update(buf)
+        return d.hexdigest()
+
+def download_file_with_sha1(name, path, urls, sha1, sha1path, resolve, mustExist, sources=False):
     def _download_lib():
-        print 'Downloading ' + ("Sources " if sources else "") + name + ' from ' + str(urls)
-        download(path, urls)
+        cacheDir = get_env('MX_CACHE_DIR', join(_opts.user_home, '.mx', 'cache'))
+        if not exists(cacheDir):
+            os.makedirs(cacheDir)
+        base = basename(path)
+        cachePath = join(cacheDir, base + '_' + sha1)
+
+        if not exists(cachePath) or sha1OfFile(cachePath) != sha1:
+            if exists(cachePath):
+                log('SHA1 of ' + cachePath + ' does not match expected value (' + sha1 + ') - re-downloading')
+            print 'Downloading ' + ("sources " if sources else "") + name + ' from ' + str(urls)
+            download(cachePath, urls)
+
+        d = dirname(path)
+        if d != '' and not exists(d):
+            os.makedirs(d)
+        if 'symlink' in dir(os):
+            if exists(path):
+                os.unlink(path)
+            os.symlink(cachePath, path)
+        else:
+            shutil.copy(cachePath, path)
 
     def _sha1Cached():
         with open(sha1path, 'r') as f:
@@ -498,30 +527,21 @@
 
     def _writeSha1Cached():
         with open(sha1path, 'w') as f:
-            f.write(_sha1OfFile())
-
-    def _sha1OfFile():
-        with open(path, 'rb') as f:
-            d = hashlib.sha1()
-            while True:
-                buf = f.read(4096)
-                if not buf:
-                    break
-                d.update(buf)
-            return d.hexdigest()
+            f.write(sha1OfFile(path))
 
     if resolve and mustExist and not exists(path):
         assert not len(urls) == 0, 'cannot find required library ' + name + ' ' + path
         _download_lib()
 
-    if sha1 and not exists(sha1path):
-        _writeSha1Cached()
-
-    if sha1 and sha1 != _sha1Cached():
-        _download_lib()
-        if sha1 != _sha1OfFile():
-            abort("SHA1 does not match for " + name + ". Broken download? SHA1 not updated in projects file?")
-        _writeSha1Cached()
+    if exists(path):
+        if sha1 and not exists(sha1path):
+            _writeSha1Cached()
+
+        if sha1 and sha1 != _sha1Cached():
+            _download_lib()
+            if sha1 != sha1OfFile(path):
+                abort("SHA1 does not match for " + name + ". Broken download? SHA1 not updated in projects file?")
+            _writeSha1Cached()
 
     return path
 
@@ -587,12 +607,26 @@
         self.sha1 = sha1
         self.sourcePath = sourcePath
         self.sourceUrls = sourceUrls
+        if sourcePath == path:
+            assert sourceSha1 is None or sourceSha1 == sha1
+            sourceSha1 = sha1
         self.sourceSha1 = sourceSha1
         self.deps = deps
-        abspath = _make_absolute(self.path, self.suite.dir)
+        abspath = _make_absolute(path, self.suite.dir)
         if not optional and not exists(abspath):
             if not len(urls):
                 abort('Non-optional library {} must either exist at {} or specify one or more URLs from which it can be retrieved'.format(name, abspath))
+
+        def _checkSha1PropertyCondition(propName, cond, inputPath):
+            if not cond:
+                absInputPath = _make_absolute(inputPath, self.suite.dir)
+                if exists(absInputPath):
+                    abort('Missing "{}" property for library {}. Add the following line to projects file:\nlibrary@{}@{}={}'.format(propName, name, name, propName, sha1OfFile(absInputPath)))
+                abort('Missing "{}" property for library {}'.format(propName, name))
+
+        _checkSha1PropertyCondition('sha1', sha1, path)
+        _checkSha1PropertyCondition('sourceSha1', not sourcePath or sourceSha1, sourcePath)
+
         for url in urls:
             if url.endswith('/') != self.path.endswith(os.sep):
                 abort('Path for dependency directory must have a URL ending with "/": path=' + self.path + ' url=' + url)
@@ -614,7 +648,7 @@
         if includedInJDK and java().javaCompliance >= JavaCompliance(includedInJDK):
             return None
 
-        return _download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, not self.optional)
+        return download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, not self.optional)
 
     def get_source_path(self, resolve):
         if self.sourcePath is None:
@@ -622,7 +656,7 @@
         path = _make_absolute(self.sourcePath, self.suite.dir)
         sha1path = path + '.sha1'
 
-        return _download_file_with_sha1(self.name, path, self.sourceUrls, self.sourceSha1, sha1path, resolve, len(self.sourceUrls) != 0, sources=True)
+        return download_file_with_sha1(self.name, path, self.sourceUrls, self.sourceSha1, sha1path, resolve, len(self.sourceUrls) != 0, sources=True)
 
     def append_to_classpath(self, cp, resolve):
         path = self.get_path(resolve)
@@ -1736,9 +1770,18 @@
                 print e.output
                 abort(e.returncode)
 
-        output = output.split()
-        assert output[1] == 'version'
-        self.version = VersionSpec(output[2].strip('"'))
+        def _checkOutput(out):
+            return 'version' in out
+
+        # hotspot can print a warning, e.g. if there's a .hotspot_compiler file in the cwd
+        output = output.split('\n')
+        version = None
+        for o in output:
+            if _checkOutput(o):
+                assert version is None
+                version = o
+
+        self.version = VersionSpec(version.split()[2].strip('"'))
         self.javaCompliance = JavaCompliance(self.version.versionString)
 
         if self.debug_port is not None:
@@ -1751,8 +1794,8 @@
             os.makedirs(outDir)
         javaSource = join(myDir, 'ClasspathDump.java')
         if not exists(join(outDir, 'ClasspathDump.class')):
-            subprocess.check_call([self.javac, '-d', outDir, javaSource])
-        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', outDir, 'ClasspathDump']).split('|')]
+            subprocess.check_call([self.javac, '-d', outDir, javaSource], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', outDir, 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
         if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
             warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
         self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
--- a/src/gpu/hsail/vm/gpu_hsail.cpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/gpu/hsail/vm/gpu_hsail.cpp	Wed Jul 30 10:39:39 2014 -0700
@@ -72,18 +72,19 @@
 void* Hsail::_device_context = NULL;
 jint  Hsail::_notice_safepoints = false;
 
-Hsail::okra_create_context_func_t  Hsail::_okra_create_context;
+Hsail::okra_get_context_func_t     Hsail::_okra_get_context;
 Hsail::okra_create_kernel_func_t   Hsail::_okra_create_kernel;
-Hsail::okra_push_object_func_t     Hsail::_okra_push_object;
+Hsail::okra_push_pointer_func_t    Hsail::_okra_push_pointer;
 Hsail::okra_push_boolean_func_t    Hsail::_okra_push_boolean;
 Hsail::okra_push_byte_func_t       Hsail::_okra_push_byte;
 Hsail::okra_push_double_func_t     Hsail::_okra_push_double;
 Hsail::okra_push_float_func_t      Hsail::_okra_push_float;
 Hsail::okra_push_int_func_t        Hsail::_okra_push_int;
 Hsail::okra_push_long_func_t       Hsail::_okra_push_long;
-Hsail::okra_execute_with_range_func_t    Hsail::_okra_execute_with_range;
-Hsail::okra_clearargs_func_t       Hsail::_okra_clearargs;
-Hsail::okra_register_heap_func_t   Hsail::_okra_register_heap;
+Hsail::okra_execute_kernel_func_t  Hsail::_okra_execute_kernel;
+Hsail::okra_clear_args_func_t      Hsail::_okra_clear_args;
+Hsail::okra_dispose_kernel_func_t  Hsail::_okra_dispose_kernel;
+Hsail::okra_dispose_context_func_t Hsail::_okra_dispose_context;
 
 //static jint in_kernel = 0;
 
@@ -98,16 +99,6 @@
   _notice_safepoints = false;
 }
 
-void Hsail::register_heap() {
-  // After the okra functions are set up and the heap is initialized, register the java heap with HSA
-  guarantee(Universe::heap() != NULL, "heap should be there by now.");
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] heap=" PTR_FORMAT, Universe::heap());
-    tty->print_cr("[HSAIL] base=0x%08x, capacity=%ld", Universe::heap()->base(), Universe::heap()->capacity());
-  }
-  _okra_register_heap(Universe::heap()->base(), Universe::heap()->capacity());
-}
-
 GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args,
                                                       jobject donor_threads, jint allocBytesPerWorkitem, jobject oop_map_array))
 
@@ -156,7 +147,7 @@
   HSAILAllocationInfo* allocInfo = (donor_threads == NULL ? NULL : new HSAILAllocationInfo(donor_threads, dimX, allocBytesPerWorkitem));
   
   // Reset the kernel arguments
-  _okra_clearargs(kernel);
+  _okra_clear_args(kernel);
 
   JavaThread* thread = (JavaThread*)THREAD;
   HSAILDeoptimizationInfo* e;
@@ -194,13 +185,16 @@
   }
 
   // Run the kernel
-  bool success = false;
+  jboolean success = false;
   {
     TraceTime t("execute kernel", TraceGPUInteraction);
+    graal_okra_range_t kernel_range = {0};
 
     //in_kernel = 1;
     // Run the kernel
-    success = _okra_execute_with_range(kernel, dimX);
+    kernel_range.dimension = 1;
+    kernel_range.global_size[0] = dimX;
+    success = _okra_execute_kernel(_device_context, kernel, &kernel_range);
     //in_kernel = 0;
   }
 
@@ -347,14 +341,12 @@
   env->GetByteArrayRegion(code_handle, 0, code_len, (jbyte*) code);
   env->GetStringUTFRegion(name_handle, 0, name_len, name);
 
-  register_heap();
-
   // The kernel entrypoint is always run for the time being  
   const char* entryPointName = "&run";
-
-  _device_context = _okra_create_context();
-
-  return (jlong) _okra_create_kernel(_device_context, code, entryPointName);
+  jlong okra_kernel;
+  jint okra_status = _okra_create_kernel(_device_context, code, entryPointName, (void**)&okra_kernel);
+  guarantee(okra_status==0, "_okra_create_kernel failed");
+  return (jlong) okra_kernel;
 GPU_END
 
 #if defined(LINUX)
@@ -410,26 +402,31 @@
     return false;
   }
   
-  guarantee(_okra_create_context == NULL, "cannot repeat GPU initialization");
+  guarantee(_okra_get_context == NULL, "cannot repeat GPU initialization");
 
   // At this point we know  okra_lib_handle is valid whether we loaded
   // here or earlier.  In either case, we can lookup the functions.
-  LOOKUP_OKRA_FUNCTION(okra_create_context, okra_create_context);
+  LOOKUP_OKRA_FUNCTION(okra_get_context, okra_get_context);
   LOOKUP_OKRA_FUNCTION(okra_create_kernel, okra_create_kernel);
-  LOOKUP_OKRA_FUNCTION(okra_push_object, okra_push_object);
+  LOOKUP_OKRA_FUNCTION(okra_push_pointer, okra_push_pointer);
   LOOKUP_OKRA_FUNCTION(okra_push_boolean, okra_push_boolean);
   LOOKUP_OKRA_FUNCTION(okra_push_byte, okra_push_byte);
   LOOKUP_OKRA_FUNCTION(okra_push_double, okra_push_double);
   LOOKUP_OKRA_FUNCTION(okra_push_float, okra_push_float);
   LOOKUP_OKRA_FUNCTION(okra_push_int, okra_push_int);
   LOOKUP_OKRA_FUNCTION(okra_push_long, okra_push_long);
-  LOOKUP_OKRA_FUNCTION(okra_execute_with_range, okra_execute_with_range);
-  LOOKUP_OKRA_FUNCTION(okra_clearargs, okra_clearargs);
-  LOOKUP_OKRA_FUNCTION(okra_register_heap, okra_register_heap);
+  LOOKUP_OKRA_FUNCTION(okra_execute_kernel, okra_execute_kernel);
+  LOOKUP_OKRA_FUNCTION(okra_clear_args, okra_clear_args);
+  LOOKUP_OKRA_FUNCTION(okra_dispose_kernel, okra_dispose_kernel);
+  LOOKUP_OKRA_FUNCTION(okra_dispose_context, okra_dispose_context);
   // if we made it this far, real success
 
   Gpu::initialized_gpu(new Hsail());
 
+    // There is 1 context per process
+  jint result = _okra_get_context(&_device_context);
+  guarantee(result==0, "get context failed");
+
   return true;
 GPU_END
 
--- a/src/gpu/hsail/vm/gpu_hsail.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/gpu/hsail/vm/gpu_hsail.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -190,8 +190,6 @@
   static jboolean execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod* nm,
                                                   jobject donorThreads, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS);
 
-  static void register_heap();
-
   static GraalEnv::CodeInstallResult install_code(Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations);
 
 public:
@@ -211,32 +209,45 @@
 #endif
 
 private:
-  typedef void* (*okra_create_context_func_t)();
-  typedef void* (*okra_create_kernel_func_t)(void*, unsigned char*, const char*);
-  typedef bool (*okra_push_object_func_t)(void*, void*);
-  typedef bool (*okra_push_boolean_func_t)(void*, jboolean);
-  typedef bool (*okra_push_byte_func_t)(void*, jbyte);
-  typedef bool (*okra_push_double_func_t)(void*, jdouble);
-  typedef bool (*okra_push_float_func_t)(void*, jfloat);
-  typedef bool (*okra_push_int_func_t)(void*, jint);
-  typedef bool (*okra_push_long_func_t)(void*, jlong);
-  typedef bool (*okra_execute_with_range_func_t)(void*, jint);
-  typedef bool (*okra_clearargs_func_t)(void*);
-  typedef bool (*okra_register_heap_func_t)(void*, size_t);
+
+  /*
+   * Kernel launch options from okra.h
+   */
+  typedef struct graal_okra_range_s {
+    uint32_t dimension; //max value is 3
+    uint32_t global_size[3];
+    uint32_t group_size[3];
+    uint32_t reserved; //For future use
+  } graal_okra_range_t;
+
+  typedef jint (*okra_get_context_func_t)(void**);
+  typedef jint (*okra_create_kernel_func_t)(void*, unsigned char*, const char*, void**);
+  typedef jint (*okra_push_pointer_func_t)(void*, void*);
+  typedef jint (*okra_push_boolean_func_t)(void*, jboolean);
+  typedef jint (*okra_push_byte_func_t)(void*, jbyte);
+  typedef jint (*okra_push_double_func_t)(void*, jdouble);
+  typedef jint (*okra_push_float_func_t)(void*, jfloat);
+  typedef jint (*okra_push_int_func_t)(void*, jint);
+  typedef jint (*okra_push_long_func_t)(void*, jlong);
+  typedef jint (*okra_execute_kernel_func_t)(void*, void*, graal_okra_range_t*);
+  typedef jint (*okra_clear_args_func_t)(void*);
+  typedef jint (*okra_dispose_kernel_func_t)(void*);
+  typedef jint (*okra_dispose_context_func_t)(void*);
 
 public:
-  static okra_create_context_func_t             _okra_create_context;
+  static okra_get_context_func_t                _okra_get_context;
   static okra_create_kernel_func_t              _okra_create_kernel;
-  static okra_push_object_func_t                _okra_push_object;
+  static okra_push_pointer_func_t               _okra_push_pointer;
   static okra_push_boolean_func_t               _okra_push_boolean;
   static okra_push_byte_func_t                  _okra_push_byte;
   static okra_push_double_func_t                _okra_push_double;
   static okra_push_float_func_t                 _okra_push_float;
   static okra_push_int_func_t                   _okra_push_int;
   static okra_push_long_func_t                  _okra_push_long;
-  static okra_execute_with_range_func_t         _okra_execute_with_range;
-  static okra_clearargs_func_t                  _okra_clearargs;
-  static okra_register_heap_func_t              _okra_register_heap;
+  static okra_execute_kernel_func_t             _okra_execute_kernel;
+  static okra_clear_args_func_t                 _okra_clear_args;
+  static okra_dispose_kernel_func_t             _okra_dispose_kernel;
+  static okra_dispose_context_func_t            _okra_dispose_context;
   
 protected:
   static void* _device_context;
--- a/src/gpu/hsail/vm/hsailKernelArguments.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -47,36 +47,36 @@
     }
     virtual char* argsBuilderName() {return (char*)"HSAILKernelArguments";}
     virtual void pushObject(void* obj) {
-        bool pushed = Hsail::_okra_push_object(_kernel, obj);
-        assert(pushed == true, "arg push failed");
+        jint status = Hsail::_okra_push_pointer(_kernel, obj);
+        assert(status == 0, "arg push failed");
     }
     virtual void pushBool(jboolean z) {
-        bool pushed = Hsail::_okra_push_boolean(_kernel, z);
-        assert(pushed == true, "arg push failed");
+        jint status = Hsail::_okra_push_boolean(_kernel, z);
+        assert(status == 0, "arg push failed");
     }
     virtual void pushByte(jbyte b) {
-        bool pushed = Hsail::_okra_push_byte(_kernel, b);
-        assert(pushed == true, "arg push failed");
+        jint status = Hsail::_okra_push_byte(_kernel, b);
+        assert(status == 0, "arg push failed");
     }
 
     virtual void pushDouble(jdouble d) {
-        bool pushed = Hsail::_okra_push_double(_kernel, d);
-        assert(pushed == true, "arg push failed");
+        jint status = Hsail::_okra_push_double(_kernel, d);
+        assert(status == 0, "arg push failed");
     }
 
     virtual void pushFloat(jfloat f) {
-        bool pushed = Hsail::_okra_push_float(_kernel, f);
-        assert(pushed == true, "arg push failed");
+        jint status = Hsail::_okra_push_float(_kernel, f);
+        assert(status == 0, "arg push failed");
     }
 
     virtual void pushInt(jint i) {
-        bool pushed = Hsail::_okra_push_int(_kernel, i);
-        assert(pushed == true, "arg push failed");
+        jint status = Hsail::_okra_push_int(_kernel, i);
+        assert(status == 0, "arg push failed");
     }
 
     virtual void pushLong(jlong j) {
-        bool pushed = Hsail::_okra_push_long(_kernel, j);
-        assert(pushed == true, "arg push failed");
+        jint status = Hsail::_okra_push_long(_kernel, j);
+        assert(status == 0, "arg push failed");
     }
     virtual void pushTrailingArgs() {
         if (UseHSAILDeoptimization) {
--- a/src/share/vm/classfile/systemDictionary.cpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/classfile/systemDictionary.cpp	Wed Jul 30 10:39:39 2014 -0700
@@ -1059,7 +1059,9 @@
       // deoptimizations.
       add_to_hierarchy(k, CHECK_NULL); // No exception, but can block
 
-      // But, do not add to system dictionary.
+      // But, do not add to system dictionary.  That normally takes
+      // care of updating _number_of_modifications so do it here.
+      notice_modification();
     }
 
     // Rewrite and patch constant pool here.
--- a/src/share/vm/classfile/systemDictionary.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -204,6 +204,7 @@
   GRAAL_ONLY(do_klass(HotSpotResolvedJavaMethod_klass,       com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod,      Graal)) \
   GRAAL_ONLY(do_klass(HotSpotResolvedObjectType_klass,       com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,      Graal)) \
   GRAAL_ONLY(do_klass(HotSpotMonitorValue_klass,             com_oracle_graal_hotspot_meta_HotSpotMonitorValue,            Graal)) \
+  GRAAL_ONLY(do_klass(HotSpotCompressedNullConstant_klass,   com_oracle_graal_hotspot_meta_HotSpotCompressedNullConstant,  Graal)) \
   GRAAL_ONLY(do_klass(HotSpotObjectConstant_klass,           com_oracle_graal_hotspot_meta_HotSpotObjectConstant,          Graal)) \
   GRAAL_ONLY(do_klass(HotSpotMetaspaceConstant_klass,        com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstant,       Graal)) \
   GRAAL_ONLY(do_klass(HotSpotStackFrameReference_klass,      com_oracle_graal_hotspot_HotSpotStackFrameReference,          Graal)) \
@@ -238,6 +239,7 @@
   GRAAL_ONLY(do_klass(NullConstant_klass,                    com_oracle_graal_api_meta_NullConstant,                       Graal)) \
   GRAAL_ONLY(do_klass(ExceptionHandler_klass,                com_oracle_graal_api_meta_ExceptionHandler,                   Graal)) \
   GRAAL_ONLY(do_klass(Kind_klass,                            com_oracle_graal_api_meta_Kind,                               Graal)) \
+  GRAAL_ONLY(do_klass(LIRKind_klass,                         com_oracle_graal_api_meta_LIRKind,                            Graal)) \
   GRAAL_ONLY(do_klass(JavaMethod_klass,                      com_oracle_graal_api_meta_JavaMethod,                         Graal)) \
   GRAAL_ONLY(do_klass(JavaType_klass,                        com_oracle_graal_api_meta_JavaType,                           Graal)) \
   GRAAL_ONLY(do_klass(Value_klass,                           com_oracle_graal_api_meta_Value,                              Graal)) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -311,6 +311,7 @@
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod,  "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod"))       \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,  "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType"))       \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue,        "com/oracle/graal/hotspot/meta/HotSpotMonitorValue"))             \
+  GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotCompressedNullConstant, "com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant")) \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotObjectConstant,      "com/oracle/graal/hotspot/meta/HotSpotObjectConstant"))           \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstant,   "com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant"))        \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotStackFrameReference,      "com/oracle/graal/hotspot/HotSpotStackFrameReference"))           \
@@ -322,6 +323,7 @@
   GRAAL_ONLY(template(com_oracle_graal_api_meta_JavaMethod,                     "com/oracle/graal/api/meta/JavaMethod"))                          \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_JavaType,                       "com/oracle/graal/api/meta/JavaType"))                            \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_Kind,                           "com/oracle/graal/api/meta/Kind"))                                \
+  GRAAL_ONLY(template(com_oracle_graal_api_meta_LIRKind,                        "com/oracle/graal/api/meta/LIRKind"))                             \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_Value,                          "com/oracle/graal/api/meta/Value"))                               \
   GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions,                    "com/oracle/graal/api/code/Assumptions"))                         \
   GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_MethodContents,     "com/oracle/graal/api/code/Assumptions$MethodContents"))          \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Wed Jul 30 10:39:39 2014 -0700
@@ -216,34 +216,44 @@
     return new LocationValue(Location::new_stk_loc(Location::invalid, 0));
   }
 
-  BasicType type = GraalRuntime::kindToBasicType(Kind::typeChar(Value::kind(value)));
-  Location::Type locationType = Location::normal;
-  if (type == T_OBJECT || type == T_ARRAY) locationType = Location::oop;
+  oop lirKind = Value::lirKind(value);
+  oop platformKind = LIRKind::platformKind(lirKind);
+  jint referenceMask = LIRKind::referenceMask(lirKind);
+  assert(referenceMask == 0 || referenceMask == 1, "unexpected referenceMask");
+  bool reference = referenceMask == 1;
+
+  BasicType type = GraalRuntime::kindToBasicType(Kind::typeChar(platformKind));
 
   if (value->is_a(RegisterValue::klass())) {
     jint number = code_Register::number(RegisterValue::reg(value));
     jint encoding = code_Register::encoding(RegisterValue::reg(value));
     if (number < RegisterImpl::number_of_registers) {
-      if (type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BOOLEAN || type == T_BYTE || type == T_ADDRESS) {
+      Location::Type locationType;
+      if (type == T_INT) {
+        locationType = reference ? Location::narrowoop : Location::int_in_long;
+      } else if (type == T_FLOAT) {
         locationType = Location::int_in_long;
       } else if (type == T_LONG) {
-        locationType = Location::lng;
+        locationType = reference ? Location::oop : Location::lng;
       } else {
-        assert(type == T_OBJECT || type == T_ARRAY, "unexpected type in cpu register");
+        assert(type == T_OBJECT && reference, "unexpected type in cpu register");
+        locationType = Location::oop;
       }
       ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, as_Register(number)->as_VMReg()));
-      if (type == T_LONG) {
+      if (type == T_LONG && !reference) {
         second = value;
       }
       return value;
     } else {
       assert(type == T_FLOAT || type == T_DOUBLE, "only float and double expected in xmm register");
+      Location::Type locationType;
       if (type == T_FLOAT) {
         // this seems weird, but the same value is used in c1_LinearScan
         locationType = Location::normal;
       } else {
         locationType = Location::dbl;
       }
+      assert(!reference, "unexpected type in floating point register");
 #ifdef TARGET_ARCH_x86
       ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, as_XMMRegister(number - 16)->as_VMReg()));
       if (type == T_DOUBLE) {
@@ -263,41 +273,54 @@
 #endif
     }
   } else if (value->is_a(StackSlot::klass())) {
-    if (type == T_DOUBLE) {
+      Location::Type locationType;
+    if (type == T_LONG) {
+      locationType = reference ? Location::oop : Location::lng;
+    } else if (type == T_INT) {
+      locationType = reference ? Location::narrowoop : Location::normal;
+    } else if (type == T_FLOAT) {
+      assert(!reference, "unexpected type in stack slot");
+      locationType = Location::normal;
+    } else if (type == T_DOUBLE) {
+      assert(!reference, "unexpected type in stack slot");
       locationType = Location::dbl;
-    } else if (type == T_LONG) {
-      locationType = Location::lng;
+    } else {
+      assert(type == T_OBJECT && reference, "unexpected type in stack slot");
+      locationType = Location::oop;
     }
     jint offset = StackSlot::offset(value);
     if (StackSlot::addFrameSize(value)) {
       offset += total_frame_size;
     }
     ScopeValue* value = new LocationValue(Location::new_stk_loc(locationType, offset));
-    if (type == T_DOUBLE || type == T_LONG) {
+    if (type == T_DOUBLE || (type == T_LONG && !reference)) {
       second = value;
     }
     return value;
   } else if (value->is_a(Constant::klass())){
     record_metadata_in_constant(value, oop_recorder);
-    if (type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BOOLEAN || type == T_BYTE) {
-      jint prim = (jint)PrimitiveConstant::primitive(value);
-      return new ConstantIntValue(prim);
-    } else if (type == T_LONG || type == T_DOUBLE) {
-      jlong prim = PrimitiveConstant::primitive(value);
-      second = new ConstantIntValue(0);
-      return new ConstantLongValue(prim);
-    } else if (type == T_OBJECT) {
-      if (value->is_a(NullConstant::klass())) {
+    if (value->is_a(PrimitiveConstant::klass())) {
+      assert(!reference, "unexpected primitive constant type");
+      if (type == T_INT || type == T_FLOAT) {
+        jint prim = (jint)PrimitiveConstant::primitive(value);
+        return new ConstantIntValue(prim);
+      } else {
+        assert(type == T_LONG || type == T_DOUBLE, "unexpected primitive constant type");
+        jlong prim = PrimitiveConstant::primitive(value);
+        second = new ConstantIntValue(0);
+        return new ConstantLongValue(prim);
+      }
+    } else {
+        assert(reference, "unexpected object constant type");
+      if (value->is_a(NullConstant::klass()) || value->is_a(HotSpotCompressedNullConstant::klass())) {
         return new ConstantOopWriteValue(NULL);
       } else {
+        assert(value->is_a(HotSpotObjectConstant::klass()), "unexpected constant type");
         oop obj = HotSpotObjectConstant::object(value);
         assert(obj != NULL, "null value must be in NullConstant");
         return new ConstantOopWriteValue(JNIHandles::make_local(obj));
       }
-    } else if (type == T_ADDRESS) {
-      ShouldNotReachHere();
     }
-    tty->print("%i", type);
   } else if (value->is_a(VirtualObject::klass())) {
     oop type = VirtualObject::type(value);
     int id = VirtualObject::id(value);
@@ -558,7 +581,7 @@
       ShouldNotReachHere();
     }
   }
-
+  jint last_pc_offset = -1;
   for (int i = 0; i < _sites->length(); i++) {
     oop site = ((objArrayOop) (_sites))->obj_at(i);
     jint pc_offset = CompilationResult_Site::pcOffset(site);
@@ -576,6 +599,7 @@
         // if the infopoint is not an actual safepoint, it must have one of the other reasons
         // (safeguard against new safepoint types that require handling above)
         assert(InfopointReason::METHOD_START() == reason || InfopointReason::METHOD_END() == reason || InfopointReason::LINE_NUMBER() == reason, "");
+        site_Infopoint(buffer, pc_offset, site);
       }
     } else if (site->is_a(CompilationResult_DataPatch::klass())) {
       TRACE_graal_4("datapatch at %i", pc_offset);
@@ -586,6 +610,7 @@
     } else {
       fatal("unexpected Site subclass");
     }
+    last_pc_offset = pc_offset;
   }
 
 #ifndef PRODUCT
@@ -683,83 +708,95 @@
   return true;
 }
 
-void CodeInstaller::record_scope(jint pc_offset, oop frame, GrowableArray<ScopeValue*>* objects) {
-  assert(frame->klass() == BytecodeFrame::klass(), "BytecodeFrame expected");
-  oop caller_frame = BytecodePosition::caller(frame);
+void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArray<ScopeValue*>* objects) {
+  oop frame = NULL;
+  if (position->is_a(BytecodeFrame::klass())) {
+    frame = position;
+  }
+  oop caller_frame = BytecodePosition::caller(position);
   if (caller_frame != NULL) {
     record_scope(pc_offset, caller_frame, objects);
   }
 
-  oop hotspot_method = BytecodePosition::method(frame);
+  oop hotspot_method = BytecodePosition::method(position);
   Method* method = getMethodFromHotSpotMethod(hotspot_method);
-  jint bci = BytecodePosition::bci(frame);
+  jint bci = BytecodePosition::bci(position);
   if (bci == BytecodeFrame::BEFORE_BCI()) {
     bci = SynchronizationEntryBCI;
   }
-  bool reexecute;
-  if (bci == SynchronizationEntryBCI){
-     reexecute = false;
-  } else {
-    Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci));
-    reexecute = bytecode_should_reexecute(code);
-    if (frame != NULL) {
-      reexecute = (BytecodeFrame::duringCall(frame) == JNI_FALSE);
-    }
-  }
 
   if (TraceGraal >= 2) {
     tty->print_cr("Recording scope pc_offset=%d bci=%d method=%s", pc_offset, bci, method->name_and_sig_as_C_string());
   }
 
-  jint local_count = BytecodeFrame::numLocals(frame);
-  jint expression_count = BytecodeFrame::numStack(frame);
-  jint monitor_count = BytecodeFrame::numLocks(frame);
-  arrayOop values = (arrayOop) BytecodeFrame::values(frame);
-
-  assert(local_count + expression_count + monitor_count == values->length(), "unexpected values length");
-
-  GrowableArray<ScopeValue*>* locals = new GrowableArray<ScopeValue*> ();
-  GrowableArray<ScopeValue*>* expressions = new GrowableArray<ScopeValue*> ();
-  GrowableArray<MonitorValue*>* monitors = new GrowableArray<MonitorValue*> ();
-
-  if (TraceGraal >= 2) {
-    tty->print_cr("Scope at bci %d with %d values", bci, values->length());
-    tty->print_cr("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count);
-  }
-
-  for (jint i = 0; i < values->length(); i++) {
-    ScopeValue* second = NULL;
-    oop value=((objArrayOop) (values))->obj_at(i);
-    if (i < local_count) {
-      ScopeValue* first = get_scope_value(value, _total_frame_size, objects, second, _oop_recorder);
-      if (second != NULL) {
-        locals->append(second);
+  bool reexecute = false;
+  if (frame != NULL) {
+    if (bci == SynchronizationEntryBCI){
+       reexecute = false;
+    } else {
+      Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci));
+      reexecute = bytecode_should_reexecute(code);
+      if (frame != NULL) {
+        reexecute = (BytecodeFrame::duringCall(frame) == JNI_FALSE);
       }
-      locals->append(first);
-    } else if (i < local_count + expression_count) {
-      ScopeValue* first = get_scope_value(value, _total_frame_size, objects, second, _oop_recorder);
-      if (second != NULL) {
-        expressions->append(second);
-      }
-      expressions->append(first);
-    } else {
-      monitors->append(get_monitor_value(value, _total_frame_size, objects, _oop_recorder));
-    }
-    if (second != NULL) {
-      i++;
-      assert(i < values->length(), "double-slot value not followed by Value.ILLEGAL");
-      assert(((objArrayOop) (values))->obj_at(i) == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL");
     }
   }
 
+  DebugToken* locals_token = NULL;
+  DebugToken* expressions_token = NULL;
+  DebugToken* monitors_token = NULL;
+  bool throw_exception = false;
 
-  _debug_recorder->dump_object_pool(objects);
+  if (frame != NULL) {
+    jint local_count = BytecodeFrame::numLocals(frame);
+    jint expression_count = BytecodeFrame::numStack(frame);
+    jint monitor_count = BytecodeFrame::numLocks(frame);
+    arrayOop values = (arrayOop) BytecodeFrame::values(frame);
+
+    assert(local_count + expression_count + monitor_count == values->length(), "unexpected values length");
+
+    GrowableArray<ScopeValue*>* locals = new GrowableArray<ScopeValue*> ();
+    GrowableArray<ScopeValue*>* expressions = new GrowableArray<ScopeValue*> ();
+    GrowableArray<MonitorValue*>* monitors = new GrowableArray<MonitorValue*> ();
+
+    if (TraceGraal >= 2) {
+      tty->print_cr("Scope at bci %d with %d values", bci, values->length());
+      tty->print_cr("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count);
+    }
 
-  DebugToken* locals_token = _debug_recorder->create_scope_values(locals);
-  DebugToken* expressions_token = _debug_recorder->create_scope_values(expressions);
-  DebugToken* monitors_token = _debug_recorder->create_monitor_values(monitors);
+    for (jint i = 0; i < values->length(); i++) {
+      ScopeValue* second = NULL;
+      oop value=((objArrayOop) (values))->obj_at(i);
+      if (i < local_count) {
+        ScopeValue* first = get_scope_value(value, _total_frame_size, objects, second, _oop_recorder);
+        if (second != NULL) {
+          locals->append(second);
+        }
+        locals->append(first);
+      } else if (i < local_count + expression_count) {
+        ScopeValue* first = get_scope_value(value, _total_frame_size, objects, second, _oop_recorder);
+        if (second != NULL) {
+          expressions->append(second);
+        }
+        expressions->append(first);
+      } else {
+        monitors->append(get_monitor_value(value, _total_frame_size, objects, _oop_recorder));
+      }
+      if (second != NULL) {
+        i++;
+        assert(i < values->length(), "double-slot value not followed by Value.ILLEGAL");
+        assert(((objArrayOop) (values))->obj_at(i) == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL");
+      }
+    }
 
-  bool throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE;
+    _debug_recorder->dump_object_pool(objects);
+
+    locals_token = _debug_recorder->create_scope_values(locals);
+    expressions_token = _debug_recorder->create_scope_values(expressions);
+    monitors_token = _debug_recorder->create_monitor_values(monitors);
+
+    throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE;
+  }
 
   _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, locals_token, expressions_token, monitors_token);
 }
@@ -782,6 +819,20 @@
   _debug_recorder->end_safepoint(pc_offset);
 }
 
+void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site) {
+  oop debug_info = CompilationResult_Infopoint::debugInfo(site);
+  assert(debug_info != NULL, "debug info expected");
+
+  _debug_recorder->add_non_safepoint(pc_offset);
+
+  oop position = DebugInfo::bytecodePosition(debug_info);
+  if (position != NULL) {
+    record_scope(pc_offset, position, NULL);
+  }
+
+  _debug_recorder->end_non_safepoint(pc_offset);
+}
+
 void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, oop site) {
   oop target = CompilationResult_Call::target(site);
   InstanceKlass* target_klass = InstanceKlass::cast(target->klass());
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -115,6 +115,7 @@
   void assumption_CallSiteTargetValue(Handle assumption);
 
   void site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site);
+  void site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site);
   void site_Call(CodeBuffer& buffer, jint pc_offset, oop site);
   void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site);
   void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site);
--- a/src/share/vm/graal/graalJavaAccess.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -207,6 +207,8 @@
   end_class                                                                                                                                                    \
   start_class(NullConstant)                                                                                                                                    \
   end_class                                                                                                                                                    \
+  start_class(HotSpotCompressedNullConstant)                                                                                                                                    \
+  end_class                                                                                                                                                    \
   start_class(HotSpotObjectConstant)                                                                                                                           \
     oop_field(HotSpotObjectConstant, object, "Ljava/lang/Object;")                                                                                             \
   end_class                                                                                                                                                    \
@@ -223,8 +225,13 @@
     static_oop_field(Kind, Int, "Lcom/oracle/graal/api/meta/Kind;");                                                                                           \
     static_oop_field(Kind, Long, "Lcom/oracle/graal/api/meta/Kind;");                                                                                          \
   end_class                                                                                                                                                    \
+  start_class(LIRKind)                                                                                                                                         \
+    oop_field(LIRKind, platformKind, "Lcom/oracle/graal/api/meta/PlatformKind;")                                                                               \
+    int_field(LIRKind, referenceMask)                                                                                                                          \
+  end_class                                                                                                                                                    \
   start_class(Value)                                                                                                                                           \
     oop_field(Value, kind, "Lcom/oracle/graal/api/meta/Kind;")                                                                                                 \
+    oop_field(Value, lirKind, "Lcom/oracle/graal/api/meta/LIRKind;")                                                                                           \
     static_oop_field(Value, ILLEGAL, "Lcom/oracle/graal/api/meta/AllocatableValue;");                                                                          \
   end_class                                                                                                                                                    \
   start_class(RegisterValue)                                                                                                                                   \
--- a/src/share/vm/graal/graalRuntime.cpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/graal/graalRuntime.cpp	Wed Jul 30 10:39:39 2014 -0700
@@ -117,7 +117,6 @@
     case 'j': return T_LONG;
     case 'd': return T_DOUBLE;
     case 'a': return T_OBJECT;
-    case 'r': return T_ADDRESS;
     case '-': return T_ILLEGAL;
     default:
       fatal(err_msg("unexpected Kind: %c", ch));
--- a/src/share/vm/graal/vmStructs_graal.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/graal/vmStructs_graal.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -34,12 +34,14 @@
   nonstatic_field(InstanceKlass, _graal_node_class, oop)                      \
   nonstatic_field(ThreadShadow,  _pending_deoptimization, int)                \
   nonstatic_field(ThreadShadow,  _pending_failed_speculation, oop)            \
+  nonstatic_field(ThreadShadow,  _pending_transfer_to_interpreter, bool)      \
   nonstatic_field(MethodData,    _graal_node_count, int)                      \
 
 #define VM_TYPES_GRAAL(declare_type, declare_toplevel_type)                   \
 
 #define VM_INT_CONSTANTS_GRAAL(declare_constant, declare_preprocessor_constant)                   \
   declare_constant(Deoptimization::Reason_aliasing)                                               \
+  declare_constant(Deoptimization::Reason_transfer_to_interpreter)                                \
   declare_constant(GraalEnv::ok)                                                                  \
   declare_constant(GraalEnv::dependencies_failed)                                                 \
   declare_constant(GraalEnv::cache_full)                                                          \
--- a/src/share/vm/opto/chaitin.cpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/opto/chaitin.cpp	Wed Jul 30 10:39:39 2014 -0700
@@ -1682,9 +1682,21 @@
       // (where top() node is placed).
       base->init_req(0, _cfg.get_root_node());
       Block *startb = _cfg.get_block_for_node(C->top());
-      startb->insert_node(base, startb->find_node(C->top()));
+      uint node_pos = startb->find_node(C->top());
+      startb->insert_node(base, node_pos);
       _cfg.map_node_to_block(base, startb);
       assert(_lrg_map.live_range_id(base) == 0, "should not have LRG yet");
+
+      // The loadConP0 might have projection nodes depending on architecture
+      // Add the projection nodes to the CFG
+      for (DUIterator_Fast imax, i = base->fast_outs(imax); i < imax; i++) {
+        Node* use = base->fast_out(i);
+        if (use->is_MachProj()) {
+          startb->insert_node(use, ++node_pos);
+          _cfg.map_node_to_block(use, startb);
+          new_lrg(use, maxlrg++);
+        }
+      }
     }
     if (_lrg_map.live_range_id(base) == 0) {
       new_lrg(base, maxlrg++);
--- a/src/share/vm/runtime/deoptimization.cpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/runtime/deoptimization.cpp	Wed Jul 30 10:39:39 2014 -0700
@@ -1393,7 +1393,12 @@
       trap_bci = 0;
       Thread::current()->set_pending_monitorenter(true);
     }
+
+    if (reason == Deoptimization::Reason_transfer_to_interpreter) {
+      thread->set_pending_transfer_to_interpreter(true);
+    }
 #endif
+
     Bytecodes::Code trap_bc     = trap_method->java_code_at(trap_bci);
 
     if (trap_scope->rethrow_exception()) {
@@ -1996,7 +2001,10 @@
   "age" GRAAL_ONLY("_or_jsr_mismatch"),
   "predicate",
   "loop_limit_check",
-  GRAAL_ONLY("aliasing")
+#ifdef GRAAL
+  "aliasing",
+  "transfer_to_interpreter",
+#endif
 };
 const char* Deoptimization::_trap_action_name[Action_LIMIT] = {
   // Note:  Keep this in sync. with enum DeoptAction.
--- a/src/share/vm/runtime/deoptimization.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/runtime/deoptimization.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -74,6 +74,7 @@
     Reason_loop_limit_check,      // compiler generated loop limits check failed
 #ifdef GRAAL
     Reason_aliasing,              // optimistic assumption about aliasing failed
+    Reason_transfer_to_interpreter, // explicit transferToInterpreter()
 #endif
     Reason_LIMIT,
 
--- a/src/share/vm/utilities/exceptions.hpp	Wed Jul 30 09:36:32 2014 -0700
+++ b/src/share/vm/utilities/exceptions.hpp	Wed Jul 30 10:39:39 2014 -0700
@@ -65,6 +65,7 @@
   int _pending_deoptimization;
   oop _pending_failed_speculation;
   bool _pending_monitorenter;
+  bool _pending_transfer_to_interpreter;
 #endif
   oop  _pending_exception;                       // Thread has gc actions.
   const char* _exception_file;                   // file information for exception (debugging only)
@@ -100,6 +101,7 @@
   void set_pending_monitorenter(bool b)          { _pending_monitorenter = b; }
   void set_pending_deoptimization(int reason)    { _pending_deoptimization = reason; }
   void set_pending_failed_speculation(oop failed_speculation)    { _pending_failed_speculation = failed_speculation; }
+  void set_pending_transfer_to_interpreter(bool b) { _pending_transfer_to_interpreter = b; }
 #endif
 
   // use THROW whenever possible!
@@ -111,7 +113,7 @@
   ThreadShadow() : _pending_exception(NULL),
                    _exception_file(NULL), _exception_line(0)
 #ifdef GRAAL
-                   , _pending_monitorenter(false), _pending_deoptimization(-1), _pending_failed_speculation(NULL)
+                   , _pending_monitorenter(false), _pending_deoptimization(-1), _pending_failed_speculation(NULL), _pending_transfer_to_interpreter(false)
 #endif
   {}
 };