changeset 8987:dcb9f151f0ec

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Wed, 10 Apr 2013 15:00:22 +0200
parents 3bc8ee03834e (current diff) fee450a11838 (diff)
children 02f57662b6c4
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignementPhase.java
diffstat 15 files changed, 238 insertions(+), 202 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Wed Apr 10 15:00:22 2013 +0200
@@ -58,8 +58,11 @@
     /**
      * Determines if this method should be substituted in all cases, even if inlining thinks it is
      * not important.
+     * 
+     * Not that this is still depending on whether inlining sees the correct call target, so it's
+     * only a hard guarantee for static and special invocations.
      */
-    boolean isForcedInlining() default false;
+    boolean forced() default false;
 
     /**
      * Determines if the substitution is for a method that may not be part of the runtime. For
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Wed Apr 10 15:00:22 2013 +0200
@@ -189,6 +189,42 @@
         return result;
     }
 
+    @Test
+    public void testComparison() {
+        compareGraphs("testComparison1Snippet", "referenceComparisonSnippet");
+        compareGraphs("testComparison2Snippet", "referenceComparisonSnippet");
+    }
+
+    @SuppressWarnings("cast")
+    public static boolean testComparison1Snippet(int a, int b) {
+        return ((Integer) a) == b;
+    }
+
+    public static boolean testComparison2Snippet(int a, int b) {
+        Integer x = a;
+        Integer y = b;
+        return x == y;
+    }
+
+    public static boolean referenceComparisonSnippet(int a, int b) {
+        return a == b;
+    }
+
+    @Test
+    public void testLateCanonicalization() {
+        compareGraphs("testLateCanonicalizationSnippet", "referenceLateCanonicalizationSnippet");
+    }
+
+    public static boolean testLateCanonicalizationSnippet(int a) {
+        Integer x = a;
+        Integer y = 1000;
+        return x == y;
+    }
+
+    public static boolean referenceLateCanonicalizationSnippet(int a) {
+        return a == 1000;
+    }
+
     private StructuredGraph graph;
 
     public static Integer materializeReferenceSnippet(int a) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Apr 10 15:00:22 2013 +0200
@@ -225,7 +225,9 @@
 
         new LoweringPhase(target, runtime, replacements, assumptions).apply(graph);
 
-        new FrameStateAssignementPhase().apply(graph);
+        new FrameStateAssignmentPhase().apply(graph);
+
+        new DeadCodeEliminationPhase().apply(graph);
 
         final SchedulePhase schedule = new SchedulePhase();
         schedule.apply(graph);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSubstitutions.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSubstitutions.java	Wed Apr 10 15:00:22 2013 +0200
@@ -31,12 +31,12 @@
     @ClassSubstitution(Boolean.class)
     private static class BooleanSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Boolean valueOf(boolean value) {
             return BoxNode.box(value, Boolean.class, Kind.Boolean);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static boolean booleanValue(Boolean value) {
             return UnboxNode.unbox(value, Kind.Boolean);
         }
@@ -45,12 +45,12 @@
     @ClassSubstitution(Byte.class)
     private static class ByteSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Byte valueOf(byte value) {
             return BoxNode.box(value, Byte.class, Kind.Byte);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static byte byteValue(Byte value) {
             return UnboxNode.unbox(value, Kind.Byte);
         }
@@ -59,12 +59,12 @@
     @ClassSubstitution(Character.class)
     private static class CharacterSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Character valueOf(char value) {
             return BoxNode.box(value, Character.class, Kind.Char);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static char charValue(Character value) {
             return UnboxNode.unbox(value, Kind.Char);
         }
@@ -73,12 +73,12 @@
     @ClassSubstitution(Double.class)
     private static class DoubleSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Double valueOf(double value) {
             return BoxNode.box(value, Double.class, Kind.Double);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static double doubleValue(Double value) {
             return UnboxNode.unbox(value, Kind.Double);
         }
@@ -87,12 +87,12 @@
     @ClassSubstitution(Float.class)
     private static class FloatSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Float valueOf(float value) {
             return BoxNode.box(value, Float.class, Kind.Float);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static float floatValue(Float value) {
             return UnboxNode.unbox(value, Kind.Float);
         }
@@ -101,12 +101,12 @@
     @ClassSubstitution(Integer.class)
     private static class IntegerSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Integer valueOf(int value) {
             return BoxNode.box(value, Integer.class, Kind.Int);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static int intValue(Integer value) {
             return UnboxNode.unbox(value, Kind.Int);
         }
@@ -115,12 +115,12 @@
     @ClassSubstitution(Long.class)
     private static class LongSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Long valueOf(long value) {
             return BoxNode.box(value, Long.class, Kind.Long);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static long longValue(Long value) {
             return UnboxNode.unbox(value, Kind.Long);
         }
@@ -129,12 +129,12 @@
     @ClassSubstitution(Short.class)
     private static class ShortSubstitutions {
 
-        @MethodSubstitution(isForcedInlining = true)
+        @MethodSubstitution(forced = true)
         public static Short valueOf(short value) {
             return BoxNode.box(value, Short.class, Kind.Short);
         }
 
-        @MethodSubstitution(isStatic = false, isForcedInlining = true)
+        @MethodSubstitution(isStatic = false, forced = true)
         public static short shortValue(Short value) {
             return UnboxNode.unbox(value, Kind.Short);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Wed Apr 10 15:00:22 2013 +0200
@@ -62,15 +62,15 @@
     }
 
     @Snippet
-    public static void serialArrayRangeWriteBarrier(@Parameter("dstObject") Object destObject, @Parameter("destPos") int destPos, @Parameter("length") int length) {
-        Object dest = FixedValueAnchorNode.getObject(destObject);
+    public static void serialArrayRangeWriteBarrier(@Parameter("dstObject") Object destinationObject, @Parameter("destPos") int destinationStartingIndex, @Parameter("length") int length) {
+        Object dest = FixedValueAnchorNode.getObject(destinationObject);
         int cardShift = cardTableShift();
         long cardStart = cardTableStart();
         final int scale = arrayIndexScale(Kind.Object);
         int header = arrayBaseOffset(Kind.Object);
         long dstAddr = GetObjectAddressNode.get(dest);
-        long start = (dstAddr + header + (long) destPos * scale) >>> cardShift;
-        long end = (dstAddr + header + ((long) destPos + length - 1) * scale) >>> cardShift;
+        long start = (dstAddr + header + (long) destinationStartingIndex * scale) >>> cardShift;
+        long end = (dstAddr + header + ((long) destinationStartingIndex + length - 1) * scale) >>> cardShift;
         long count = end - start + 1;
         while (count-- > 0) {
             DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean);
@@ -103,8 +103,8 @@
             ResolvedJavaMethod method = serialArrayRangeWriteBarrier;
             Key key = new Key(method);
             Arguments arguments = new Arguments();
-            arguments.add("dstObject", arrayRangeWriteBarrier.getDstObject());
-            arguments.add("destPos", arrayRangeWriteBarrier.getDstPos());
+            arguments.add("dstObject", arrayRangeWriteBarrier.getDestinationObject());
+            arguments.add("destPos", arrayRangeWriteBarrier.getDestinationStartingIndex());
             arguments.add("length", arrayRangeWriteBarrier.getLength());
             SnippetTemplate template = cache.get(key);
             template.instantiate(runtime, arrayRangeWriteBarrier, DEFAULT_REPLACER, arguments);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java	Wed Apr 10 15:00:22 2013 +0200
@@ -27,26 +27,26 @@
 
 public final class SerialArrayRangeWriteBarrier extends FixedWithNextNode implements Lowerable {
 
-    @Input private ValueNode dstObject;
-    @Input private ValueNode dstPos;
+    @Input private ValueNode destinationObject;
+    @Input private ValueNode destinationStartingIndex;
     @Input private ValueNode length;
 
-    public ValueNode getDstObject() {
-        return dstObject;
+    public ValueNode getDestinationObject() {
+        return destinationObject;
     }
 
-    public ValueNode getDstPos() {
-        return dstPos;
+    public ValueNode getDestinationStartingIndex() {
+        return destinationStartingIndex;
     }
 
     public ValueNode getLength() {
         return length;
     }
 
-    public SerialArrayRangeWriteBarrier(ValueNode dstObject, ValueNode dstPos, ValueNode length) {
+    public SerialArrayRangeWriteBarrier(ValueNode destinationObject, ValueNode destinationStartingIndex, ValueNode length) {
         super(StampFactory.forVoid());
-        this.dstObject = dstObject;
-        this.dstPos = dstPos;
+        this.destinationObject = destinationObject;
+        this.destinationStartingIndex = destinationStartingIndex;
         this.length = length;
 
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java	Wed Apr 10 15:00:22 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed Apr 10 15:00:22 2013 +0200
@@ -84,6 +84,13 @@
             boolean xIdentity = stateX.getVirtualObject().hasIdentity();
             boolean yIdentity = stateY.getVirtualObject().hasIdentity();
             if (xIdentity ^ yIdentity) {
+                /*
+                 * One of the two objects has identity, the other doesn't. In code, this looks like
+                 * "Integer.valueOf(a) == new Integer(b)", which is always false.
+                 * 
+                 * In other words: an object created via valueOf can never be equal to one created
+                 * by new in the same compilation unit.
+                 */
                 tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
             } else if (!xIdentity && !yIdentity) {
                 // both are virtual without identity: check contents
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Apr 10 15:00:22 2013 +0200
@@ -28,15 +28,15 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 
+/**
+ * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf
+ * methods in Integer, Long, etc.
+ */
 public class BoxNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Canonicalizable {
 
     @Input private ValueNode value;
     private final Kind boxingKind;
 
-    public BoxNode(Invoke invoke) {
-        this(invoke.methodCallTarget().arguments().get(0), invoke.node().objectStamp().type(), invoke.methodCallTarget().targetMethod().getSignature().getParameterKind(0));
-    }
-
     public BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
         super(StampFactory.exactNonNull(resultType));
         this.value = value;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Wed Apr 10 15:00:22 2013 +0200
@@ -95,12 +95,6 @@
         return this;
     }
 
-    /*
-     * Normally, all these variants wouldn't be needed because this can be accomplished by using a
-     * generic method with automatic unboxing. These intrinsics, however, are themselves used for
-     * recognizing boxings, which means that there would be a circularity issue.
-     */
-
     @NodeIntrinsic
     public static native boolean unbox(Boolean value, @ConstantNodeParameter Kind kind);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java	Wed Apr 10 15:00:22 2013 +0200
@@ -77,6 +77,9 @@
     /**
      * Determines if this method should be substituted in all cases, even if inlining thinks it is
      * not important.
+     * 
+     * Not that this is still depending on whether inlining sees the correct call target, so it's
+     * only a hard guarantee for static and special invocations.
      */
-    boolean isForcedInlining() default false;
+    boolean forced() default false;
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignementPhase.java	Wed Apr 10 14:59:32 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2013, 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.phases.common;
-
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
-
-public class FrameStateAssignementPhase extends Phase {
-
-    private static class FrameStateAssignementState {
-
-        private FrameState framestate;
-
-        public FrameStateAssignementState(FrameState framestate) {
-            this.framestate = framestate;
-        }
-
-        public FrameState getFramestate() {
-            return framestate;
-        }
-
-        public void setFramestate(FrameState framestate) {
-            assert framestate != null;
-            this.framestate = framestate;
-        }
-
-        @Override
-        public String toString() {
-            return "FrameStateAssignementState: " + framestate;
-        }
-    }
-
-    private static class FrameStateAssignementClosure extends BlockIteratorClosure<FrameStateAssignementState> {
-
-        @Override
-        protected void processBlock(Block block, FrameStateAssignementState currentState) {
-            FixedNode node = block.getBeginNode();
-            while (node != null) {
-                if (node instanceof DeoptimizingNode) {
-                    DeoptimizingNode deopt = (DeoptimizingNode) node;
-                    if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) {
-                        deopt.setDeoptimizationState(currentState.getFramestate());
-                    }
-                }
-
-                if (node instanceof StateSplit) {
-                    StateSplit stateSplit = (StateSplit) node;
-                    if (stateSplit.stateAfter() != null) {
-                        currentState.setFramestate(stateSplit.stateAfter());
-                        stateSplit.setStateAfter(null);
-                    }
-                }
-
-                if (node instanceof FixedWithNextNode) {
-                    node = ((FixedWithNextNode) node).next();
-                } else {
-                    node = null;
-                }
-            }
-        }
-
-        @Override
-        protected FrameStateAssignementState merge(Block mergeBlock, List<FrameStateAssignementState> states) {
-            MergeNode merge = (MergeNode) mergeBlock.getBeginNode();
-            if (merge.stateAfter() != null) {
-                return new FrameStateAssignementState(merge.stateAfter());
-            }
-            return new FrameStateAssignementState(singleFrameState(states));
-        }
-
-        @Override
-        protected FrameStateAssignementState cloneState(FrameStateAssignementState oldState) {
-            return new FrameStateAssignementState(oldState.getFramestate());
-        }
-
-        @Override
-        protected List<FrameStateAssignementState> processLoop(Loop loop, FrameStateAssignementState initialState) {
-            return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
-        }
-
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        assert checkFixedDeopts(graph);
-        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
-        ReentrantBlockIterator.apply(new FrameStateAssignementClosure(), cfg.getStartBlock(), new FrameStateAssignementState(null), null);
-    }
-
-    private static boolean checkFixedDeopts(StructuredGraph graph) {
-        NodePredicate isFloatingNode = GraphUtil.isFloatingNode();
-        for (Node n : graph.getNodes().filterInterface(DeoptimizingNode.class)) {
-            if (((DeoptimizingNode) n).canDeoptimize() && isFloatingNode.apply(n)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private static FrameState singleFrameState(List<FrameStateAssignementState> states) {
-        Iterator<FrameStateAssignementState> it = states.iterator();
-        assert it.hasNext();
-        FrameState first = it.next().getFramestate();
-        while (it.hasNext()) {
-            if (first != it.next().getFramestate()) {
-                return null;
-            }
-        }
-        return first;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Wed Apr 10 15:00:22 2013 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013, 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.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+
+public class FrameStateAssignmentPhase extends Phase {
+
+    private static class FrameStateAssignmentState {
+
+        private FrameState framestate;
+
+        public FrameStateAssignmentState(FrameState framestate) {
+            this.framestate = framestate;
+        }
+
+        public FrameState getFramestate() {
+            return framestate;
+        }
+
+        public void setFramestate(FrameState framestate) {
+            assert framestate != null;
+            this.framestate = framestate;
+        }
+
+        @Override
+        public String toString() {
+            return "FrameStateAssignementState: " + framestate;
+        }
+    }
+
+    private static class FrameStateAssignementClosure extends BlockIteratorClosure<FrameStateAssignmentState> {
+
+        @Override
+        protected void processBlock(Block block, FrameStateAssignmentState currentState) {
+            FixedNode node = block.getBeginNode();
+            while (node != null) {
+                if (node instanceof DeoptimizingNode) {
+                    DeoptimizingNode deopt = (DeoptimizingNode) node;
+                    if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) {
+                        deopt.setDeoptimizationState(currentState.getFramestate());
+                    }
+                }
+
+                if (node instanceof StateSplit) {
+                    StateSplit stateSplit = (StateSplit) node;
+                    if (stateSplit.stateAfter() != null) {
+                        currentState.setFramestate(stateSplit.stateAfter());
+                        stateSplit.setStateAfter(null);
+                    }
+                }
+
+                if (node instanceof FixedWithNextNode) {
+                    node = ((FixedWithNextNode) node).next();
+                } else {
+                    node = null;
+                }
+            }
+        }
+
+        @Override
+        protected FrameStateAssignmentState merge(Block mergeBlock, List<FrameStateAssignmentState> states) {
+            MergeNode merge = (MergeNode) mergeBlock.getBeginNode();
+            if (merge.stateAfter() != null) {
+                return new FrameStateAssignmentState(merge.stateAfter());
+            }
+            return new FrameStateAssignmentState(singleFrameState(states));
+        }
+
+        @Override
+        protected FrameStateAssignmentState cloneState(FrameStateAssignmentState oldState) {
+            return new FrameStateAssignmentState(oldState.getFramestate());
+        }
+
+        @Override
+        protected List<FrameStateAssignmentState> processLoop(Loop loop, FrameStateAssignmentState initialState) {
+            return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+        }
+
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        assert checkFixedDeopts(graph);
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+        ReentrantBlockIterator.apply(new FrameStateAssignementClosure(), cfg.getStartBlock(), new FrameStateAssignmentState(null), null);
+    }
+
+    private static boolean checkFixedDeopts(StructuredGraph graph) {
+        NodePredicate isFloatingNode = GraphUtil.isFloatingNode();
+        for (Node n : graph.getNodes().filterInterface(DeoptimizingNode.class)) {
+            if (((DeoptimizingNode) n).canDeoptimize() && isFloatingNode.apply(n)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static FrameState singleFrameState(List<FrameStateAssignmentState> states) {
+        Iterator<FrameStateAssignmentState> it = states.iterator();
+        assert it.hasNext();
+        FrameState first = it.next().getFramestate();
+        while (it.hasNext()) {
+            if (first != it.next().getFramestate()) {
+                return null;
+            }
+        }
+        return first;
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Apr 10 15:00:22 2013 +0200
@@ -149,7 +149,7 @@
                 Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalParameters);
                 if (originalMethod != null) {
                     ResolvedJavaMethod original = registerMethodSubstitution(originalMethod, substituteMethod);
-                    if (original != null && methodSubstitution.isForcedInlining()) {
+                    if (original != null && methodSubstitution.forced()) {
                         forcedSubstitutions.add(original);
                     }
                 }
@@ -160,7 +160,7 @@
                 Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalParameters);
                 if (originalMethod != null) {
                     ResolvedJavaMethod original = registerMacroSubstitution(originalMethod, macroSubstitution.macro());
-                    if (original != null && macroSubstitution.isForcedInlining()) {
+                    if (original != null && macroSubstitution.forced()) {
                         forcedSubstitutions.add(original);
                     }
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Apr 10 14:59:32 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Apr 10 15:00:22 2013 +0200
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.virtual.phases.ea.PartialEscapeAnalysisPhase.*;
 
-import java.io.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -47,7 +46,7 @@
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.BlockState.ReadCacheEntry;
-import com.oracle.graal.virtual.phases.ea.EffectList.*;
+import com.oracle.graal.virtual.phases.ea.EffectList.Effect;
 
 class PartialEscapeClosure extends BlockIteratorClosure<BlockState> {
 
@@ -90,21 +89,17 @@
         return changed;
     }
 
-    private static void trace2(String format, Object... args) {
-        Debug.log(format, args);
-    }
-
     public List<Node> applyEffects(final StructuredGraph graph) {
         final ArrayList<Node> obsoleteNodes = new ArrayList<>();
         BlockIteratorClosure<Object> closure = new BlockIteratorClosure<Object>() {
 
             private void apply(GraphEffectList effects, Object context) {
                 if (!effects.isEmpty()) {
-                    trace2(" ==== effects for %s", context);
+                    Debug.log(" ==== effects for %s", context);
                     for (Effect effect : effects) {
                         effect.apply(graph, obsoleteNodes);
                         if (effect.isVisible()) {
-                            trace2("    %s", effect);
+                            Debug.log("    %s", effect);
                         }
                     }
                 }
@@ -331,8 +326,6 @@
 
     }
 
-    static PrintStream out = System.out;
-
     @Override
     protected BlockState cloneState(BlockState oldState) {
         return oldState.cloneState();
@@ -394,7 +387,7 @@
                     ValueNode value = obj.getEntry(i);
                     ObjectState valueObj = exitState.getObjectState(value);
                     if (valueObj == null) {
-                        if ((value instanceof PhiNode && ((PhiNode) value).merge() == exitNode.loopBegin()) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
+                        if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
                             ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
                             obj.setEntry(i, proxy);
                             effects.addFloatingNode(proxy, "virtualProxy");
@@ -413,11 +406,9 @@
                     }
                     obj.updateMaterializedValue(proxy);
                 } else {
-                    // assert initialObj.getMaterializedValue() == obj.getMaterializedValue() :
-                    // "materialized value is not allowed to change within loops: " +
-// initialObj.getMaterializedValue()
-                    // +
-                    // " vs. " + obj.getMaterializedValue() + " at " + exitNode;
+                    if (initialObj.getMaterializedValue() == obj.getMaterializedValue()) {
+                        Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObj.getMaterializedValue(), obj.getMaterializedValue(), exitNode);
+                    }
                 }
             }
         }