changeset 16329:281c30cf1952

Merge
author Stefan Anzinger <stefan.anzinger@gmail.com>
date Mon, 30 Jun 2014 18:17:13 +0200
parents 34ac3ddfd5ac (current diff) 8da760bd1575 (diff)
children 41d479400da8
files graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEvent.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEventLog.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java mx/projects
diffstat 39 files changed, 961 insertions(+), 334 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Jun 30 18:17:13 2014 +0200
@@ -90,7 +90,7 @@
      * Determines if verification is enabled in the current method, regardless of the
      * {@linkplain Debug#currentScope() current debug scope}.
      *
-     * @see Debug#verify(Object, Object)
+     * @see Debug#verify(Object, String)
      */
     public static boolean isVerifyEnabledForMethod() {
         if (!ENABLED) {
@@ -107,7 +107,7 @@
      * Determines if verification is enabled in the {@linkplain Debug#currentScope() current debug
      * scope}.
      *
-     * @see Debug#verify(Object, Object)
+     * @see Debug#verify(Object, String)
      */
     public static boolean isVerifyEnabled() {
         return ENABLED && DebugScope.getInstance().isVerifyEnabled();
@@ -491,13 +491,13 @@
      * config} to perform verification on a given object.
      *
      * @param object object to verify
-     * @param context object describing the context of verification
+     * @param message description of verification context
      *
-     * @see DebugVerifyHandler#verify(Object, Object...)
+     * @see DebugVerifyHandler#verify(Object, String)
      */
-    public static void verify(Object object, Object context) {
+    public static void verify(Object object, String message) {
         if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
-            DebugScope.getInstance().verify(object, context);
+            DebugScope.getInstance().verify(object, message);
         }
     }
 
@@ -506,28 +506,28 @@
      * config} to perform verification on a given object.
      *
      * @param object object to verify
-     * @param context1 first object describing the context of verification
-     * @param context2 second object describing the context of verification
+     * @param format a format string for the description of the verification context
+     * @param arg the argument referenced by the format specifiers in {@code format}
      *
-     * @see DebugVerifyHandler#verify(Object, Object...)
+     * @see DebugVerifyHandler#verify(Object, String)
      */
-    public static void verify(Object object, Object context1, Object context2) {
+    public static void verify(Object object, String format, Object arg) {
         if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
-            DebugScope.getInstance().verify(object, context1, context2);
+            DebugScope.getInstance().verify(object, format, arg);
         }
     }
 
     /**
-     * This override exists to catch cases when {@link #verify(Object, Object)} is called with one
-     * argument bound to a varargs method parameter. It will bind to this method instead of the
-     * single arg variant and produce a deprecation warning instead of silently wrapping the
+     * This override exists to catch cases when {@link #verify(Object, String, Object)} is called
+     * with one argument bound to a varargs method parameter. It will bind to this method instead of
+     * the single arg variant and produce a deprecation warning instead of silently wrapping the
      * Object[] inside of another Object[].
      */
     @Deprecated
-    public static void verify(Object object, Object[] args) {
+    public static void verify(Object object, String format, Object[] args) {
         assert false : "shouldn't use this";
         if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
-            DebugScope.getInstance().verify(object, args);
+            DebugScope.getInstance().verify(object, format, args);
         }
     }
 
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugVerifyHandler.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugVerifyHandler.java	Mon Jun 30 18:17:13 2014 +0200
@@ -31,25 +31,7 @@
      * Verifies that a given object satisfies some invariants.
      *
      * @param object object to verify
-     * @param context object(s) describing the context of verification
-     */
-    void verify(Object object, Object... context);
-
-    /**
-     * Extracts the first object of a given type from a verification input object.
+     * @param message description of verification context
      */
-    default <T> T extract(Class<T> type, Object input) {
-        if (type.isInstance(input)) {
-            return type.cast(input);
-        }
-        if (input instanceof Object[]) {
-            for (Object nestedContext : (Object[]) input) {
-                T object = extract(type, nestedContext);
-                if (object != null) {
-                    return object;
-                }
-            }
-        }
-        return null;
-    }
+    void verify(Object object, String message);
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Jun 30 18:17:13 2014 +0200
@@ -218,14 +218,15 @@
     }
 
     /**
-     * @see Debug#verify(Object, Object)
+     * @see Debug#verify(Object, String)
      */
-    public void verify(Object object, Object... ctx) {
+    public void verify(Object object, String formatString, Object... args) {
         if (isVerifyEnabled()) {
             DebugConfig config = getConfig();
             if (config != null) {
+                String message = String.format(formatString, args);
                 for (DebugVerifyHandler handler : config.verifyHandlers()) {
-                    handler.verify(object, ctx);
+                    handler.verify(object, message);
                 }
             }
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Jun 30 18:17:13 2014 +0200
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.GraphEvent.NodeEvent;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.NodeClass.NodeClassIterator;
 import com.oracle.graal.graph.NodeClass.Position;
@@ -39,8 +38,6 @@
 
     public final String name;
 
-    private static final boolean TIME_TRAVEL = false;
-
     /**
      * The set of nodes in the graph, ordered by {@linkplain #register(Node) registration} time.
      */
@@ -67,7 +64,6 @@
     private final ArrayList<Node> nodeCacheLast;
     private int nodesDeletedSinceLastCompression;
     private int nodesDeletedBeforeLastCompression;
-    private GraphEventLog eventLog;
 
     /**
      * The number of times this graph has been compressed.
@@ -302,16 +298,46 @@
     }
 
     /**
+     * The type of events sent to a {@link NodeEventListener}.
+     */
+    public enum NodeEvent {
+        /**
+         * A node's input is changed.
+         */
+        INPUT_CHANGED,
+
+        /**
+         * A node's {@linkplain Node#usages() usages} count dropped to zero.
+         */
+        ZERO_USAGES,
+
+        /**
+         * A node was added to a graph.
+         */
+        NODE_ADDED;
+    }
+
+    /**
      * Client interested in one or more node related events.
      */
     public interface NodeEventListener {
 
         /**
+         * Default handler for events.
+         *
+         * @param e an event
+         * @param node the node related to {@code e}
+         */
+        default void event(NodeEvent e, Node node) {
+        }
+
+        /**
          * Notifies this listener of a change in a node's inputs.
          *
          * @param node a node who has had one of its inputs changed
          */
         default void inputChanged(Node node) {
+            event(NodeEvent.INPUT_CHANGED, node);
         }
 
         /**
@@ -320,6 +346,7 @@
          * @param node a node whose {@link Node#usages()} just became empty
          */
         default void usagesDroppedToZero(Node node) {
+            event(NodeEvent.ZERO_USAGES, node);
         }
 
         /**
@@ -328,6 +355,7 @@
          * @param node a node that was just added to the graph
          */
         default void nodeAdded(Node node) {
+            event(NodeEvent.NODE_ADDED, node);
         }
     }
 
@@ -375,8 +403,8 @@
         }
 
         public void usagesDroppedToZero(Node node) {
-            head.inputChanged(node);
-            next.inputChanged(node);
+            head.usagesDroppedToZero(node);
+            next.usagesDroppedToZero(node);
         }
     }
 
@@ -851,36 +879,11 @@
         if (nodeEventListener != null) {
             nodeEventListener.nodeAdded(node);
         }
-        logNodeAdded(node);
-    }
-
-    void logNodeAdded(Node node) {
-        if (TIME_TRAVEL) {
-            log(new GraphEvent.NodeEvent(node, GraphEvent.NodeEvent.Type.ADDED));
-        }
-    }
-
-    void logNodeDeleted(Node node) {
-        if (TIME_TRAVEL) {
-            log(new GraphEvent.NodeEvent(node, GraphEvent.NodeEvent.Type.DELETED));
-        }
-    }
-
-    private void log(NodeEvent nodeEvent) {
-        if (eventLog == null) {
-            eventLog = new GraphEventLog();
-        }
-        eventLog.add(nodeEvent);
-    }
-
-    public GraphEventLog getEventLog() {
-        return eventLog;
     }
 
     void unregister(Node node) {
         assert !isFrozen();
         assert !node.isDeleted() : "cannot delete a node twice! node=" + node;
-        logNodeDeleted(node);
         nodes[node.id] = null;
         nodesDeletedSinceLastCompression++;
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEvent.java	Mon Jun 30 17:27:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.graph;
-
-import java.io.*;
-
-public abstract class GraphEvent {
-
-    private Exception exceptionContext;
-
-    public static class NodeEvent extends GraphEvent {
-
-        public static enum Type {
-            ADDED,
-            DELETED,
-            CHANGED
-        }
-
-        public final Node node;
-        public final Type type;
-        private final String nodeString;
-
-        public NodeEvent(Node n, Type type) {
-            this.node = n;
-            this.type = type;
-            nodeString = n.toString();
-        }
-
-        @Override
-        public StackTraceElement[] print(StackTraceElement[] last, PrintStream stream) {
-            stream.println(type.toString() + ", " + nodeString);
-            return super.print(last, stream);
-        }
-    }
-
-    public static class EdgeEvent extends GraphEvent {
-
-        public static enum Type {
-            INPUT,
-            SUCC
-        }
-
-        public final Node node;
-        public final int index;
-        public final Node newValue;
-        public final Type type;
-
-        public EdgeEvent(Node node, int index, Node newValue, Type type) {
-            this.node = node;
-            this.index = index;
-            this.newValue = newValue;
-            this.type = type;
-        }
-    }
-
-    public GraphEvent() {
-        exceptionContext = new Exception();
-    }
-
-    public StackTraceElement[] print(StackTraceElement[] last, PrintStream stream) {
-        StackTraceElement[] stackTrace = exceptionContext.getStackTrace();
-
-        boolean atTop = true;
-        for (int i = 0; i < stackTrace.length; ++i) {
-            StackTraceElement elem = stackTrace[i];
-            int toBottom = stackTrace.length - i;
-            if (atTop) {
-                if (!elem.getClassName().startsWith("com.oracle.graal.graph.Graph") && !elem.getClassName().startsWith("com.oracle.graal.graph.Node")) {
-                    atTop = false;
-                } else {
-                    continue;
-                }
-            } else {
-                if (last.length >= toBottom && last[last.length - toBottom].equals(elem)) {
-                    continue;
-                }
-            }
-            stream.println(String.format("%s.%s(%s:%d)", elem.getClassName(), elem.getMethodName(), elem.getFileName(), elem.getLineNumber()));
-        }
-        return stackTrace;
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEventLog.java	Mon Jun 30 17:27:35 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.graph;
-
-import java.io.*;
-import java.util.*;
-
-public class GraphEventLog {
-
-    private List<GraphEvent> events = new ArrayList<>();
-
-    public void add(GraphEvent e) {
-        this.events.add(e);
-    }
-
-    public void printEvents(PrintStream stream) {
-        StackTraceElement[] last = new StackTraceElement[0];
-        for (GraphEvent e : events) {
-            last = e.print(last, stream);
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -34,7 +34,7 @@
  *
  * @see ClassSubstitutions#cast(Class, Object)
  */
-public class ClassCastNode extends MacroNode implements Canonicalizable.Binary<ValueNode> {
+public class ClassCastNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
 
     public ClassCastNode(Invoke invoke) {
         super(invoke);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Mon Jun 30 18:17:13 2014 +0200
@@ -35,7 +35,7 @@
  * @see ClassSubstitutions#getClassLoader0(Class)
  */
 @SuppressWarnings("javadoc")
-public class ClassGetClassLoader0Node extends MacroNode implements Canonicalizable {
+public class ClassGetClassLoader0Node extends MacroStateSplitNode implements Canonicalizable {
 
     public ClassGetClassLoader0Node(Invoke invoke) {
         super(invoke);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -38,7 +38,7 @@
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class ArrayCopyNode extends MacroNode implements Virtualizable, Lowerable {
+public class ArrayCopyNode extends MacroStateSplitNode implements Virtualizable, Lowerable {
 
     public ArrayCopyNode(Invoke invoke) {
         super(invoke);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class CallSiteTargetNode extends MacroNode implements Canonicalizable, Lowerable {
+public class CallSiteTargetNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
 
     public CallSiteTargetNode(Invoke invoke) {
         super(invoke);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -44,7 +44,7 @@
 /**
  * Node for invocation methods defined on the class {@link MethodHandle}.
  */
-public class MethodHandleNode extends MacroNode implements Simplifiable {
+public class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
 
     /** The method that this node is representing. */
     private final IntrinsicMethod intrinsicMethod;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -39,7 +39,7 @@
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider {
+public class ObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider {
 
     public ObjectCloneNode(Invoke invoke) {
         super(invoke);
@@ -107,7 +107,7 @@
     /*
      * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
      * exact type) and if it is a cloneable type.
-     * 
+     *
      * If yes, then the exact type is returned, otherwise it returns null.
      */
     private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class ReflectionGetCallerClassNode extends MacroNode implements Canonicalizable, Lowerable {
+public class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
 
     public ReflectionGetCallerClassNode(Invoke invoke) {
         super(invoke);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java	Mon Jun 30 18:17:13 2014 +0200
@@ -0,0 +1,171 @@
+/*
+ * 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.test;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.ValuePositionProcedure;
+import com.oracle.graal.lir.asm.*;
+
+public class ValuePositionTest1 {
+
+    private static class NestedCompositeValue extends CompositeValue {
+
+        private static final long serialVersionUID = -8804214200173503527L;
+        @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
+
+        public NestedCompositeValue(Value value) {
+            super(LIRKind.Illegal);
+            this.value = value;
+        }
+
+    }
+
+    private static class DummyValue extends Value {
+
+        private static final long serialVersionUID = -645435039553382737L;
+        private final int id;
+        private static int counter = 1;
+
+        protected DummyValue() {
+            super(LIRKind.Illegal);
+            this.id = counter++;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + id;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            DummyValue other = (DummyValue) obj;
+            if (id != other.id) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    private static class TestOp extends LIRInstruction {
+
+        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
+
+        public TestOp(NestedCompositeValue compValue) {
+            this.compValue = compValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            fail("should not reach!");
+        }
+
+    }
+
+    private static LIRInstruction createNestedOp(Value value, int nestingLevel) {
+        NestedCompositeValue compValue = new NestedCompositeValue(value);
+        for (int i = 0; i < nestingLevel; i++) {
+            compValue = new NestedCompositeValue(compValue);
+        }
+        TestOp op = new TestOp(compValue);
+        return op;
+    }
+
+    @Test
+    public void nestedTest0() {
+        DummyValue dummyValue = new DummyValue();
+        LIRInstruction op = createNestedOp(dummyValue, 0);
+
+        List<ValuePosition> positions = new ArrayList<>();
+
+        op.forEachInput(new ValuePositionProcedure() {
+
+            @Override
+            public void doValue(LIRInstruction instruction, ValuePosition position) {
+                positions.add(position);
+            }
+        });
+
+        assertEquals(1, positions.size());
+        assertEquals(dummyValue, positions.get(0).get(op));
+    }
+
+    @Test
+    public void nestedTest1() {
+        DummyValue dummyValue = new DummyValue();
+        LIRInstruction op = createNestedOp(dummyValue, 1);
+
+        List<ValuePosition> positions = new ArrayList<>();
+
+        op.forEachInput(new ValuePositionProcedure() {
+
+            @Override
+            public void doValue(LIRInstruction instruction, ValuePosition position) {
+                positions.add(position);
+            }
+        });
+
+        assertEquals(1, positions.size());
+        assertEquals(dummyValue, positions.get(0).get(op));
+    }
+
+    @Test
+    public void nestedTest2() {
+        DummyValue dummyValue = new DummyValue();
+        LIRInstruction op = createNestedOp(dummyValue, 2);
+
+        List<ValuePosition> positions = new ArrayList<>();
+
+        op.forEachInput(new ValuePositionProcedure() {
+
+            @Override
+            public void doValue(LIRInstruction instruction, ValuePosition position) {
+                positions.add(position);
+            }
+        });
+
+        assertEquals(1, positions.size());
+        assertEquals(dummyValue, positions.get(0).get(op));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java	Mon Jun 30 18:17:13 2014 +0200
@@ -0,0 +1,149 @@
+/*
+ * 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.test;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.ValuePositionProcedure;
+import com.oracle.graal.lir.asm.*;
+
+public class ValuePositionTest2 {
+
+    private static class NestedCompositeValue extends CompositeValue {
+
+        private static final long serialVersionUID = -2243948303328857965L;
+        @Component({REG, OperandFlag.ILLEGAL}) protected Value value1;
+        @Component({REG, OperandFlag.ILLEGAL}) protected Value value2;
+
+        public NestedCompositeValue(Value value1, Value value2) {
+            super(LIRKind.Illegal);
+            this.value1 = value1;
+            this.value2 = value2;
+        }
+
+    }
+
+    private static class DummyValue extends Value {
+
+        private static final long serialVersionUID = 3620305384660607012L;
+        private final int id;
+        private static int counter = 0;
+
+        protected DummyValue() {
+            super(LIRKind.Illegal);
+            this.id = counter++;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + id;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!super.equals(obj)) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            DummyValue other = (DummyValue) obj;
+            if (id != other.id) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    private static class TestOp extends LIRInstruction {
+
+        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
+
+        public TestOp(NestedCompositeValue compValue) {
+            this.compValue = compValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            fail("should not reach!");
+        }
+
+    }
+
+    @Test
+    public void testSetGet() {
+        DummyValue dummyValue0 = new DummyValue();
+        DummyValue dummyValue1 = new DummyValue();
+        DummyValue dummyValue2 = new DummyValue();
+        DummyValue dummyValue3 = new DummyValue();
+
+        NestedCompositeValue compValue0 = new NestedCompositeValue(dummyValue0, dummyValue1);
+        NestedCompositeValue compValue1 = new NestedCompositeValue(compValue0, dummyValue2);
+        NestedCompositeValue compValue2 = new NestedCompositeValue(dummyValue3, compValue1);
+
+        LIRInstruction op = new TestOp(compValue2);
+        List<ValuePosition> positions = new ArrayList<>();
+
+        op.forEachInput(new ValuePositionProcedure() {
+
+            @Override
+            public void doValue(LIRInstruction instruction, ValuePosition position) {
+                positions.add(position);
+            }
+        });
+
+        assertEquals(4, positions.size());
+
+        // replace values
+        List<Value> replValues = new ArrayList<>();
+        for (ValuePosition pos : positions) {
+            Value v = new DummyValue();
+            replValues.add(v);
+            pos.set(op, v);
+
+        }
+
+        // check replaced values
+        Iterator<Value> it = replValues.iterator();
+        for (ValuePosition pos : positions) {
+            Value v = pos.get(op);
+            assertEquals(it.next(), v);
+        }
+        assertFalse(it.hasNext());
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Mon Jun 30 18:17:13 2014 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValuePositionProcedure;
 
 /**
  * Base class to represent values that need to be stored in more than one register.
@@ -58,6 +59,10 @@
         valueClass.forEachComponent(inst, this, mode, proc);
     }
 
+    public final void forEachComponent(LIRInstruction inst, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
+        valueClass.forEachComponent(inst, this, mode, proc, outerPosition);
+    }
+
     @Override
     public String toString() {
         return valueClass.toString(this);
@@ -76,4 +81,9 @@
         }
         return false;
     }
+
+    CompositeValueClass getValueClass() {
+        return valueClass;
+    }
+
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Mon Jun 30 18:17:13 2014 +0200
@@ -25,11 +25,13 @@
 import java.lang.reflect.*;
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.CompositeValue.Component;
 import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValuePositionProcedure;
 
 /**
  * Lazily associated metadata for every {@link CompositeValue} type. The metadata includes:
@@ -143,6 +145,10 @@
         forEach(inst, obj, directComponentCount, componentOffsets, mode, componentFlags, proc);
     }
 
+    public final void forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
+        forEach(inst, obj, directComponentCount, componentOffsets, mode, componentFlags, proc, outerPosition);
+    }
+
     public String toString(CompositeValue obj) {
         StringBuilder result = new StringBuilder();
 
@@ -154,4 +160,16 @@
 
         return result.toString();
     }
+
+    Value getValue(CompositeValue obj, ValuePosition pos) {
+        return getValueForPosition(obj, componentOffsets, directComponentCount, pos);
+    }
+
+    void setValue(CompositeValue obj, ValuePosition pos, Value value) {
+        setValueForPosition(obj, componentOffsets, directComponentCount, pos, value);
+    }
+
+    EnumSet<OperandFlag> getFlags(ValuePosition pos) {
+        return componentFlags[pos.getIndex()];
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Jun 30 18:17:13 2014 +0200
@@ -42,6 +42,22 @@
     public static final Value[] NO_OPERANDS = {};
 
     /**
+     * Iterator for iterating over a list of {@linkplain ValuePosition value positions}.
+     */
+    public abstract static class ValuePositionProcedure {
+
+        /**
+         * Iterator method to be overwritten. This version of the iterator does not take additional
+         * parameters to keep the signature short.
+         *
+         * @param instruction The current instruction.
+         * @param position The position of the value that is iterated.
+         */
+
+        public abstract void doValue(LIRInstruction instruction, ValuePosition position);
+    }
+
+    /**
      * Iterator for iterating over a list of values. Subclasses must overwrite one of the doValue
      * methods. Clients of the class must only call the doValue method that takes additional
      * parameters.
@@ -297,6 +313,22 @@
         return false;
     }
 
+    public final void forEachInput(ValuePositionProcedure proc) {
+        instructionClass.forEachUse(this, proc);
+    }
+
+    public final void forEachAlive(ValuePositionProcedure proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
+
+    public final void forEachTemp(ValuePositionProcedure proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
+
+    public final void forEachOutput(ValuePositionProcedure proc) {
+        instructionClass.forEachDef(this, proc);
+    }
+
     public final void forEachInput(InstructionValueProcedure proc) {
         instructionClass.forEachUse(this, proc);
     }
@@ -354,4 +386,8 @@
     public String toString() {
         return instructionClass.toString(this);
     }
+
+    public LIRInstructionClass getLIRInstructionClass() {
+        return instructionClass;
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Jun 30 18:17:13 2014 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.LIRInstruction.StateProcedure;
+import com.oracle.graal.lir.LIRInstruction.ValuePositionProcedure;
 
 public class LIRInstructionClass extends LIRIntrospection {
 
@@ -241,6 +242,73 @@
         return str.toString();
     }
 
+    Value getValue(LIRInstruction obj, ValuePosition pos) {
+        long[] offsets;
+        int directCount;
+        switch (pos.getMode()) {
+            case USE:
+                directCount = directUseCount;
+                offsets = useOffsets;
+                break;
+            case ALIVE:
+                directCount = directAliveCount;
+                offsets = aliveOffsets;
+                break;
+            case TEMP:
+                directCount = directTempCount;
+                offsets = tempOffsets;
+                break;
+            case DEF:
+                directCount = directDefCount;
+                offsets = defOffsets;
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
+        }
+        return getValueForPosition(obj, offsets, directCount, pos);
+    }
+
+    void setValue(LIRInstruction obj, ValuePosition pos, Value value) {
+        long[] offsets;
+        int directCount;
+        switch (pos.getMode()) {
+            case USE:
+                directCount = directUseCount;
+                offsets = useOffsets;
+                break;
+            case ALIVE:
+                directCount = directAliveCount;
+                offsets = aliveOffsets;
+                break;
+            case TEMP:
+                directCount = directTempCount;
+                offsets = tempOffsets;
+                break;
+            case DEF:
+                directCount = directDefCount;
+                offsets = defOffsets;
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
+        }
+        setValueForPosition(obj, offsets, directCount, pos, value);
+    }
+
+    EnumSet<OperandFlag> getFlags(ValuePosition pos) {
+        switch (pos.getMode()) {
+            case USE:
+                return useFlags[pos.getIndex()];
+            case ALIVE:
+                return aliveFlags[pos.getIndex()];
+            case TEMP:
+                return tempFlags[pos.getIndex()];
+            case DEF:
+                return defFlags[pos.getIndex()];
+            default:
+                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
+        }
+    }
+
     public final String getOpcode(LIRInstruction obj) {
         if (opcodeConstant != null) {
             return opcodeConstant;
@@ -262,6 +330,22 @@
         return false;
     }
 
+    public final void forEachUse(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    }
+
+    public final void forEachAlive(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    }
+
+    public final void forEachTemp(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    }
+
+    public final void forEachDef(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    }
+
     public final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) {
         forEach(obj, obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Mon Jun 30 18:17:13 2014 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.lir.LIRInstruction.InstructionValueProcedure;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValuePositionProcedure;
 
 abstract class LIRIntrospection extends FieldIntrospection {
 
@@ -146,6 +147,49 @@
         }
     }
 
+    protected static void forEach(LIRInstruction inst, Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValuePositionProcedure proc,
+                    ValuePosition outerPosition) {
+        for (int i = 0; i < offsets.length; i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+
+            if (i < directCount) {
+                Value value = getValue(obj, offsets[i]);
+                doForValue(inst, mode, proc, outerPosition, i, ValuePosition.NO_SUBINDEX, value);
+            } else {
+                Value[] values = getValueArray(obj, offsets[i]);
+                for (int j = 0; j < values.length; j++) {
+                    Value value = values[j];
+                    doForValue(inst, mode, proc, outerPosition, i, j, value);
+                }
+            }
+        }
+    }
+
+    private static void doForValue(LIRInstruction inst, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition, int index, int subIndex, Value value) {
+        ValuePosition position = new ValuePosition(mode, index, subIndex, outerPosition);
+        if (value instanceof CompositeValue) {
+            CompositeValue composite = (CompositeValue) value;
+            composite.forEachComponent(inst, mode, proc, position);
+        } else {
+            proc.doValue(inst, position);
+        }
+    }
+
+    protected static Value getValueForPosition(Object obj, long[] offsets, int directCount, ValuePosition pos) {
+        if (pos.getIndex() < directCount) {
+            return getValue(obj, offsets[pos.getIndex()]);
+        }
+        return getValueArray(obj, offsets[pos.getIndex()])[pos.getSubIndex()];
+    }
+
+    protected static void setValueForPosition(Object obj, long[] offsets, int directCount, ValuePosition pos, Value value) {
+        if (pos.getIndex() < directCount) {
+            setValue(obj, offsets[pos.getIndex()], value);
+        } else {
+            getValueArray(obj, offsets[pos.getIndex()])[pos.getSubIndex()] = value;
+        }
+    }
+
     protected static Value getValue(Object obj, long offset) {
         return (Value) unsafe.getObject(obj, offset);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java	Mon Jun 30 18:17:13 2014 +0200
@@ -0,0 +1,145 @@
+/*
+ * 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 java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.LIRInstruction.*;
+
+/**
+ * Describes an operand slot for a {@link LIRInstructionClass}.
+ */
+public final class ValuePosition {
+
+    private final OperandMode mode;
+    private final int index;
+    private final int subIndex;
+    private final ValuePosition outerPosition;
+
+    public static final int NO_SUBINDEX = -1;
+    public static final ValuePosition ROOT_VALUE_POSITION = null;
+
+    public ValuePosition(OperandMode mode, int index, int subIndex, ValuePosition outerPosition) {
+        this.mode = mode;
+        this.index = index;
+        this.subIndex = subIndex;
+        this.outerPosition = outerPosition;
+    }
+
+    public boolean isCompositePosition() {
+        return outerPosition != ROOT_VALUE_POSITION;
+    }
+
+    public Value get(LIRInstruction inst) {
+        if (isCompositePosition()) {
+            CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
+            return compValue.getValueClass().getValue(compValue, this);
+        }
+        return inst.getLIRInstructionClass().getValue(inst, this);
+    }
+
+    public EnumSet<OperandFlag> getFlags(LIRInstruction inst) {
+        if (isCompositePosition()) {
+            CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
+            return compValue.getValueClass().getFlags(this);
+        }
+        return inst.getLIRInstructionClass().getFlags(this);
+    }
+
+    public void set(LIRInstruction inst, Value value) {
+        if (isCompositePosition()) {
+            CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
+            compValue.getValueClass().setValue(compValue, this, value);
+        } else {
+            inst.getLIRInstructionClass().setValue(inst, this, value);
+        }
+    }
+
+    public int getSubIndex() {
+        return subIndex;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public OperandMode getMode() {
+        return mode;
+    }
+
+    public ValuePosition getSuperPosition() {
+        return outerPosition;
+    }
+
+    @Override
+    public String toString() {
+        if (outerPosition == ROOT_VALUE_POSITION) {
+            return mode.toString() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")";
+        }
+        return outerPosition.toString() + "[" + mode.toString() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + index;
+        result = prime * result + ((mode == null) ? 0 : mode.hashCode());
+        result = prime * result + subIndex;
+        result = prime * result + ((outerPosition == null) ? 0 : outerPosition.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ValuePosition other = (ValuePosition) obj;
+        if (index != other.index) {
+            return false;
+        }
+        if (mode != other.mode) {
+            return false;
+        }
+        if (subIndex != other.subIndex) {
+            return false;
+        }
+        if (outerPosition == null) {
+            if (other.outerPosition != null) {
+                return false;
+            }
+        } else if (!outerPosition.equals(other.outerPosition)) {
+            return false;
+        }
+        return true;
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -163,6 +163,9 @@
             int numEnds = this.forwardEndCount();
             for (int i = 0; i < numEnds - 1; i++) {
                 AbstractEndNode end = forwardEndAt(numEnds - 1 - i);
+                if (tool != null) {
+                    tool.addToWorkList(end);
+                }
                 AbstractEndNode newEnd;
                 if (merge instanceof LoopBeginNode) {
                     newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge));
@@ -207,6 +210,9 @@
             List<AbstractEndNode> endNodes = forwardEnds().snapshot();
             for (AbstractEndNode end : endNodes) {
                 ReturnNode newReturn = graph().add(new ReturnNode(returnValuePhi == null ? returnNode.result() : returnValuePhi.valueAt(end)));
+                if (tool != null) {
+                    tool.addToWorkList(end.predecessor());
+                }
                 end.replaceAtPredecessor(newReturn);
             }
             GraphUtil.killCFG(this);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Mon Jun 30 18:17:13 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.common;
 
+import static com.oracle.graal.graph.Graph.NodeEvent.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.*;
@@ -44,7 +46,7 @@
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
         ConditionalEliminationPhase eliminate = new ConditionalEliminationPhase(context.getMetaAccess());
-        HashSetNodeEventListener listener = new HashSetNodeEventListener.ExceptForAddedNodes();
+        HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NODE_ADDED);
         int count = 0;
         while (true) {
             try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java	Mon Jun 30 18:17:13 2014 +0200
@@ -22,13 +22,15 @@
  */
 package com.oracle.graal.phases.common.cfs;
 
+import static com.oracle.graal.graph.Graph.NodeEvent.*;
+
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Graph.NodeEventScope;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.util.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -47,7 +49,7 @@
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
         FlowSensitiveReductionPhase eliminate = new FlowSensitiveReductionPhase(context.getMetaAccess());
-        HashSetNodeEventListener listener = new HashSetNodeEventListener.ExceptForAddedNodes();
+        HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NODE_ADDED);
         int count = 1;
         while (true) {
             try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeEventListener.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeEventListener.java	Mon Jun 30 18:17:13 2014 +0200
@@ -24,7 +24,7 @@
 
 import java.util.*;
 
-import com.oracle.graal.graph.Graph.NodeEventListener;
+import com.oracle.graal.graph.Graph.*;
 import com.oracle.graal.graph.*;
 
 /**
@@ -33,36 +33,42 @@
  */
 public class HashSetNodeEventListener implements NodeEventListener {
 
+    private final Set<Node> nodes;
+    private final Set<NodeEvent> filter;
+
     /**
-     * Accumulates all node events except for {@link NodeEventListener#nodeAdded(Node) node
-     * additions}.
+     * Creates a {@link NodeEventListener} that collects nodes from all events.
+     */
+    public HashSetNodeEventListener() {
+        this.nodes = new HashSet<>();
+        this.filter = EnumSet.allOf(NodeEvent.class);
+    }
+
+    /**
+     * Creates a {@link NodeEventListener} that collects nodes from all events that match a given
+     * filter.
      */
-    public static class ExceptForAddedNodes extends HashSetNodeEventListener {
-        @Override
-        public void nodeAdded(Node node) {
+    public HashSetNodeEventListener(Set<NodeEvent> filter) {
+        this.nodes = new HashSet<>();
+        this.filter = filter;
+    }
+
+    /**
+     * Excludes a given event from those for which nodes are collected.
+     */
+    public HashSetNodeEventListener exclude(NodeEvent e) {
+        filter.remove(e);
+        return this;
+    }
+
+    public void event(NodeEvent e, Node node) {
+        if (filter.contains(e)) {
+            nodes.add(node);
         }
     }
 
-    private final Set<Node> nodes;
-
-    public HashSetNodeEventListener() {
-        this.nodes = new HashSet<>();
-    }
-
-    public void nodeAdded(Node node) {
-        nodes.add(node);
-    }
-
-    public void inputChanged(Node node) {
-        nodes.add(node);
-    }
-
-    public void usagesDroppedToZero(Node node) {
-        nodes.add(node);
-    }
-
     /**
-     * Gets the set of nodes that were communicated to this listener.
+     * Gets the set being used to accumulate the nodes communicated to this listener.
      */
     public Set<Node> getNodes() {
         return nodes;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon Jun 30 18:17:13 2014 +0200
@@ -101,7 +101,7 @@
                 Debug.dump(graph, "After phase %s", getName());
             }
             if (Debug.isVerifyEnabled()) {
-                Debug.verify(graph, this, "After phase " + getName());
+                Debug.verify(graph, "After phase %s", getName());
             }
             assert graph.verify();
         } catch (Throwable t) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/NoDeadCodeVerifyHandler.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/NoDeadCodeVerifyHandler.java	Mon Jun 30 18:17:13 2014 +0200
@@ -25,14 +25,12 @@
 import static com.oracle.graal.printer.NoDeadCodeVerifyHandler.Options.*;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
-import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 
 /**
@@ -54,34 +52,24 @@
         // @formatter:on
     }
 
-    private static final Map<Class<?>, Boolean> discovered = new ConcurrentHashMap<>();
-
-    public void verify(Object object, Object... context) {
-        if (NDCV.getValue() != OFF) {
-            StructuredGraph graph = extract(StructuredGraph.class, object);
-            BasePhase<?> phase = extract(BasePhase.class, context);
-            assert phase != null : "a Phase context is required by " + getClass().getSimpleName();
-            if (graph != null) {
-                List<Node> before = graph.getNodes().snapshot();
-                new DeadCodeEliminationPhase().run(graph);
-                List<Node> after = graph.getNodes().snapshot();
-                assert after.size() <= before.size();
-                if (before.size() != after.size()) {
-                    before.removeAll(after);
-                    if (discovered.put(phase.getClass(), Boolean.TRUE) == null) {
-                        String message = extract(String.class, context);
-                        String prefix = message == null ? "" : message + ": ";
-                        String phaseClass = phase.getClass().getName();
-                        GraalInternalError error = new GraalInternalError("%sfound dead nodes in %s (phase class=%s): %s", prefix, graph, phaseClass, before);
-                        if (NDCV.getValue() == INFO) {
-                            System.out.println(error.getMessage());
-                        } else if (NDCV.getValue() == VERBOSE) {
-                            error.printStackTrace(System.out);
-                        } else {
-                            assert NDCV.getValue() == FATAL;
-                            throw error;
-                        }
-                    }
+    public void verify(Object object, String message) {
+        if (NDCV.getValue() != OFF && object instanceof StructuredGraph) {
+            StructuredGraph graph = (StructuredGraph) object;
+            List<Node> before = graph.getNodes().snapshot();
+            new DeadCodeEliminationPhase().run(graph);
+            List<Node> after = graph.getNodes().snapshot();
+            assert after.size() <= before.size();
+            if (before.size() != after.size()) {
+                before.removeAll(after);
+                String prefix = message == null ? "" : message + ": ";
+                GraalInternalError error = new GraalInternalError("%sfound dead nodes in %s: %s", prefix, graph, before);
+                if (NDCV.getValue() == INFO) {
+                    System.out.println(error.getMessage());
+                } else if (NDCV.getValue() == VERBOSE) {
+                    error.printStackTrace(System.out);
+                } else {
+                    assert NDCV.getValue() == FATAL;
+                    throw error;
                 }
             }
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Jun 30 18:17:13 2014 +0200
@@ -687,24 +687,23 @@
         List<ReturnNode> returnNodes = snippet.getNodes(ReturnNode.class).snapshot();
         if (returnNodes.isEmpty()) {
             this.returnNode = null;
-            this.memoryMap = null;
         } else if (returnNodes.size() == 1) {
             this.returnNode = returnNodes.get(0);
-            this.memoryMap = returnNode.getMemoryMap();
         } else {
             MergeNode merge = snippet.add(new MergeNode());
             List<MemoryMapNode> memMaps = returnNodes.stream().map(n -> n.getMemoryMap()).collect(Collectors.toList());
             ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
             this.returnNode = snippet.add(new ReturnNode(returnValue));
             MemoryMapImpl mmap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps);
-            this.memoryMap = snippet.unique(new MemoryMapNode(mmap.getMap()));
-            merge.setNext(this.returnNode);
-
+            MemoryMapNode memoryMap = snippet.unique(new MemoryMapNode(mmap.getMap()));
+            this.returnNode.setMemoryMap(memoryMap);
             for (MemoryMapNode mm : memMaps) {
-                if (mm.isAlive()) {
-                    mm.safeDelete();
+                if (mm != memoryMap && mm.isAlive()) {
+                    assert mm.usages().isEmpty();
+                    GraphUtil.killWithUnusedFloatingInputs(mm);
                 }
             }
+            merge.setNext(this.returnNode);
         }
 
         this.sideEffectNodes = curSideEffectNodes;
@@ -794,11 +793,6 @@
     private final ArrayList<Node> nodes;
 
     /**
-     * Map of killing locations to memory checkpoints (nodes).
-     */
-    private final MemoryMapNode memoryMap;
-
-    /**
      * Times instantiations of this template.
      *
      * @see SnippetInfo#instantiationTimer
@@ -957,6 +951,7 @@
             // no floating reads yet, ignore locations created while lowering
             return true;
         }
+        MemoryMapNode memoryMap = returnNode.getMemoryMap();
         if (memoryMap == null || memoryMap.isEmpty()) {
             // there are no kills in the snippet graph
             return true;
@@ -1018,6 +1013,7 @@
 
         @Override
         public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+            MemoryMapNode memoryMap = returnNode.getMemoryMap();
             assert memoryMap != null : "no memory map stored for this snippet graph (snippet doesn't have a ReturnNode?)";
             MemoryNode lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
             assert lastLocationAccess != null;
@@ -1030,7 +1026,7 @@
 
         @Override
         public Collection<LocationIdentity> getLocations() {
-            return memoryMap.getLocations();
+            return returnNode.getMemoryMap().getLocations();
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,13 +24,13 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
-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.*;
@@ -39,7 +39,22 @@
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
 
-public class MacroNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+/**
+ * Macro nodes can be used to temporarily replace an invoke (usually by using the
+ * {@link MacroSubstitution} annotation). They can, for example, be used to implement constant
+ * folding for known JDK functions like {@link Class#isInterface()}.<br/>
+ * <br/>
+ * During lowering, multiple sources are queried in order to look for a replacement:
+ * <ul>
+ * <li>If {@link #getLoweredSnippetGraph(LoweringTool)} returns a non-null result, this graph is
+ * used as a replacement.</li>
+ * <li>If a {@link MethodSubstitution} for the target method is found, this substitution is used as
+ * a replacement.</li>
+ * <li>Otherwise, the macro node is replaced with an {@link InvokeNode}. Note that this is only
+ * possible if the macro node is a {@link MacroStateSplitNode}.</li>
+ * </ul>
+ */
+public class MacroNode extends FixedWithNextNode implements Lowerable {
 
     @Input protected final NodeInputList<ValueNode> arguments;
 
@@ -49,7 +64,7 @@
     private final InvokeKind invokeKind;
 
     protected MacroNode(Invoke invoke) {
-        super(invoke.asNode().stamp(), invoke.stateAfter());
+        super(StampFactory.forKind(((MethodCallTargetNode) invoke.callTarget()).targetMethod().getSignature().getReturnKind()));
         MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
         this.arguments = new NodeInputList<>(this, methodCallTarget.arguments());
         this.bci = invoke.bci();
@@ -70,6 +85,10 @@
         return returnType;
     }
 
+    protected FrameState stateAfter() {
+        return null;
+    }
+
     /**
      * Gets a snippet to be used for lowering this macro node. The returned graph (if non-null) must
      * have been {@linkplain #lowerReplacement(StructuredGraph, LoweringTool) lowered}.
@@ -145,6 +164,7 @@
             InliningUtil.inline(invoke, replacementGraph, false, null);
             Debug.dump(graph(), "After inlining replacement %s", replacementGraph);
         } else {
+            assert stateAfter() != null : "cannot lower to invoke without state: " + this;
             invoke.lower(tool);
         }
     }
@@ -166,23 +186,4 @@
         }
         return invoke;
     }
-
-    protected void replaceSnippetInvokes(StructuredGraph snippetGraph) {
-        for (MethodCallTargetNode call : snippetGraph.getNodes(MethodCallTargetNode.class)) {
-            Invoke invoke = call.invoke();
-            if (!call.targetMethod().equals(getTargetMethod())) {
-                throw new GraalInternalError("unexpected invoke %s in snippet", getClass().getSimpleName());
-            }
-            assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI;
-            // Here we need to fix the bci of the invoke
-            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci()));
-            newInvoke.setStateAfter(invoke.stateAfter());
-            snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
-        }
-    }
-
-    @Override
-    public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * This is an extension of {@link MacroNode} that is a {@link StateSplit} and a
+ * {@link MemoryCheckpoint}.
+ */
+public class MacroStateSplitNode extends MacroNode implements StateSplit, MemoryCheckpoint.Single {
+
+    @Input(InputType.State) private FrameState stateAfter;
+
+    protected MacroStateSplitNode(Invoke invoke) {
+        super(invoke);
+        this.stateAfter = invoke.stateAfter();
+    }
+
+    @Override
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.ANY_LOCATION;
+    }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+
+    protected void replaceSnippetInvokes(StructuredGraph snippetGraph) {
+        for (MethodCallTargetNode call : snippetGraph.getNodes(MethodCallTargetNode.class)) {
+            Invoke invoke = call.invoke();
+            if (!call.targetMethod().equals(getTargetMethod())) {
+                throw new GraalInternalError("unexpected invoke %s in snippet", getClass().getSimpleName());
+            }
+            assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI;
+            // Here we need to fix the bci of the invoke
+            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci()));
+            newInvoke.setStateAfter(invoke.stateAfter());
+            snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -31,7 +31,7 @@
  * This node class can be used to create {@link MacroNode}s for simple pure functions like
  * {@link System#identityHashCode(Object)}.
  */
-public abstract class PureFunctionMacroNode extends MacroNode implements Canonicalizable {
+public abstract class PureFunctionMacroNode extends MacroStateSplitNode implements Canonicalizable {
 
     public PureFunctionMacroNode(Invoke invoke) {
         super(invoke);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,11 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.truffle.*;
 
@@ -50,6 +53,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        throw new GraalInternalError(GraphUtil.approxSourceException(this, new RuntimeException("assumption could not be evaluated to a constant")));
+    }
+
+    @Override
     public void simplify(SimplifierTool tool) {
         ValueNode assumption = getAssumption();
         if (tool.assumptions() != null && assumption.isConstant()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/BailoutNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/BailoutNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
 public class BailoutNode extends MacroNode implements Canonicalizable {
@@ -35,13 +36,20 @@
         assert arguments.size() == 1;
     }
 
+    public ValueNode getMessage() {
+        return arguments.get(0);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)");
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        ValueNode arg = arguments.get(0);
-        String message = "";
-        if (arg.isConstant()) {
-            message = arg.asConstant().toValueString();
+        if (getMessage().isConstant()) {
+            throw new BailoutException(getMessage().asConstant().toValueString());
         }
-        throw new BailoutException(message);
+        return this;
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class NeverInlineMacroNode extends MacroNode implements com.oracle.graal.graph.IterableNodeType {
+public class NeverInlineMacroNode extends MacroStateSplitNode implements com.oracle.graal.graph.IterableNodeType {
 
     public NeverInlineMacroNode(Invoke invoke) {
         super(invoke);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.truffle.nodes.asserts;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.nodes.*;
 
-public class NeverPartOfCompilationNode extends MacroNode implements com.oracle.graal.graph.IterableNodeType {
+public class NeverPartOfCompilationNode extends MacroNode implements IterableNodeType {
 
     private final String message;
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Mon Jun 30 18:17:13 2014 +0200
@@ -34,7 +34,9 @@
 /**
  * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean)}.
  */
-public class CustomizedUnsafeStoreMacroNode extends NeverPartOfCompilationNode implements Canonicalizable {
+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;
@@ -45,6 +47,7 @@
     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
@@ -61,8 +64,21 @@
                 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.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Mon Jun 30 17:27:35 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Mon Jun 30 18:17:13 2014 +0200
@@ -91,7 +91,7 @@
                 }
 
                 // apply the effects collected during this iteration
-                HashSetNodeEventListener listener = new HashSetNodeEventListener.ExceptForAddedNodes();
+                HashSetNodeEventListener listener = new HashSetNodeEventListener();
                 try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
                     closure.applyEffects();
                 }
--- a/mx/projects	Mon Jun 30 17:27:35 2014 +0200
+++ b/mx/projects	Mon Jun 30 18:17:13 2014 +0200
@@ -345,6 +345,14 @@
 project@com.oracle.graal.lir@javaCompliance=1.8
 project@com.oracle.graal.lir@workingSets=Graal,LIR
 
+# graal.lir.test
+project@com.oracle.graal.lir.test@subDir=graal
+project@com.oracle.graal.lir.test@sourceDirs=src
+project@com.oracle.graal.lir.test@dependencies=JUNIT,com.oracle.graal.lir
+project@com.oracle.graal.lir.test@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.lir.test@javaCompliance=1.8
+project@com.oracle.graal.lir.test@workingSets=Graal,LIR
+
 # graal.lir.amd64
 project@com.oracle.graal.lir.amd64@subDir=graal
 project@com.oracle.graal.lir.amd64@sourceDirs=src
--- a/src/share/vm/graal/graalRuntime.cpp	Mon Jun 30 17:27:35 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Mon Jun 30 18:17:13 2014 +0200
@@ -778,7 +778,7 @@
   if (!recognized) {
     bool throw_err = hotSpotOptionsClass.is_null();
     if (!hotSpotOptionsClass.is_null()) {
-      set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), ' ', Handle(), 0L);
+      set_option_helper(hotSpotOptionsClass, name, (int)name_len, Handle(), ' ', Handle(), 0L);
       if (!HAS_PENDING_EXCEPTION) {
         throw_err = true;
       }