changeset 6526:ee651c726397

split phases out of graal.phases project into graal.phases.common project
author Doug Simon <doug.simon@oracle.com>
date Sun, 07 Oct 2012 14:27:50 +0200
parents 2c913b643422
children 3c5b19e8f2a3
files graal/com.oracle.graal.boot/src/com/oracle/graal/boot/meta/MethodElement.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CheckCastEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GlobalValueNumberingPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InsertStateAfterPlaceholderPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IntrinsificationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeCheckCastEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/PhiStampPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/Phase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhasePlan.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/BoxingEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/CanonicalizerPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/CheckCastEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ComputeProbabilityPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ConvertDeoptimizeToGuardPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ConvertUnreachedToGuardPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/CullFrameStatesPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/DeadCodeEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ExpandBoxingNodesPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/FloatingReadPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/GlobalValueNumberingPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/IdentifyBoxingPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/InliningPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/InsertStateAfterPlaceholderPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/IntrinsificationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/IterativeCheckCastEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/LoopSafepointInsertionPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/LoweringPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/Phase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/PhasePlan.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/PhiStampPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ReadEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/RemoveValueProxyPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/TailDuplicationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/InliningUtil.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InvokeTest.java graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetVerificationPhase.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/experimental/SplitPartialEscapeAnalysisPhase.java mx/projects src/share/vm/runtime/arguments.cpp
diffstat 97 files changed, 4944 insertions(+), 4933 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.boot/src/com/oracle/graal/boot/meta/MethodElement.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.boot/src/com/oracle/graal/boot/meta/MethodElement.java	Sun Oct 07 14:27:50 2012 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 
 public class MethodElement extends Element {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -30,8 +30,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-import com.oracle.graal.phases.phases.PhasePlan.*;
+import com.oracle.graal.phases.PhasePlan.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant 0. Then boxing
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -25,7 +25,7 @@
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 public class CompareCanonicalizerTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant 0. Then
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant 0.
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 public class FloatingReadTest extends GraphScheduleTest {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -40,8 +40,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-import com.oracle.graal.phases.phases.PhasePlan.*;
+import com.oracle.graal.phases.PhasePlan.*;
 import com.oracle.graal.phases.schedule.*;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -30,8 +30,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-import com.oracle.graal.phases.phases.PhasePlan.*;
+import com.oracle.graal.phases.PhasePlan.*;
+import com.oracle.graal.phases.common.*;
 
 public class IfBoxingEliminationTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -29,7 +29,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant 0.
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -28,7 +28,7 @@
 
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 public class InvokeExceptionTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -28,7 +28,7 @@
 
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 public class InvokeHintsTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 public class LoopUnswitchTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant 0.
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 public class ReassociateAndCanonicalTest extends GraalCompilerTest {
     public static int rnd = (int) (Math.random() * 100);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * In the following tests, the scalar type system of the compiler should be complete enough to see the relation between the different conditions.
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * This class tests some specific patterns the stamp system should be able to canonicalize away using
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 public class StraighteningTest extends GraalCompilerTest {
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -34,7 +34,7 @@
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -32,7 +32,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -34,7 +34,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sun Oct 07 14:27:50 2012 +0200
@@ -40,8 +40,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-import com.oracle.graal.phases.phases.PhasePlan.*;
+import com.oracle.graal.phases.PhasePlan.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.phases.ea.*;
 import com.oracle.graal.virtual.phases.ea.experimental.*;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Sun Oct 07 14:27:50 2012 +0200
@@ -48,7 +48,6 @@
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.util.*;
-import com.oracle.graal.virtual.nodes.*;
 import com.oracle.max.asm.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Sun Oct 07 14:27:50 2012 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
 
 
 public final class CompilationTask implements Runnable, Comparable<CompilationTask> {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Sun Oct 07 14:27:50 2012 +0200
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
 
 /**
  * Calls from HotSpot into Java.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Sun Oct 07 14:27:50 2012 +0200
@@ -38,8 +38,7 @@
 import com.oracle.graal.hotspot.snippets.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-import com.oracle.graal.phases.phases.PhasePlan.*;
+import com.oracle.graal.phases.PhasePlan.*;
 import com.oracle.graal.snippets.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -32,8 +32,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-import com.oracle.graal.phases.util.*;
+import com.oracle.graal.phases.common.*;
 
 public class IntrinsifyArrayCopyPhase extends Phase {
     private final GraalCodeCacheProvider runtime;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Sun Oct 07 14:27:50 2012 +0200
@@ -42,7 +42,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.util.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.snippets.*;
 import com.oracle.graal.snippets.Snippet.ConstantParameter;
 import com.oracle.graal.snippets.Snippet.Parameter;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Sun Oct 07 14:27:50 2012 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.java;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.*;
 
 public class GraphBuilderConfiguration {
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -46,7 +46,6 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
 import com.oracle.graal.phases.util.*;
 
 /**
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Sun Oct 07 14:27:50 2012 +0200
@@ -29,7 +29,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 
 
 public abstract class LoopTransformations {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.*;
 
 
 public class LoopFullUnrollPhase extends Phase {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
 
 public class LoopTransformHighPhase extends Phase {
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -26,7 +26,6 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
 
 public class LoopTransformLowPhase extends Phase {
     private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
+
+public class BoxingEliminationPhase extends Phase {
+
+    private int virtualIds = Integer.MIN_VALUE;
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.getNodes(UnboxNode.class).isNotEmpty()) {
+
+            Map<PhiNode, PhiNode> phiReplacements = new HashMap<>();
+            for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) {
+                tryEliminate(graph, unboxNode, phiReplacements);
+            }
+
+            new DeadCodeEliminationPhase().apply(graph);
+
+            for (BoxNode boxNode : graph.getNodes(BoxNode.class)) {
+                tryEliminate(boxNode);
+            }
+        }
+    }
+
+    private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map<PhiNode, PhiNode> phiReplacements) {
+        ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements);
+        if (unboxedValue != null) {
+            assert unboxedValue.kind() == unboxNode.kind();
+            unboxNode.replaceAtUsages(unboxedValue);
+            graph.removeFixed(unboxNode);
+        }
+    }
+
+    private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map<PhiNode, PhiNode> phiReplacements) {
+        if (!phiReplacements.containsKey(phiNode)) {
+            PhiNode result = null;
+            ObjectStamp stamp = phiNode.objectStamp();
+            if (stamp.nonNull() && stamp.isExactType()) {
+                ResolvedJavaType type = stamp.type();
+                if (type != null && type.toJava() == kind.toBoxedJavaClass()) {
+                    StructuredGraph graph = (StructuredGraph) phiNode.graph();
+                    result = graph.add(new PhiNode(kind, phiNode.merge()));
+                    phiReplacements.put(phiNode, result);
+                    virtualizeUsages(phiNode, result, type);
+                    int i = 0;
+                    for (ValueNode n : phiNode.values()) {
+                        ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements);
+                        if (unboxedValue != null) {
+                            assert unboxedValue.kind() == kind;
+                            result.addInput(unboxedValue);
+                        } else {
+                            UnboxNode unboxNode = graph.add(new UnboxNode(kind, n));
+                            FixedNode pred = phiNode.merge().phiPredecessorAt(i);
+                            graph.addBeforeFixed(pred, unboxNode);
+                            result.addInput(unboxNode);
+                        }
+                        ++i;
+                    }
+                }
+            }
+        }
+        return phiReplacements.get(phiNode);
+    }
+
+    private ValueNode unboxedValue(ValueNode n, Kind kind, Map<PhiNode, PhiNode> phiReplacements) {
+        if (n instanceof BoxNode) {
+            BoxNode boxNode = (BoxNode) n;
+            return boxNode.source();
+        } else if (n instanceof PhiNode) {
+            PhiNode phiNode = (PhiNode) n;
+            return getReplacementPhi(phiNode, kind, phiReplacements);
+        } else {
+            return null;
+        }
+    }
+
+    private void tryEliminate(BoxNode boxNode) {
+
+        assert boxNode.objectStamp().isExactType();
+        virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type());
+
+        if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) {
+            // Elimination failed, because boxing object escapes.
+            return;
+        }
+
+        FrameState stateAfter = boxNode.stateAfter();
+        boxNode.setStateAfter(null);
+        stateAfter.safeDelete();
+
+        ((StructuredGraph) boxNode.graph()).removeFixed(boxNode);
+    }
+
+    private void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) {
+        ValueNode virtualValueNode = null;
+        VirtualObjectNode virtualObjectNode = null;
+        for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) {
+            if (virtualValueNode == null) {
+                virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(virtualIds++, exactType, replacement));
+            }
+            n.replaceFirstInput(boxNode, virtualObjectNode);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.InputChangedListener;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+public class CanonicalizerPhase extends Phase {
+    private static final int MAX_ITERATION_PER_NODE = 10;
+    private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes");
+    private static final DebugMetric METRIC_CANONICALIZATION_CONSIDERED_NODES = Debug.metric("CanonicalizationConsideredNodes");
+    private static final DebugMetric METRIC_INFER_STAMP_CALLED = Debug.metric("InferStampCalled");
+    private static final DebugMetric METRIC_STAMP_CHANGED = Debug.metric("StampChanged");
+    private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes");
+    public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits");
+
+    private final int newNodesMark;
+    private final TargetDescription target;
+    private final Assumptions assumptions;
+    private final MetaAccessProvider runtime;
+    private final IsImmutablePredicate immutabilityPredicate;
+    private final Iterable<Node> initWorkingSet;
+
+    private NodeWorkList workList;
+    private Tool tool;
+    private List<Node> snapshotTemp;
+
+    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) {
+        this(target, runtime, assumptions, null, 0, null);
+    }
+
+    /**
+     * @param target
+     * @param runtime
+     * @param assumptions
+     * @param workingSet the initial working set of nodes on which the canonicalizer works, should be an auto-grow node bitmap
+     * @param immutabilityPredicate
+     */
+    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, IsImmutablePredicate immutabilityPredicate) {
+        this(target, runtime, assumptions, workingSet, 0, immutabilityPredicate);
+    }
+
+    /**
+     * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by
+     *            this mark are processed otherwise all nodes in the graph are processed
+     */
+    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, IsImmutablePredicate immutabilityPredicate) {
+        this(target, runtime, assumptions, null, newNodesMark, immutabilityPredicate);
+    }
+
+    private CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, int newNodesMark, IsImmutablePredicate immutabilityPredicate) {
+        this.newNodesMark = newNodesMark;
+        this.target = target;
+        this.assumptions = assumptions;
+        this.runtime = runtime;
+        this.immutabilityPredicate = immutabilityPredicate;
+        this.initWorkingSet = workingSet;
+        this.snapshotTemp = new ArrayList<>();
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (initWorkingSet == null) {
+            workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE);
+            if (newNodesMark > 0) {
+                workList.addAll(graph.getNewNodes(newNodesMark));
+            }
+        } else {
+            workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE);
+            workList.addAll(initWorkingSet);
+        }
+        tool = new Tool(workList, runtime, target, assumptions, immutabilityPredicate);
+        processWorkSet(graph);
+    }
+
+    public interface IsImmutablePredicate {
+        /**
+         * Determines if a given constant is an object/array whose current
+         * fields/elements will never change.
+         */
+        boolean apply(Constant constant);
+    }
+
+    private void processWorkSet(StructuredGraph graph) {
+        graph.trackInputChange(new InputChangedListener() {
+            @Override
+            public void inputChanged(Node node) {
+                workList.addAgain(node);
+            }
+        });
+
+        for (Node n : workList) {
+            processNode(n, graph);
+        }
+
+        graph.stopTrackingInputChange();
+    }
+
+    private void processNode(Node node, StructuredGraph graph) {
+        if (node.isAlive()) {
+            METRIC_PROCESSED_NODES.increment();
+
+            if (tryGlobalValueNumbering(node, graph)) {
+                return;
+            }
+            int mark = graph.getMark();
+            if (!tryKillUnused(node)) {
+                node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
+                if (!tryCanonicalize(node, graph, tool)) {
+                    tryInferStamp(node, graph);
+                } else {
+                    for (Node in : snapshotTemp) {
+                        if (in.isAlive() && in.usages().isEmpty()) {
+                            GraphUtil.killWithUnusedFloatingInputs(in);
+                        }
+                    }
+                }
+                snapshotTemp.clear();
+            }
+
+            for (Node newNode : graph.getNewNodes(mark)) {
+                workList.add(newNode);
+            }
+        }
+    }
+
+    private static boolean tryKillUnused(Node node) {
+        if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) {
+            GraphUtil.killWithUnusedFloatingInputs(node);
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) {
+        if (node.getNodeClass().valueNumberable()) {
+            Node newNode = graph.findDuplicate(node);
+            if (newNode != null) {
+                assert !(node instanceof FixedNode || newNode instanceof FixedNode);
+                node.replaceAtUsages(newNode);
+                node.safeDelete();
+                METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment();
+                Debug.log("GVN applied and new node is %1s", newNode);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) {
+        if (node instanceof Canonicalizable) {
+            assert !(node instanceof Simplifiable);
+            METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
+            return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>(){
+                public Boolean call() {
+                    ValueNode canonical = ((Canonicalizable) node).canonical(tool);
+//     cases:                                           original node:
+//                                         |Floating|Fixed-unconnected|Fixed-connected|
+//                                         --------------------------------------------
+//                                     null|   1    |        X        |       3       |
+//                                         --------------------------------------------
+//                                 Floating|   2    |        X        |       4       |
+//       canonical node:                   --------------------------------------------
+//                        Fixed-unconnected|   X    |        X        |       5       |
+//                                         --------------------------------------------
+//                          Fixed-connected|   2    |        X        |       6       |
+//                                         --------------------------------------------
+//       X: must not happen (checked with assertions)
+                    if (canonical == node) {
+                        Debug.log("Canonicalizer: work on %s", node);
+                        return false;
+                    } else {
+                        Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
+                        METRIC_CANONICALIZED_NODES.increment();
+                        if (node instanceof FloatingNode) {
+                            if (canonical == null) {
+                                // case 1
+                                graph.removeFloating((FloatingNode) node);
+                            } else {
+                                // case 2
+                                assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode) : node + " -> " + canonical +
+                                                " : replacement should be floating or fixed and connected";
+                                graph.replaceFloating((FloatingNode) node, canonical);
+                            }
+                        } else {
+                            assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
+                            if (canonical == null) {
+                                // case 3
+                                graph.removeFixed((FixedWithNextNode) node);
+                            } else if (canonical instanceof FloatingNode) {
+                                // case 4
+                                graph.replaceFixedWithFloating((FixedWithNextNode) node, (FloatingNode) canonical);
+                            } else {
+                                assert canonical instanceof FixedNode;
+                                if (canonical.predecessor() == null) {
+                                    assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors";
+                                    // case 5
+                                    graph.replaceFixedWithFixed((FixedWithNextNode) node, (FixedWithNextNode) canonical);
+                                } else {
+                                    assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
+                                    // case 6
+                                    node.replaceAtUsages(canonical);
+                                    graph.removeFixed((FixedWithNextNode) node);
+                                }
+                            }
+                        }
+                        return true;
+                    }
+                }
+            });
+        } else if (node instanceof Simplifiable) {
+            Debug.log("Canonicalizer: simplifying %s", node);
+            METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
+            Debug.scope("SimplifyNode", node, new Runnable() {
+                public void run() {
+                    ((Simplifiable) node).simplify(tool);
+                }
+            });
+        }
+        return node.isDeleted();
+    }
+
+    /**
+     * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that the stamp has
+     * changed), re-queues the node's usages . If the stamp has changed then this method also checks if the stamp
+     * now describes a constant integer value, in which case the node is replaced with a constant.
+     */
+    private void tryInferStamp(Node node, StructuredGraph graph) {
+        if (node.isAlive() && node instanceof ValueNode) {
+            ValueNode valueNode = (ValueNode) node;
+            METRIC_INFER_STAMP_CALLED.increment();
+            if (valueNode.inferStamp()) {
+                METRIC_STAMP_CHANGED.increment();
+                if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) {
+                    ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph);
+                    Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement);
+                    valueNode.replaceAtUsages(replacement);
+                } else {
+                    for (Node usage : valueNode.usages()) {
+                        workList.addAgain(usage);
+                    }
+                }
+            }
+        }
+    }
+
+    private static final class Tool implements SimplifierTool {
+
+        private final NodeWorkList nodeWorkSet;
+        private final MetaAccessProvider runtime;
+        private final TargetDescription target;
+        private final Assumptions assumptions;
+        private final IsImmutablePredicate immutabilityPredicate;
+
+        public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, TargetDescription target, Assumptions assumptions, IsImmutablePredicate immutabilityPredicate) {
+            this.nodeWorkSet = nodeWorkSet;
+            this.runtime = runtime;
+            this.target = target;
+            this.assumptions = assumptions;
+            this.immutabilityPredicate = immutabilityPredicate;
+        }
+
+        @Override
+        public void deleteBranch(FixedNode branch) {
+            branch.predecessor().replaceFirstSuccessor(branch, null);
+            GraphUtil.killCFG(branch);
+        }
+
+        /**
+         * @return the current target or {@code null} if no target is available in the current context.
+         */
+        @Override
+        public TargetDescription target() {
+            return target;
+        }
+
+        /**
+         * @return an object that can be used for recording assumptions or {@code null} if assumptions are not allowed in the current context.
+         */
+        @Override
+        public Assumptions assumptions() {
+            return assumptions;
+        }
+
+        @Override
+        public MetaAccessProvider runtime() {
+            return runtime;
+        }
+
+        @Override
+        public void addToWorkList(Node node) {
+            nodeWorkSet.add(node);
+        }
+
+        @Override
+        public boolean isImmutable(Constant objectConstant) {
+            return immutabilityPredicate != null && immutabilityPredicate.apply(objectConstant);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CheckCastEliminationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+
+public class CheckCastEliminationPhase extends Phase {
+
+    private static final DebugMetric metricInstanceOfRegistered = Debug.metric("InstanceOfRegistered");
+    private static final DebugMetric metricNullCheckRegistered = Debug.metric("NullCheckRegistered");
+    private static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved");
+    private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved");
+    private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved");
+    private static final DebugMetric metricNullCheckGuardRemoved = Debug.metric("NullCheckGuardRemoved");
+    private static final DebugMetric metricGuardsReplaced = Debug.metric("GuardsReplaced");
+
+    private StructuredGraph graph;
+
+    @Override
+    protected void run(StructuredGraph inputGraph) {
+        graph = inputGraph;
+        new EliminateCheckCasts(graph.start(), new State()).apply();
+    }
+
+    public static class State implements MergeableState<State> {
+
+        private IdentityHashMap<ValueNode, ResolvedJavaType> knownTypes;
+        private HashSet<ValueNode> knownNotNull;
+        private HashSet<ValueNode> knownNull;
+        private IdentityHashMap<BooleanNode, ValueNode> trueConditions;
+        private IdentityHashMap<BooleanNode, ValueNode> falseConditions;
+
+        public State() {
+            this.knownTypes = new IdentityHashMap<>();
+            this.knownNotNull = new HashSet<>();
+            this.knownNull = new HashSet<>();
+            this.trueConditions = new IdentityHashMap<>();
+            this.falseConditions = new IdentityHashMap<>();
+        }
+
+        public State(State other) {
+            this.knownTypes = new IdentityHashMap<>(other.knownTypes);
+            this.knownNotNull = new HashSet<>(other.knownNotNull);
+            this.knownNull = new HashSet<>(other.knownNull);
+            this.trueConditions = new IdentityHashMap<>(other.trueConditions);
+            this.falseConditions = new IdentityHashMap<>(other.falseConditions);
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<State> withStates) {
+            IdentityHashMap<ValueNode, ResolvedJavaType> newKnownTypes = new IdentityHashMap<>();
+            HashSet<ValueNode> newKnownNotNull = new HashSet<>();
+            HashSet<ValueNode> newKnownNull = new HashSet<>();
+            IdentityHashMap<BooleanNode, ValueNode> newTrueConditions = new IdentityHashMap<>();
+            IdentityHashMap<BooleanNode, ValueNode> newFalseConditions = new IdentityHashMap<>();
+
+            for (Map.Entry<ValueNode, ResolvedJavaType> entry : knownTypes.entrySet()) {
+                ValueNode node = entry.getKey();
+                ResolvedJavaType type = entry.getValue();
+
+                for (State other : withStates) {
+                    ResolvedJavaType otherType = other.getNodeType(node);
+                    type = widen(type, otherType);
+                    if (type == null) {
+                        break;
+                    }
+                }
+                if (type == null && type != node.objectStamp().type()) {
+                    newKnownTypes.put(node, type);
+                }
+            }
+            for (ValueNode node : knownNotNull) {
+                boolean notNull = true;
+                for (State other : withStates) {
+                    if (!other.knownNotNull.contains(node)) {
+                        notNull = false;
+                        break;
+                    }
+                }
+                if (notNull) {
+                    newKnownNotNull.add(node);
+                }
+            }
+            for (ValueNode node : knownNull) {
+                boolean nul = true;
+                for (State other : withStates) {
+                    if (!other.knownNull.contains(node)) {
+                        nul = false;
+                        break;
+                    }
+                }
+                if (nul) {
+                    newKnownNull.add(node);
+                }
+            }
+            for (Map.Entry<BooleanNode, ValueNode> entry : trueConditions.entrySet()) {
+                BooleanNode check = entry.getKey();
+                ValueNode guard = entry.getValue();
+
+                for (State other : withStates) {
+                    ValueNode otherGuard = other.trueConditions.get(check);
+                    if (otherGuard == null) {
+                        guard = null;
+                        break;
+                    }
+                    if (otherGuard != guard) {
+                        guard = merge;
+                    }
+                }
+                if (guard != null) {
+                    newTrueConditions.put(check, guard);
+                }
+            }
+            for (Map.Entry<BooleanNode, ValueNode> entry : falseConditions.entrySet()) {
+                BooleanNode check = entry.getKey();
+                ValueNode guard = entry.getValue();
+
+                for (State other : withStates) {
+                    ValueNode otherGuard = other.falseConditions.get(check);
+                    if (otherGuard == null) {
+                        guard = null;
+                        break;
+                    }
+                    if (otherGuard != guard) {
+                        guard = merge;
+                    }
+                }
+                if (guard != null) {
+                    newFalseConditions.put(check, guard);
+                }
+            }
+
+            /*
+            // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values)
+            if (!(merge instanceof LoopBeginNode)) {
+                for (PhiNode phi : merge.phis()) {
+                    if (phi.type() == PhiType.Value && phi.kind() == Kind.Object) {
+                        ValueNode firstValue = phi.valueAt(0);
+                        ResolvedJavaType type = getNodeType(firstValue);
+                        boolean notNull = knownNotNull.contains(firstValue);
+                        boolean nul = knownNull.contains(firstValue);
+
+                        for (int i = 0; i < withStates.size(); i++) {
+                            State otherState = withStates.get(i);
+                            ValueNode value = phi.valueAt(i + 1);
+                            ResolvedJavaType otherType = otherState.getNodeType(value);
+                            type = widen(type, otherType);
+                            notNull &= otherState.knownNotNull.contains(value);
+                            nul &= otherState.knownNull.contains(value);
+                        }
+                        if (type == null && type != phi.declaredType()) {
+                            newKnownTypes.put(phi, type);
+                        }
+                        if (notNull) {
+                            newKnownNotNull.add(phi);
+                        }
+                        if (nul) {
+                            newKnownNull.add(phi);
+                        }
+                    }
+                }
+            }
+            */
+            this.knownTypes = newKnownTypes;
+            this.knownNotNull = newKnownNotNull;
+            this.knownNull = newKnownNull;
+            this.trueConditions = newTrueConditions;
+            this.falseConditions = newFalseConditions;
+            return true;
+        }
+
+        public ResolvedJavaType getNodeType(ValueNode node) {
+            ResolvedJavaType result = knownTypes.get(node);
+            return result == null ? node.objectStamp().type() : result;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) {
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+        }
+
+        @Override
+        public State clone() {
+            return new State(this);
+        }
+    }
+
+    public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null || b == null) {
+            return null;
+        } else if (a == b) {
+            return a;
+        } else {
+            return a.leastCommonAncestor(b);
+        }
+    }
+
+    public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) {
+        if (a == null) {
+            return b;
+        } else if (b == null) {
+            return a;
+        } else if (a == b) {
+            return a;
+        } else if (a.isSubtypeOf(b)) {
+            return a;
+        } else if (b.isSubtypeOf(a)) {
+            return b;
+        } else {
+            return a;
+        }
+    }
+
+    public class EliminateCheckCasts extends PostOrderNodeIterator<State> {
+        private BeginNode lastBegin = null;
+
+        public EliminateCheckCasts(FixedNode start, State initialState) {
+            super(start, initialState);
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            if (node instanceof BeginNode) {
+                BeginNode begin = (BeginNode) node;
+                lastBegin = begin;
+                Node pred = node.predecessor();
+                if (pred != null && pred instanceof IfNode) {
+                    IfNode ifNode = (IfNode) pred;
+                    if (!(ifNode.compare() instanceof ConstantNode)) {
+                        boolean isTrue = (node == ifNode.trueSuccessor());
+                        if (isTrue) {
+                            state.trueConditions.put(ifNode.compare(), begin);
+                        } else {
+                            state.falseConditions.put(ifNode.compare(), begin);
+                        }
+                    }
+                    if (ifNode.compare() instanceof InstanceOfNode) {
+                        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare();
+                        if ((node == ifNode.trueSuccessor())) {
+                            ValueNode object = instanceOf.object();
+                            state.knownNotNull.add(object);
+                            state.knownTypes.put(object, tighten(instanceOf.targetClass(), state.getNodeType(object)));
+                            metricInstanceOfRegistered.increment();
+                        }
+                    } else if (ifNode.compare() instanceof IsNullNode) {
+                        IsNullNode nullCheck = (IsNullNode) ifNode.compare();
+                        boolean isNull = (node == ifNode.trueSuccessor());
+                        if (isNull) {
+                            state.knownNull.add(nullCheck.object());
+                        } else {
+                            state.knownNotNull.add(nullCheck.object());
+                        }
+                        metricNullCheckRegistered.increment();
+                    }
+                }
+                for (GuardNode guard : begin.guards().snapshot()) {
+                    BooleanNode condition = guard.condition();
+                    ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition);
+                    if (existingGuards != null) {
+                        guard.replaceAtUsages(existingGuards);
+                        GraphUtil.killWithUnusedFloatingInputs(guard);
+                        metricGuardsReplaced.increment();
+                    } else {
+                        boolean removeCheck = false;
+                        if (condition instanceof IsNullNode) {
+                            IsNullNode isNull = (IsNullNode) condition;
+                            if (guard.negated() && state.knownNotNull.contains(isNull.object())) {
+                                removeCheck = true;
+                            } else if (!guard.negated() && state.knownNull.contains(isNull.object())) {
+                                removeCheck = true;
+                            }
+                            if (removeCheck) {
+                                metricNullCheckGuardRemoved.increment();
+                            }
+                        }
+                        if (removeCheck) {
+                            guard.replaceAtUsages(begin);
+                            GraphUtil.killWithUnusedFloatingInputs(guard);
+                        } else {
+                            if (guard.negated()) {
+                                state.falseConditions.put(condition, guard);
+                            } else {
+                                state.trueConditions.put(condition, guard);
+                            }
+                        }
+                    }
+                }
+            } else if (node instanceof CheckCastNode) {
+                CheckCastNode checkCast = (CheckCastNode) node;
+                ResolvedJavaType type = state.getNodeType(checkCast.object());
+                if (checkCast.targetClass() != null && type != null && type.isSubtypeOf(checkCast.targetClass())) {
+                    PiNode piNode;
+                    boolean nonNull = state.knownNotNull.contains(checkCast.object());
+                    piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, nonNull ? StampFactory.declaredNonNull(type) : StampFactory.declared(type)));
+                    checkCast.replaceAtUsages(piNode);
+                    graph.removeFixed(checkCast);
+                    metricCheckCastRemoved.increment();
+                }
+            } else if (node instanceof IfNode) {
+                IfNode ifNode = (IfNode) node;
+                BooleanNode replaceWith = null;
+                BooleanNode compare = ifNode.compare();
+
+                if (state.trueConditions.containsKey(compare)) {
+                    replaceWith = ConstantNode.forBoolean(true, graph);
+                } else if (state.falseConditions.containsKey(compare)) {
+                    replaceWith = ConstantNode.forBoolean(false, graph);
+                } else {
+                    if (compare instanceof InstanceOfNode) {
+                        InstanceOfNode instanceOf = (InstanceOfNode) compare;
+                        ValueNode object = instanceOf.object();
+                        if (state.knownNull.contains(object)) {
+                            replaceWith = ConstantNode.forBoolean(false, graph);
+                        } else if (state.knownNotNull.contains(object)) {
+                            ResolvedJavaType type = state.getNodeType(object);
+                            if (type != null && type.isSubtypeOf(instanceOf.targetClass())) {
+                                replaceWith = ConstantNode.forBoolean(true, graph);
+                            }
+                        }
+                        if (replaceWith != null) {
+                            metricInstanceOfRemoved.increment();
+                        }
+                    } else if (compare instanceof IsNullNode) {
+                        IsNullNode isNull = (IsNullNode) compare;
+                        ValueNode object = isNull.object();
+                        if (state.knownNull.contains(object)) {
+                            replaceWith = ConstantNode.forBoolean(true, graph);
+                        } else if (state.knownNotNull.contains(object)) {
+                            replaceWith = ConstantNode.forBoolean(false, graph);
+                        }
+                        if (replaceWith != null) {
+                            metricNullCheckRemoved.increment();
+                        }
+                    }
+                }
+                if (replaceWith != null) {
+                    ifNode.setCompare(replaceWith);
+                    if (compare.usages().isEmpty()) {
+                        GraphUtil.killWithUnusedFloatingInputs(compare);
+                    }
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+
+public class ComputeProbabilityPhase extends Phase {
+    private static final double EPSILON = 1d / Integer.MAX_VALUE;
+
+    /*
+     * The computation of absolute probabilities works in three steps:
+     *
+     * - The first step, "PropagateProbability", traverses the graph in post order (merges after their ends, ...) and keeps track of the "probability state".
+     *   Whenever it encounters a ControlSplit it uses the split's probability information to divide the probability upon the successors.
+     *   Whenever it encounters an Invoke it assumes that the exception edge is unlikely and propagates the whole probability to the normal successor.
+     *   Whenever it encounters a Merge it sums up the probability of all predecessors.
+     *   It also maintains a set of active loops (whose LoopBegin has been visited) and builds def/use information for the second step.
+     *
+     * - The third step propagates the loop frequencies and multiplies each FixedNode's probability with its loop frequency.
+     *
+     *   TODO: add exception probability information to Invokes
+     */
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        new PropagateProbability(graph.start()).apply();
+        Debug.dump(graph, "After PropagateProbability");
+        computeLoopFactors();
+        Debug.dump(graph, "After computeLoopFactors");
+        new PropagateLoopFrequency(graph.start()).apply();
+
+        if (GraalOptions.LoopFrequencyPropagationPolicy < 0) {
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+            BitSet visitedBlocks = new BitSet(cfg.getBlocks().length);
+            for (Loop loop : cfg.getLoops()) {
+                if (loop.parent == null) {
+                    correctLoopFrequencies(loop, 1, visitedBlocks);
+                }
+            }
+        }
+    }
+
+    private void correctLoopFrequencies(Loop loop, double parentFrequency, BitSet visitedBlocks) {
+        LoopBeginNode loopBegin = ((LoopBeginNode) loop.header.getBeginNode());
+        double frequency = parentFrequency * loopBegin.loopFrequency();
+        for (Loop child : loop.children) {
+            correctLoopFrequencies(child, frequency, visitedBlocks);
+        }
+
+        double factor = getCorrectionFactor(loopBegin.probability(), frequency);
+        for (Block block : loop.blocks) {
+            int blockId = block.getId();
+            if (!visitedBlocks.get(blockId)) {
+                visitedBlocks.set(blockId);
+
+                FixedNode node = block.getBeginNode();
+                while (node != block.getEndNode()) {
+                    node.setProbability(node.probability() * factor);
+                    node = ((FixedWithNextNode) node).next();
+                }
+                node.setProbability(node.probability() * factor);
+            }
+        }
+    }
+
+    private static double getCorrectionFactor(double probability, double frequency) {
+        switch (GraalOptions.LoopFrequencyPropagationPolicy) {
+            case -1:
+                return 1 / frequency;
+            case -2:
+                return (1 / frequency) * (Math.log(Math.E + frequency) - 1);
+            case -3:
+                double originalProbability = probability / frequency;
+                assert isRelativeProbability(originalProbability);
+                return (1 / frequency) * Math.max(1, Math.pow(originalProbability, 1.5) * Math.log10(frequency));
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    private void computeLoopFactors() {
+        for (LoopInfo info : loopInfos) {
+            double frequency = info.loopFrequency();
+            assert frequency != -1;
+        }
+    }
+
+    private static boolean isRelativeProbability(double prob) {
+        // 1.01 to allow for some rounding errors
+        return prob >= 0 && prob <= 1.01;
+    }
+
+    public static class LoopInfo {
+        public final LoopBeginNode loopBegin;
+
+        public final NodeMap<Set<LoopInfo>> requires;
+
+        private double loopFrequency = -1;
+        public boolean ended = false;
+
+        public LoopInfo(LoopBeginNode loopBegin) {
+            this.loopBegin = loopBegin;
+            this.requires = loopBegin.graph().createNodeMap();
+        }
+
+        public double loopFrequency() {
+            if (loopFrequency == -1 && ended) {
+                double backEdgeProb = 0.0;
+                for (LoopEndNode le : loopBegin.loopEnds()) {
+                    double factor = 1;
+                    Set<LoopInfo> requireds = requires.get(le);
+                    for (LoopInfo required : requireds) {
+                        double t = required.loopFrequency();
+                        if (t == -1) {
+                            return -1;
+                        }
+                        factor *= t;
+                    }
+                    backEdgeProb += le.probability() * factor;
+                }
+                double d = loopBegin.probability() - backEdgeProb;
+                if (d < EPSILON) {
+                    d = EPSILON;
+                }
+                loopFrequency = loopBegin.probability() / d;
+                loopBegin.setLoopFrequency(loopFrequency);
+            }
+            return loopFrequency;
+        }
+    }
+
+    public Set<LoopInfo> loopInfos = new HashSet<>();
+    public Map<MergeNode, Set<LoopInfo>> mergeLoops = new IdentityHashMap<>();
+
+    private class Probability implements MergeableState<Probability> {
+        public double probability;
+        public HashSet<LoopInfo> loops;
+        public LoopInfo loopInfo;
+
+        public Probability(double probability, HashSet<LoopInfo> loops) {
+            this.probability = probability;
+            this.loops = new HashSet<>(4);
+            if (loops != null) {
+                this.loops.addAll(loops);
+            }
+        }
+
+        @Override
+        public Probability clone() {
+            return new Probability(probability, loops);
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<Probability> withStates) {
+            if (merge.forwardEndCount() > 1) {
+                HashSet<LoopInfo> intersection = new HashSet<>(loops);
+                for (Probability other : withStates) {
+                    intersection.retainAll(other.loops);
+                }
+                for (LoopInfo info : loops) {
+                    if (!intersection.contains(info)) {
+                        double loopFrequency = info.loopFrequency();
+                        if (loopFrequency == -1) {
+                            return false;
+                        }
+                        probability *= loopFrequency;
+                    }
+                }
+                for (Probability other : withStates) {
+                    double prob = other.probability;
+                    for (LoopInfo info : other.loops) {
+                        if (!intersection.contains(info)) {
+                            double loopFrequency = info.loopFrequency();
+                            if (loopFrequency == -1) {
+                                return false;
+                            }
+                            prob *= loopFrequency;
+                        }
+                    }
+                    probability += prob;
+                }
+                loops = intersection;
+                mergeLoops.put(merge, new HashSet<>(intersection));
+                assert isRelativeProbability(probability) : probability;
+            }
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+            loopInfo = new LoopInfo(loopBegin);
+            loopInfos.add(loopInfo);
+            loops.add(loopInfo);
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<Probability> loopEndStates) {
+            assert loopInfo != null;
+            List<LoopEndNode> loopEnds = loopBegin.orderedLoopEnds();
+            int i = 0;
+            for (Probability proba : loopEndStates) {
+                LoopEndNode loopEnd = loopEnds.get(i++);
+                Set<LoopInfo> requires = loopInfo.requires.get(loopEnd);
+                if (requires == null) {
+                    requires = new HashSet<>();
+                    loopInfo.requires.set(loopEnd, requires);
+                }
+                for (LoopInfo innerLoop : proba.loops) {
+                    if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) {
+                        requires.add(innerLoop);
+                    }
+                }
+            }
+            loopInfo.ended = true;
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+            assert node.predecessor() != null;
+            Node pred = node.predecessor();
+            if (pred instanceof Invoke) {
+                Invoke x = (Invoke) pred;
+                if (x.next() != node) {
+                    probability = 0;
+                }
+            } else {
+                assert pred instanceof ControlSplitNode;
+                ControlSplitNode x = (ControlSplitNode) pred;
+                double sum = 0;
+                for (int i = 0; i < x.blockSuccessorCount(); i++) {
+                    if (x.blockSuccessor(i) == node) {
+                        sum += x.probability(i);
+                    }
+                }
+                probability *= sum;
+            }
+        }
+    }
+
+    private class PropagateProbability extends PostOrderNodeIterator<Probability> {
+
+        public PropagateProbability(FixedNode start) {
+            super(start, new Probability(1d, null));
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            node.setProbability(state.probability);
+        }
+    }
+
+    private class LoopCount implements MergeableState<LoopCount> {
+        public double count;
+
+        public LoopCount(double count) {
+            this.count = count;
+        }
+
+        @Override
+        public LoopCount clone() {
+            return new LoopCount(count);
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<LoopCount> withStates) {
+            assert merge.forwardEndCount() == withStates.size() + 1;
+            if (merge.forwardEndCount() > 1) {
+                Set<LoopInfo> loops = mergeLoops.get(merge);
+                assert loops != null;
+                double countProd = 1;
+                for (LoopInfo loop : loops) {
+                    countProd *= loop.loopFrequency();
+                }
+                count = countProd;
+            }
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+            count *= loopBegin.loopFrequency();
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<LoopCount> loopEndStates) {
+            // nothing to do...
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+            // nothing to do...
+        }
+    }
+
+    private class PropagateLoopFrequency extends PostOrderNodeIterator<LoopCount> {
+
+        private final FrequencyPropagationPolicy policy;
+
+        public PropagateLoopFrequency(FixedNode start) {
+            super(start, new LoopCount(1d));
+            this.policy = createFrequencyPropagationPolicy();
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            node.setProbability(policy.compute(node.probability(), state.count));
+        }
+
+    }
+
+    private static FrequencyPropagationPolicy createFrequencyPropagationPolicy() {
+        switch (GraalOptions.LoopFrequencyPropagationPolicy) {
+            case -3:
+            case -2:
+            case -1:
+            case 0:
+                return new FullFrequencyPropagation();
+            case 1:
+                return new NoFrequencyPropagation();
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    private interface FrequencyPropagationPolicy {
+
+        double compute(double probability, double frequency);
+    }
+
+    private static class FullFrequencyPropagation implements FrequencyPropagationPolicy {
+
+        @Override
+        public double compute(double probability, double frequency) {
+            return probability * frequency;
+        }
+    }
+
+    private static class NoFrequencyPropagation implements FrequencyPropagationPolicy {
+
+        @Override
+        public double compute(double probability, double frequency) {
+            return probability;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+public class ConvertDeoptimizeToGuardPhase extends Phase {
+
+    private static BeginNode findBeginNode(Node startNode) {
+        Node n = startNode;
+        while (true) {
+            if (n instanceof BeginNode) {
+                return (BeginNode) n;
+            } else {
+                n = n.predecessor();
+            }
+        }
+    }
+
+    @Override
+    protected void run(final StructuredGraph graph) {
+        if (graph.getNodes(DeoptimizeNode.class).isEmpty()) {
+            return;
+        }
+
+        for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) {
+            visitDeoptBegin(findBeginNode(d), d, graph);
+        }
+
+        new DeadCodeEliminationPhase().apply(graph);
+    }
+
+    private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) {
+        if (deoptBegin instanceof MergeNode) {
+            MergeNode mergeNode = (MergeNode) deoptBegin;
+            Debug.log("Visiting %s followed by %s", mergeNode, deopt);
+            List<EndNode> ends = mergeNode.forwardEnds().snapshot();
+            for (EndNode end : ends) {
+                if (!end.isDeleted()) {
+                    BeginNode beginNode = findBeginNode(end);
+                    if (!(beginNode instanceof MergeNode)) {
+                        visitDeoptBegin(beginNode, deopt, graph);
+                    }
+                }
+            }
+            if (mergeNode.isDeleted()) {
+                if (!deopt.isDeleted()) {
+                    Debug.log("Merge deleted, deopt moved to %s", findBeginNode(deopt));
+                    visitDeoptBegin(findBeginNode(deopt), deopt, graph);
+                }
+            }
+        } else if (deoptBegin.predecessor() instanceof IfNode) {
+            IfNode ifNode = (IfNode) deoptBegin.predecessor();
+            BeginNode otherBegin = ifNode.trueSuccessor();
+            BooleanNode conditionNode = ifNode.compare();
+            boolean negated = false;
+            if (deoptBegin == ifNode.trueSuccessor()) {
+                negated = true;
+                otherBegin = ifNode.falseSuccessor();
+            }
+            BeginNode ifBlockBegin = findBeginNode(ifNode);
+            Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, ifBlockBegin);
+            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), negated, deopt.leafGraphId()));
+            otherBegin.replaceAtUsages(ifBlockBegin);
+            FixedNode next = otherBegin.next();
+            otherBegin.setNext(null);
+            guard.setNext(next);
+            ifNode.replaceAtPredecessor(guard);
+            GraphUtil.killCFG(ifNode);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+
+public class ConvertUnreachedToGuardPhase extends Phase {
+    private OptimisticOptimizations opt;
+
+    public ConvertUnreachedToGuardPhase(OptimisticOptimizations opt) {
+        this.opt = opt;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (!opt.removeNeverExecutedCode()) {
+            return;
+        }
+        for (Node node : graph.getNodes()) {
+            if (node instanceof IfNode) {
+                IfNode ifNode = (IfNode) node;
+                BeginNode insertGuard = null;
+                BeginNode delete = null;
+                boolean inverted = false;
+                if (ifNode.probability(IfNode.TRUE_EDGE) == 0) {
+                    insertGuard = ifNode.falseSuccessor();
+                    delete = ifNode.trueSuccessor();
+                    inverted = true;
+                } else if (ifNode.probability(IfNode.FALSE_EDGE) == 0) {
+                    insertGuard = ifNode.trueSuccessor();
+                    delete = ifNode.falseSuccessor();
+                }
+                if (insertGuard != null) {
+                    GuardNode guard = graph.unique(new GuardNode(ifNode.compare(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, inverted, ifNode.leafGraphId()));
+                    graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard)));
+                    GraphUtil.killCFG(delete);
+                    graph.removeSplit(ifNode, inverted ? IfNode.FALSE_EDGE : IfNode.TRUE_EDGE);
+                }
+            }
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+
+/**
+ * This phase culls unused FrameStates from the graph.
+ * It does a post order iteration over the graph, and
+ */
+public class CullFrameStatesPhase extends Phase {
+
+    private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled");
+    private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed");
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        new CullFrameStates(graph.start(), new State(null)).apply();
+    }
+
+    public static class State implements MergeableState<State> {
+
+        private FrameState lastFrameState;
+
+        public State(FrameState lastFrameState) {
+            this.lastFrameState = lastFrameState;
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<State> withStates) {
+            FrameState stateAfter = merge.stateAfter();
+            if (merge instanceof LoopBeginNode) {
+                if (stateAfter != null) {
+                    lastFrameState = stateAfter;
+                }
+                return true;
+            }
+            metricMergesTraversed.increment();
+            if (stateAfter != null) {
+                for (State other : withStates) {
+                    if (other.lastFrameState != lastFrameState) {
+                        lastFrameState = stateAfter;
+                        return true;
+                    }
+                }
+                metricFrameStatesCulled.increment();
+                merge.setStateAfter(null);
+                if (stateAfter.usages().isEmpty()) {
+                    GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) {
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+        }
+
+        @Override
+        public State clone() {
+            return new State(lastFrameState);
+        }
+    }
+
+    public static class CullFrameStates extends PostOrderNodeIterator<State> {
+
+        public CullFrameStates(FixedNode start, State initialState) {
+            super(start, initialState);
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            if (node instanceof StateSplit) {
+                FrameState stateAfter = ((StateSplit) node).stateAfter();
+                if (stateAfter != null) {
+                    state.lastFrameState = stateAfter;
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+
+public class DeadCodeEliminationPhase extends Phase {
+
+    // Metrics
+    private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved");
+
+    private NodeFlood flood;
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        this.flood = graph.createNodeFlood();
+
+        flood.add(graph.start());
+        iterateSuccessors();
+        disconnectCFGNodes(graph);
+        iterateInputs(graph);
+        deleteNodes(graph);
+
+        // remove chained Merges
+        for (MergeNode merge : graph.getNodes(MergeNode.class)) {
+            if (merge.forwardEndCount() == 1 && !(merge instanceof LoopBeginNode)) {
+                graph.reduceTrivialMerge(merge);
+            }
+        }
+    }
+
+    private void iterateSuccessors() {
+        for (Node current : flood) {
+            if (current instanceof EndNode) {
+                EndNode end = (EndNode) current;
+                flood.add(end.merge());
+            } else {
+                for (Node successor : current.successors()) {
+                    flood.add(successor);
+                }
+            }
+        }
+    }
+
+    private void disconnectCFGNodes(StructuredGraph graph) {
+        for (EndNode node : graph.getNodes(EndNode.class)) {
+            if (!flood.isMarked(node)) {
+                MergeNode merge = node.merge();
+                if (merge != null && flood.isMarked(merge)) {
+                    // We are a dead end node leading to a live merge.
+                    merge.removeEnd(node);
+                }
+            }
+        }
+        for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.class)) {
+            if (flood.isMarked(loop)) {
+                boolean reachable = false;
+                for (LoopEndNode end : loop.loopEnds()) {
+                    if (flood.isMarked(end)) {
+                        reachable = true;
+                        break;
+                    }
+                }
+                if (!reachable) {
+                    Debug.log("Removing loop with unreachable end: %s", loop);
+                    for (LoopEndNode end : loop.loopEnds().snapshot()) {
+                        loop.removeEnd(end);
+                    }
+                    graph.reduceDegenerateLoopBegin(loop);
+                }
+            }
+        }
+    }
+
+    private void deleteNodes(StructuredGraph graph) {
+        for (Node node : graph.getNodes()) {
+            if (!flood.isMarked(node)) {
+                node.clearInputs();
+                node.clearSuccessors();
+            }
+        }
+        for (Node node : graph.getNodes()) {
+            if (!flood.isMarked(node)) {
+                metricNodesRemoved.increment();
+                node.safeDelete();
+            }
+        }
+    }
+
+    private void iterateInputs(StructuredGraph graph) {
+        for (Node node : graph.getNodes()) {
+            if (node instanceof LocalNode) {
+                flood.add(node);
+            }
+            if (flood.isMarked(node)) {
+                for (Node input : node.inputs()) {
+                    flood.add(input);
+                }
+            }
+        }
+        for (Node current : flood) {
+            for (Node input : current.inputs()) {
+                flood.add(input);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.*;
+
+public class ExpandBoxingNodesPhase extends Phase {
+
+    private final BoxingMethodPool pool;
+
+    public ExpandBoxingNodesPhase(BoxingMethodPool pool) {
+        this.pool = pool;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (BoxNode boxNode : graph.getNodes(BoxNode.class)) {
+            boxNode.expand(pool);
+        }
+
+        for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) {
+            unboxNode.expand(pool);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+
+public class FloatingReadPhase extends Phase {
+
+    private IdentityHashMap<LoopBeginNode, List<MemoryMap>> loopEndStatesMap;
+
+    private static class LoopState {
+        public LoopBeginNode loopBegin;
+        public MemoryMap state;
+        public IdentityHashMap<PhiNode, Object> loopPhiLocations = new IdentityHashMap<>();
+        public ValueNode loopEntryAnyLocation;
+        public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) {
+            this.loopBegin = loopBegin;
+            this.state = state;
+            this.loopEntryAnyLocation = loopEntryAnyLocation;
+        }
+
+        @Override
+        public String toString() {
+            return "State@" + loopBegin;
+        }
+    }
+
+    private class MemoryMap implements MergeableState<MemoryMap> {
+        private IdentityHashMap<Object, ValueNode> lastMemorySnapshot;
+        private LinkedList<LoopState> loops;
+
+        public MemoryMap(MemoryMap memoryMap) {
+            lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
+            loops = new LinkedList<>(memoryMap.loops);
+        }
+
+        public MemoryMap() {
+            lastMemorySnapshot = new IdentityHashMap<>();
+            loops = new LinkedList<>();
+        }
+
+        @Override
+        public String toString() {
+            return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString();
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<MemoryMap> withStates) {
+            if (withStates.size() == 0) {
+                return true;
+            }
+
+            int minLoops = loops.size();
+            for (MemoryMap other : withStates) {
+                int otherLoops = other.loops.size();
+                if (otherLoops < minLoops) {
+                    minLoops = otherLoops;
+                }
+            }
+            while (loops.size() > minLoops) {
+                loops.pop();
+            }
+            for (MemoryMap other : withStates) {
+                while (other.loops.size() > minLoops) {
+                    other.loops.pop();
+                }
+            }
+
+            Set<Object> keys = new HashSet<>();
+            for (Object key : lastMemorySnapshot.keySet()) {
+                keys.add(key);
+            }
+            for (MemoryMap other : withStates) {
+                assert other.loops.size() == loops.size();
+                assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin;
+                for (Object key : other.lastMemorySnapshot.keySet()) {
+                    keys.add(key);
+                }
+            }
+            @SuppressWarnings("unchecked")
+            IdentityHashMap<Object, ValueNode> newMemorySnapshot = (IdentityHashMap<Object, ValueNode>) lastMemorySnapshot.clone();
+
+            for (Object key : keys) {
+                ValueNode merged = lastMemorySnapshot.get(key);
+                if (merged == null) {
+                    merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                }
+                int mergedStatesCount = 1;
+                boolean isPhi = false;
+                for (MemoryMap other : withStates) {
+                    ValueNode otherValue = other.lastMemorySnapshot.get(key);
+                    if (otherValue == null) {
+                        otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                    }
+                    if (isPhi) {
+                        ((PhiNode) merged).addInput(otherValue);
+                    } else if (merged != otherValue) {
+                        PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
+                        for (int j = 0; j < mergedStatesCount; j++) {
+                            phi.addInput(merged);
+                        }
+                        phi.addInput(otherValue);
+                        merged = phi;
+                        isPhi = true;
+                        newMemorySnapshot.put(key, phi);
+                    }
+                    mergedStatesCount++;
+                }
+            }
+
+            lastMemorySnapshot = newMemorySnapshot;
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+            LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION));
+            for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) {
+                PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin));
+                phi.addInput(entry.getValue());
+                entry.setValue(phi);
+                loopState.loopPhiLocations.put(phi, entry.getKey());
+            }
+            loops.push(loopState);
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) {
+            loopEndStatesMap.put(loopBegin, loopEndStates);
+            tryFinishLoopPhis(this, loopBegin);
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+            // nothing
+        }
+
+        @Override
+        public MemoryMap clone() {
+            return new MemoryMap(this);
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        loopEndStatesMap = new IdentityHashMap<>();
+        new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) {
+            @Override
+            protected void node(FixedNode node) {
+                processNode(node, state);
+            }
+        }.apply();
+    }
+
+    private void processNode(FixedNode node, MemoryMap state) {
+        if (node instanceof ReadNode) {
+            processRead((ReadNode) node, state);
+        } else if (node instanceof WriteNode) {
+            processWrite((WriteNode) node, state);
+        } else if (node instanceof MemoryCheckpoint) {
+            processCheckpoint((MemoryCheckpoint) node, state);
+        } else if (node instanceof LoopExitNode) {
+            processLoopExit((LoopExitNode) node, state);
+        }
+    }
+
+    private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) {
+        processAnyLocationWrite((ValueNode) checkpoint, state);
+    }
+
+    private static void processWrite(WriteNode writeNode, MemoryMap state) {
+        if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) {
+            processAnyLocationWrite(writeNode, state);
+        }
+        state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode);
+    }
+
+    private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) {
+        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
+            entry.setValue(modifiying);
+        }
+        state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying);
+        state.loops.clear();
+    }
+
+    private void processRead(ReadNode readNode, MemoryMap state) {
+        StructuredGraph graph = (StructuredGraph) readNode.graph();
+        assert readNode.getNullCheck() == false;
+        Object locationIdentity = readNode.location().locationIdentity();
+        ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity);
+        FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies()));
+        floatingRead.setNullCheck(readNode.getNullCheck());
+        ValueAnchorNode anchor = null;
+        for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) {
+            if (anchor == null) {
+                anchor = graph.add(new ValueAnchorNode());
+            }
+            anchor.addAnchoredNode(guard);
+        }
+        if (anchor != null) {
+            graph.addAfterFixed(readNode, anchor);
+        }
+        graph.replaceFixedWithFloating(readNode, floatingRead);
+    }
+
+    private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) {
+        ValueNode lastLocationAccess;
+        if (locationIdentity == LocationNode.FINAL_LOCATION) {
+            lastLocationAccess = null;
+        } else {
+            lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity);
+            if (lastLocationAccess == null) {
+                LoopState lastLoop = state.loops.peek();
+                if (lastLoop == null) {
+                    lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                } else {
+                    ValueNode phiInit;
+                    if (state.loops.size() > 1) {
+                        phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity);
+                    } else {
+                        phiInit = lastLoop.loopEntryAnyLocation;
+                    }
+                    PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin));
+                    phi.addInput(phiInit);
+                    lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi);
+                    lastLoop.loopPhiLocations.put(phi, locationIdentity);
+                    tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin);
+                    lastLocationAccess = phi;
+                }
+                state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess);
+            }
+        }
+        return lastLocationAccess;
+    }
+
+    private static void processLoopExit(LoopExitNode exit, MemoryMap state) {
+        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
+            entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory)));
+        }
+        if (!state.loops.isEmpty()) {
+            state.loops.pop();
+        }
+    }
+
+    private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) {
+        List<MemoryMap> loopEndStates = loopEndStatesMap.get(loopBegin);
+        if (loopEndStates == null) {
+            return;
+        }
+        LoopState loopState = loopMemory.loops.get(0);
+        int i = 0;
+        while (loopState.loopBegin != loopBegin) {
+            loopState = loopMemory.loops.get(++i);
+        }
+        for (PhiNode phi : loopBegin.phis()) {
+            if (phi.type() == PhiType.Memory && phi.valueCount() == 1) {
+                Object location = loopState.loopPhiLocations.get(phi);
+                assert location != null : "unknown location for " + phi;
+                for (MemoryMap endState : loopEndStates) {
+                    ValueNode otherNode = endState.lastMemorySnapshot.get(location);
+                    if (otherNode == null) {
+                        otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                    }
+                    phi.addInput(otherNode);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GlobalValueNumberingPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+public class GlobalValueNumberingPhase extends Phase {
+
+    public static final DebugMetric metricGlobalValueNumberingHits = Debug.metric("GlobalValueNumberingHits");
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        NodeBitMap visited = graph.createNodeBitMap();
+        for (Node n : graph.getNodes()) {
+            apply(n, visited, graph);
+        }
+    }
+
+    private void apply(Node n, NodeBitMap visited, StructuredGraph compilerGraph) {
+        if (!visited.isMarked(n)) {
+            visited.mark(n);
+            for (Node input : n.inputs()) {
+                apply(input, visited, compilerGraph);
+            }
+            if (n.getNodeClass().valueNumberable()) {
+                Node newNode = compilerGraph.findDuplicate(n);
+                if (newNode != null) {
+                    assert !(n instanceof FixedNode || newNode instanceof FixedNode);
+                    n.replaceAtUsages(newNode);
+                    n.safeDelete();
+                    metricGlobalValueNumberingHits.increment();
+                    Debug.log("GVN applied and new node is %1s", newNode);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+
+public class IdentifyBoxingPhase extends Phase {
+
+    private final BoxingMethodPool pool;
+
+    public IdentifyBoxingPhase(BoxingMethodPool pool) {
+        this.pool = pool;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (Invoke invoke : graph.getInvokes()) {
+            tryIntrinsify(invoke);
+        }
+    }
+
+    public void tryIntrinsify(Invoke invoke) {
+        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
+            return;
+        }
+        MethodCallTargetNode callTarget = invoke.methodCallTarget();
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+        if (pool.isSpecialMethod(targetMethod)) {
+            assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument";
+            Kind returnKind = callTarget.returnKind();
+            ValueNode sourceValue = callTarget.arguments().get(0);
+
+            // Check whether this is a boxing or an unboxing.
+            Node newNode = null;
+            if (returnKind == Kind.Object) {
+                // We have a boxing method here.
+                assert Modifier.isStatic(targetMethod.accessFlags()) : "boxing method must be static";
+                Kind sourceKind = targetMethod.signature().argumentKindAt(0);
+                newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.holder(), sourceKind, invoke.bci()));
+            } else {
+                // We have an unboxing method here.
+                assert !Modifier.isStatic(targetMethod.accessFlags()) : "unboxing method must be an instance method";
+                newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue));
+            }
+
+            // Intrinsify the invoke to the special node.
+            invoke.intrinsify(newNode);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.PhasePlan.*;
+import com.oracle.graal.phases.common.InliningUtil.*;
+import com.oracle.graal.phases.util.*;
+
+
+public class InliningPhase extends Phase implements InliningCallback {
+    /*
+     * - Detect method which only call another method with some parameters set to constants: void foo(a) -> void foo(a, b) -> void foo(a, b, c) ...
+     *   These should not be taken into account when determining inlining depth.
+     * - honor the result of overrideInliningDecision(0, caller, invoke.bci, method, true);
+     */
+
+    private final TargetDescription target;
+    private final GraalCodeCacheProvider runtime;
+
+    private final Collection<? extends Invoke> hints;
+
+    private final PriorityQueue<InlineInfo> inlineCandidates = new PriorityQueue<>();
+    private Assumptions assumptions;
+
+    private final PhasePlan plan;
+    private final GraphCache cache;
+    private final WeightComputationPolicy weightComputationPolicy;
+    private final InliningPolicy inliningPolicy;
+    private final OptimisticOptimizations optimisticOpts;
+
+    // Metrics
+    private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
+    private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
+    private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
+
+    public InliningPhase(TargetDescription target, GraalCodeCacheProvider runtime, Collection<? extends Invoke> hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
+        this.target = target;
+        this.runtime = runtime;
+        this.hints = hints;
+        this.assumptions = assumptions;
+        this.cache = cache;
+        this.plan = plan;
+        this.optimisticOpts = optimisticOpts;
+        this.weightComputationPolicy = createWeightComputationPolicy();
+        this.inliningPolicy = createInliningPolicy();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected void run(final StructuredGraph graph) {
+        graph.createNodeMap();
+
+        if (hints != null) {
+            scanInvokes((Iterable<? extends Node>) Util.uncheckedCast(this.hints));
+        } else {
+            scanInvokes(graph.getNodes(InvokeNode.class));
+            scanInvokes(graph.getNodes(InvokeWithExceptionNode.class));
+        }
+
+        while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) {
+            InlineInfo candidate = inlineCandidates.remove();
+            if (!candidate.invoke.node().isAlive()) {
+                continue;
+            }
+            // refresh infos
+            final InlineInfo info = InliningUtil.getInlineInfo(candidate.invoke, candidate.level, runtime, assumptions, this, optimisticOpts);
+
+            boolean inline = Debug.scope("InliningDecisions", new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    return info != null && inliningPolicy.isWorthInlining(graph, info);
+                }
+            });
+
+            if (inline) {
+                int mark = graph.getMark();
+                Iterable<Node> newNodes = null;
+                try {
+                    info.inline(graph, runtime, this);
+                    Debug.dump(graph, "after %s", info);
+                    newNodes = graph.getNewNodes(mark);
+                    if (GraalOptions.OptCanonicalizer) {
+                        new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph);
+                    }
+//                    if (GraalOptions.Intrinsify) {
+//                        new IntrinsificationPhase(runtime).apply(graph);
+//                    }
+                    metricInliningPerformed.increment();
+                } catch (BailoutException bailout) {
+                    // TODO determine if we should really bail out of the whole compilation.
+                    throw bailout;
+                } catch (AssertionError e) {
+                    throw new GraalInternalError(e).addContext(info.toString());
+                } catch (RuntimeException e) {
+                    throw new GraalInternalError(e).addContext(info.toString());
+                } catch (GraalInternalError e) {
+                    throw e.addContext(info.toString());
+                }
+
+                if (newNodes != null && info.level < GraalOptions.MaximumInlineLevel) {
+                    scanInvokes(newNodes);
+                }
+            }
+        }
+
+        if (GraalOptions.Debug && graph.getNodeCount() >= GraalOptions.MaximumDesiredSize) {
+            Debug.scope("InliningDecisions", new Runnable() {
+                public void run() {
+                    for (InlineInfo info : inlineCandidates) {
+                        Debug.log("not inlining %s because inlining cut off by MaximumDesiredSize", InliningUtil.methodName(info));
+                    }
+                }
+            });
+
+            metricInliningStoppedByMaxDesiredSize.increment();
+        }
+    }
+
+    private void scanInvokes(final Iterable<? extends Node> nodes) {
+        Debug.scope("InliningDecisions", new Runnable() {
+            public void run() {
+                for (Node node : nodes) {
+                    if (node != null) {
+                        if (node instanceof Invoke) {
+                            Invoke invoke = (Invoke) node;
+                            scanInvoke(invoke);
+                        }
+                        for (Node usage : node.usages().filterInterface(Invoke.class).snapshot()) {
+                            scanInvoke((Invoke) usage);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    private void scanInvoke(Invoke invoke) {
+        InlineInfo info = InliningUtil.getInlineInfo(invoke, computeInliningLevel(invoke), runtime, assumptions, this, optimisticOpts);
+        if (info != null) {
+            metricInliningConsidered.increment();
+            inlineCandidates.add(info);
+        }
+    }
+
+    public static final Map<JavaMethod, Integer> parsedMethods = new HashMap<>();
+
+
+
+    private static final DebugMetric metricInliningRuns = Debug.metric("Runs");
+
+    @Override
+    public StructuredGraph buildGraph(final ResolvedJavaMethod method) {
+        metricInliningRuns.increment();
+        if (GraalOptions.CacheGraphs && cache != null) {
+            StructuredGraph cachedGraph = cache.get(method);
+            if (cachedGraph != null) {
+                return cachedGraph;
+            }
+        }
+        StructuredGraph newGraph = new StructuredGraph(method);
+        if (plan != null) {
+            plan.runPhases(PhasePosition.AFTER_PARSING, newGraph);
+        }
+        assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
+
+        if (GraalOptions.ProbabilityAnalysis) {
+            new DeadCodeEliminationPhase().apply(newGraph);
+            new ComputeProbabilityPhase().apply(newGraph);
+        }
+        if (GraalOptions.OptCanonicalizer) {
+            new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph);
+        }
+        if (GraalOptions.Intrinsify) {
+            new IntrinsificationPhase(runtime).apply(newGraph);
+        }
+        if (GraalOptions.CullFrameStates) {
+            new CullFrameStatesPhase().apply(newGraph);
+        }
+        if (GraalOptions.CacheGraphs && cache != null) {
+            cache.put(newGraph);
+        }
+        return newGraph;
+    }
+
+    @Override
+    public double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke) {
+        boolean preferred = hints != null && hints.contains(invoke);
+        return weightComputationPolicy.computeWeight(caller, method, invoke, preferred);
+    }
+
+    public static int graphComplexity(StructuredGraph graph) {
+        int result = 0;
+        for (Node node : graph.getNodes()) {
+            if (node instanceof ConstantNode || node instanceof LocalNode || node instanceof BeginNode || node instanceof ReturnNode || node instanceof UnwindNode) {
+                result += 0;
+            } else if (node instanceof PhiNode) {
+                result += 5;
+            } else if (node instanceof MergeNode || node instanceof Invoke || node instanceof LoopEndNode || node instanceof EndNode) {
+                result += 0;
+            } else if (node instanceof ControlSplitNode) {
+                result += ((ControlSplitNode) node).blockSuccessorCount();
+            } else {
+                result += 1;
+            }
+        }
+        return Math.max(1, result);
+    }
+
+
+    @Override
+    public void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) {
+        assumptions.recordConcreteMethod(method, context, impl);
+    }
+
+    @Override
+    public void recordMethodContentsAssumption(ResolvedJavaMethod method) {
+        if (assumptions != null) {
+            assumptions.recordMethodContents(method);
+        }
+    }
+
+    private static int computeInliningLevel(Invoke invoke) {
+        int count = -1;
+        FrameState curState = invoke.stateAfter();
+        while (curState != null) {
+            count++;
+            curState = curState.outerFrameState();
+        }
+        return count;
+    }
+
+    private static InliningPolicy createInliningPolicy() {
+        switch(GraalOptions.InliningPolicy) {
+            case 0: return new WeightBasedInliningPolicy();
+            case 1: return new C1StaticSizeBasedInliningPolicy();
+            case 2: return new MinimumCodeSizeBasedInliningPolicy();
+            case 3: return new DynamicSizeBasedInliningPolicy();
+            case 4: return new GreedySizeBasedInliningPolicy();
+            default:
+                GraalInternalError.shouldNotReachHere();
+                return null;
+        }
+    }
+
+    private static WeightComputationPolicy createWeightComputationPolicy() {
+        switch(GraalOptions.WeightComputationPolicy) {
+            case 0: throw new GraalInternalError("removed because of invokation counter changes");
+            case 1: return new BytecodeSizeBasedWeightComputationPolicy();
+            case 2: return new ComplexityBasedWeightComputationPolicy();
+            default:
+                GraalInternalError.shouldNotReachHere();
+                return null;
+        }
+    }
+
+    private interface InliningPolicy {
+        boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info);
+    }
+
+    private static class WeightBasedInliningPolicy implements InliningPolicy {
+        @Override
+        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
+            if (!checkCompiledCodeSize(info)) {
+                return false;
+            }
+
+            double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, callerGraph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp;
+            if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) {
+                Debug.log("not inlining %s (cut off by weight %e)", InliningUtil.methodName(info), info.weight);
+                return false;
+            }
+
+            Debug.log("inlining %s (weight %f): %s", InliningUtil.methodName(info), info.weight);
+            return true;
+        }
+    }
+
+    private static class C1StaticSizeBasedInliningPolicy implements InliningPolicy {
+        @Override
+        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
+            double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize);
+            return decideSizeBasedInlining(info, maxSize);
+        }
+    }
+
+    private static class MinimumCodeSizeBasedInliningPolicy implements InliningPolicy {
+        @Override
+        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
+            assert GraalOptions.ProbabilityAnalysis;
+            if (!checkCompiledCodeSize(info)) {
+                return false;
+            }
+
+            double inlineWeight = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability());
+            double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize * inlineWeight;
+            maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize);
+
+            return decideSizeBasedInlining(info, maxSize);
+        }
+    }
+
+    private static class DynamicSizeBasedInliningPolicy implements InliningPolicy {
+        @Override
+        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
+            assert GraalOptions.ProbabilityAnalysis;
+            if (!checkCompiledCodeSize(info)) {
+                return false;
+            }
+
+            double inlineBoost = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()) + Math.log10(Math.max(1, info.invoke.probability() - GraalOptions.ProbabilityCapForInlining + 1));
+            double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize;
+            maxSize = maxSize + maxSize * inlineBoost;
+            maxSize = Math.min(GraalOptions.MaximumGreedyInlineSize, Math.max(GraalOptions.MaximumTrivialSize, maxSize));
+
+            return decideSizeBasedInlining(info, maxSize);
+        }
+    }
+
+    private static class GreedySizeBasedInliningPolicy implements InliningPolicy {
+        @Override
+        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
+            assert GraalOptions.ProbabilityAnalysis;
+            if (!checkCompiledCodeSize(info)) {
+                return false;
+            }
+
+            double maxSize = GraalOptions.MaximumGreedyInlineSize;
+            if (GraalOptions.InliningBonusPerTransferredValue != 0) {
+                Signature signature = info.invoke.methodCallTarget().targetMethod().signature();
+                int transferredValues = signature.argumentCount(!Modifier.isStatic(info.invoke.methodCallTarget().targetMethod().accessFlags()));
+                if (signature.returnKind() != Kind.Void) {
+                    transferredValues++;
+                }
+                maxSize += transferredValues * GraalOptions.InliningBonusPerTransferredValue;
+            }
+
+            double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability());
+            maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * maxSize * inlineRatio;
+            maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize);
+
+            return decideSizeBasedInlining(info, maxSize);
+        }
+    }
+
+    private static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) {
+        boolean success = info.weight <= maxSize;
+        if (DebugScope.getInstance().isLogEnabled()) {
+            String formatterString = success ? "inlining %s (size %f <= %f)" : "not inlining %s (too large %f > %f)";
+            Debug.log(formatterString, InliningUtil.methodName(info), info.weight, maxSize);
+        }
+        return success;
+    }
+
+    private static boolean checkCompiledCodeSize(InlineInfo info) {
+        if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) {
+            Debug.log("not inlining %s (CompiledCodeSize %d > %d)", InliningUtil.methodName(info), info.compiledCodeSize(), GraalOptions.SmallCompiledCodeSize);
+            return false;
+        }
+        return true;
+    }
+
+
+    private interface WeightComputationPolicy {
+        double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke);
+    }
+
+    private static class BytecodeSizeBasedWeightComputationPolicy implements WeightComputationPolicy {
+        @Override
+        public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) {
+            double codeSize = method.codeSize();
+            if (preferredInvoke) {
+                codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis;
+            }
+            return codeSize;
+        }
+    }
+
+    private static class ComplexityBasedWeightComputationPolicy implements WeightComputationPolicy {
+        @Override
+        public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) {
+            double complexity = method.compilationComplexity();
+            if (preferredInvoke) {
+                complexity = complexity / GraalOptions.BoostInliningForEscapeAnalysis;
+            }
+            return complexity;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,959 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaType.Representation;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.FrameState.InliningIdentifier;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+public class InliningUtil {
+
+    private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
+
+    public interface InliningCallback {
+        StructuredGraph buildGraph(ResolvedJavaMethod method);
+        double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke);
+        void recordMethodContentsAssumption(ResolvedJavaMethod method);
+        void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl);
+    }
+
+    public static String methodName(ResolvedJavaMethod method, Invoke invoke) {
+        if (!Debug.isLogEnabled()) {
+            return null;
+        } else if (invoke != null && invoke.stateAfter() != null) {
+            return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)";
+        } else {
+            return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)";
+        }
+    }
+
+    public static String methodName(InlineInfo info) {
+        if (!Debug.isLogEnabled()) {
+            return null;
+        } else if (info.invoke != null && info.invoke.stateAfter() != null) {
+            return methodName(info.invoke.stateAfter(), info.invoke.bci()) + ": " + info.toString();
+        } else {
+            return info.toString();
+        }
+    }
+
+    private static String methodName(FrameState frameState, int bci) {
+        StringBuilder sb = new StringBuilder();
+        if (frameState.outerFrameState() != null) {
+            sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
+            sb.append("->");
+        }
+        sb.append(MetaUtil.format("%h.%n", frameState.method()));
+        sb.append("@").append(bci);
+        return sb.toString();
+    }
+
+    /**
+     * Represents an opportunity for inlining at the given invoke, with the given weight and level.
+     * The weight is the amortized weight of the additional code - so smaller is better.
+     * The level is the number of nested inlinings that lead to this invoke.
+     */
+    public abstract static class InlineInfo implements Comparable<InlineInfo> {
+        public final Invoke invoke;
+        public final double weight;
+        public final int level;
+
+        public InlineInfo(Invoke invoke, double weight, int level) {
+            this.invoke = invoke;
+            this.weight = weight;
+            this.level = level;
+        }
+
+        public abstract int compiledCodeSize();
+
+        @Override
+        public int compareTo(InlineInfo o) {
+            return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0;
+        }
+
+        protected static StructuredGraph getGraph(final ResolvedJavaMethod concrete, final InliningCallback callback) {
+            return Debug.scope("GetInliningGraph", concrete, new Callable<StructuredGraph>() {
+                @Override
+                public StructuredGraph call() throws Exception {
+                    return callback.buildGraph(concrete);
+                }
+            });
+        }
+
+        public abstract boolean canDeopt();
+
+        /**
+         * Performs the inlining described by this object and returns the node that represents the return value of the
+         * inlined method (or null for void methods and methods that have no non-exceptional exit).
+         *
+         * @param graph
+         * @param runtime
+         * @param callback
+         */
+        public abstract void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback);
+    }
+
+    /**
+     * Represents an inlining opportunity where the compiler can statically determine a monomorphic target method and
+     * therefore is able to determine the called method exactly.
+     */
+    private static class ExactInlineInfo extends InlineInfo {
+        public final ResolvedJavaMethod concrete;
+
+        public ExactInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete) {
+            super(invoke, weight, level);
+            this.concrete = concrete;
+        }
+
+        @Override
+        public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, final InliningCallback callback) {
+            StructuredGraph graph = getGraph(concrete, callback);
+            assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime);
+            callback.recordMethodContentsAssumption(concrete);
+            InliningUtil.inline(invoke, graph, true);
+        }
+
+        @Override
+        public int compiledCodeSize() {
+            return concrete.compiledCodeSize();
+        }
+
+        @Override
+        public String toString() {
+            return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
+        }
+
+        @Override
+        public boolean canDeopt() {
+            return false;
+        }
+    }
+
+    /**
+     * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which
+     * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed.
+     */
+    private static class TypeGuardInlineInfo extends InlineInfo {
+        public final ResolvedJavaMethod concrete;
+        public final ResolvedJavaType type;
+
+        public TypeGuardInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete, ResolvedJavaType type) {
+            super(invoke, weight, level);
+            this.concrete = concrete;
+            this.type = type;
+        }
+
+        @Override
+        public int compiledCodeSize() {
+            return concrete.compiledCodeSize();
+        }
+
+        @Override
+        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
+            // receiver null check must be before the type check
+            InliningUtil.receiverNullCheck(invoke);
+            ValueNode receiver = invoke.methodCallTarget().receiver();
+            LoadHubNode receiverHub = graph.add(new LoadHubNode(receiver));
+            ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), runtime, graph);
+            ObjectEqualsNode typeCheck = graph.unique(new ObjectEqualsNode(receiverHub, typeHub));
+            FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, invoke.leafGraphId()));
+            ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
+            assert invoke.predecessor() != null;
+
+            ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true);
+            invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+            graph.addBeforeFixed(invoke.node(), receiverHub);
+            graph.addBeforeFixed(invoke.node(), guard);
+            graph.addBeforeFixed(invoke.node(), anchor);
+
+            StructuredGraph calleeGraph = getGraph(concrete, callback);
+            assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime);
+            callback.recordMethodContentsAssumption(concrete);
+            InliningUtil.inline(invoke, calleeGraph, false);
+        }
+
+        @Override
+        public String toString() {
+            return "type-checked " + MetaUtil.format("%H.%n(%p):%r", concrete);
+        }
+
+        @Override
+        public boolean canDeopt() {
+            return true;
+        }
+    }
+
+    /**
+     * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable
+     * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered.
+     */
+    private static class MultiTypeGuardInlineInfo extends InlineInfo {
+        public final List<ResolvedJavaMethod> concretes;
+        public final ProfiledType[] ptypes;
+        public final int[] typesToConcretes;
+        public final double notRecordedTypeProbability;
+
+        public MultiTypeGuardInlineInfo(Invoke invoke, double weight, int level, List<ResolvedJavaMethod> concretes, ProfiledType[] ptypes,
+                        int[] typesToConcretes, double notRecordedTypeProbability) {
+            super(invoke, weight, level);
+            assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods";
+            assert ptypes.length == typesToConcretes.length : "array lengths must match";
+
+            this.concretes = concretes;
+            this.ptypes = ptypes;
+            this.typesToConcretes = typesToConcretes;
+            this.notRecordedTypeProbability = notRecordedTypeProbability;
+        }
+
+        @Override
+        public int compiledCodeSize() {
+            int result = 0;
+            for (ResolvedJavaMethod m: concretes) {
+                result += m.compiledCodeSize();
+            }
+            return result;
+        }
+
+        @Override
+        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
+            int numberOfMethods = concretes.size();
+            boolean hasReturnValue = invoke.node().kind() != Kind.Void;
+
+            // receiver null check must be the first node
+            InliningUtil.receiverNullCheck(invoke);
+            if (numberOfMethods > 1 || shouldFallbackToInvoke()) {
+                inlineMultipleMethods(graph, runtime, callback, numberOfMethods, hasReturnValue);
+            } else {
+                inlineSingleMethod(graph, runtime, callback);
+            }
+        }
+
+        private boolean shouldFallbackToInvoke() {
+            return notRecordedTypeProbability > 0;
+        }
+
+        private void inlineMultipleMethods(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, int numberOfMethods, boolean hasReturnValue) {
+            FixedNode continuation = invoke.next();
+
+            ValueNode originalReceiver = invoke.methodCallTarget().receiver();
+            // setup merge and phi nodes for results and exceptions
+            MergeNode returnMerge = graph.add(new MergeNode());
+            returnMerge.setProbability(invoke.probability());
+            returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci));
+
+            PhiNode returnValuePhi = null;
+            if (hasReturnValue) {
+                returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge));
+            }
+
+            MergeNode exceptionMerge = null;
+            PhiNode exceptionObjectPhi = null;
+            if (invoke instanceof InvokeWithExceptionNode) {
+                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+                DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+
+                exceptionMerge = graph.add(new MergeNode());
+                exceptionMerge.setProbability(exceptionEdge.probability());
+
+                FixedNode exceptionSux = exceptionObject.next();
+                graph.addBeforeFixed(exceptionSux, exceptionMerge);
+                exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge));
+                exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Void, exceptionObjectPhi));
+            }
+
+            // create one separate block for each invoked method
+            BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods];
+            for (int i = 0; i < numberOfMethods; i++) {
+                int predecessors = 0;
+                double probability = 0;
+                for (int j = 0; j < typesToConcretes.length; j++) {
+                    if (typesToConcretes[j] == i) {
+                        predecessors++;
+                        probability += ptypes[j].probability;
+                    }
+                }
+
+                calleeEntryNodes[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, predecessors, invoke.probability() * probability, true);
+            }
+
+            // create the successor for an unknown type
+            FixedNode unknownTypeNode;
+            if (shouldFallbackToInvoke()) {
+                unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, notRecordedTypeProbability, false);
+            } else {
+                unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId()));
+            }
+
+            // replace the invoke exception edge
+            if (invoke instanceof InvokeWithExceptionNode) {
+                InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
+                BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+                exceptionObject.replaceAtUsages(exceptionObjectPhi);
+                exceptionObject.setNext(null);
+                GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
+            }
+
+            // replace the invoke with a switch on the type of the actual receiver
+            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver()));
+            graph.addBeforeFixed(invoke.node(), receiverHub);
+            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, calleeEntryNodes, unknownTypeNode);
+
+            assert invoke.next() == continuation;
+            invoke.setNext(null);
+            returnMerge.setNext(continuation);
+            invoke.node().replaceAtUsages(returnValuePhi);
+            invoke.node().replaceAndDelete(dispatchOnType);
+
+            ArrayList<PiNode> replacements = new ArrayList<>();
+
+            // do the actual inlining for every invoke
+            for (int i = 0; i < calleeEntryNodes.length; i++) {
+                BeginNode node = calleeEntryNodes[i];
+                Invoke invokeForInlining = (Invoke) node.next();
+
+                ResolvedJavaType commonType = getLeastCommonType(i);
+                ValueNode receiver = invokeForInlining.methodCallTarget().receiver();
+                boolean exact = getTypeCount(i) == 1;
+                PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
+                invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+                ResolvedJavaMethod concrete = concretes.get(i);
+                StructuredGraph calleeGraph = getGraph(concrete, callback);
+                callback.recordMethodContentsAssumption(concrete);
+                assert !IntrinsificationPhase.canIntrinsify(invokeForInlining, concrete, runtime);
+                InliningUtil.inline(invokeForInlining, calleeGraph, false);
+                replacements.add(anchoredReceiver);
+            }
+            if (shouldFallbackToInvoke()) {
+                replacements.add(null);
+            }
+            if (GraalOptions.OptTailDuplication) {
+                /*
+                 * We might want to perform tail duplication at the merge after a type switch, if there are invokes that would
+                 * benefit from the improvement in type information.
+                 */
+                FixedNode current = returnMerge;
+                int opportunities = 0;
+                do {
+                    if (current instanceof InvokeNode && ((InvokeNode) current).methodCallTarget().receiver() == originalReceiver) {
+                        opportunities++;
+                    } else if (current.inputs().contains(originalReceiver)) {
+                        opportunities++;
+                    }
+                    current = ((FixedWithNextNode) current).next();
+                } while (current instanceof FixedWithNextNode);
+                if (opportunities > 0) {
+                    metricInliningTailDuplication.increment();
+                    Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
+                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements);
+                }
+            }
+        }
+
+        private int getTypeCount(int concreteMethodIndex) {
+            int count = 0;
+            for (int i = 0; i < typesToConcretes.length; i++) {
+                if (typesToConcretes[i] == concreteMethodIndex) {
+                    count++;
+                }
+            }
+            return count;
+        }
+
+        private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
+            ResolvedJavaType commonType = null;
+            for (int i = 0; i < typesToConcretes.length; i++) {
+                if (typesToConcretes[i] == concreteMethodIndex) {
+                    if (commonType == null) {
+                        commonType = ptypes[i].type;
+                    } else {
+                        commonType = commonType.leastCommonAncestor(ptypes[i].type);
+                    }
+                }
+            }
+            assert commonType != null;
+            return commonType;
+        }
+
+        private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
+            assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+
+            MergeNode calleeEntryNode = graph.add(new MergeNode());
+            calleeEntryNode.setProbability(invoke.probability());
+            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver()));
+            graph.addBeforeFixed(invoke.node(), receiverHub);
+
+            FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId()));
+            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, new BeginNode[] {calleeEntryNode}, unknownTypeNode);
+
+            FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor();
+            pred.setNext(dispatchOnType);
+            calleeEntryNode.setNext(invoke.node());
+
+            ResolvedJavaMethod concrete = concretes.get(0);
+            StructuredGraph calleeGraph = getGraph(concrete, callback);
+            assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime);
+            callback.recordMethodContentsAssumption(concrete);
+            InliningUtil.inline(invoke, calleeGraph, false);
+        }
+
+        private FixedNode createDispatchOnType(StructuredGraph graph, LoadHubNode objectClassNode, BeginNode[] calleeEntryNodes, FixedNode unknownTypeSux) {
+            assert ptypes.length > 1;
+
+            ResolvedJavaType[] types = new ResolvedJavaType[ptypes.length];
+            double[] probabilities = new double[ptypes.length + 1];
+            BeginNode[] successors = new BeginNode[ptypes.length + 1];
+            int[] keySuccessors = new int[ptypes.length + 1];
+            for (int i = 0; i < ptypes.length; i++) {
+                types[i] = ptypes[i].type;
+                probabilities[i] = ptypes[i].probability;
+                FixedNode entry = calleeEntryNodes[typesToConcretes[i]];
+                if (entry instanceof MergeNode) {
+                    EndNode endNode = graph.add(new EndNode());
+                    ((MergeNode) entry).addForwardEnd(endNode);
+                    entry = endNode;
+                }
+                successors[i] = BeginNode.begin(entry);
+                keySuccessors[i] = i;
+            }
+            assert !(unknownTypeSux instanceof MergeNode);
+            successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+            probabilities[successors.length - 1] = notRecordedTypeProbability;
+            keySuccessors[successors.length - 1] = successors.length - 1;
+
+            TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(objectClassNode, successors, probabilities, types, probabilities, keySuccessors));
+
+            return typeSwitch;
+        }
+
+        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi,
+                        MergeNode exceptionMerge, PhiNode exceptionObjectPhi, int predecessors, double probability, boolean useForInlining) {
+            Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability);
+            BeginNode calleeEntryNode = graph.add(predecessors > 1 ? new MergeNode() : new BeginNode());
+            calleeEntryNode.setNext(duplicatedInvoke.node());
+            calleeEntryNode.setProbability(probability);
+
+            EndNode endNode = graph.add(new EndNode());
+            endNode.setProbability(probability);
+
+            duplicatedInvoke.setNext(endNode);
+            returnMerge.addForwardEnd(endNode);
+
+            if (returnValuePhi != null) {
+                returnValuePhi.addInput(duplicatedInvoke.node());
+            }
+            return calleeEntryNode;
+        }
+
+        private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) {
+            Invoke result = (Invoke) invoke.node().copyWithInputs();
+            Node callTarget = result.callTarget().copyWithInputs();
+            result.node().replaceFirstInput(result.callTarget(), callTarget);
+            result.setUseForInlining(useForInlining);
+            result.setProbability(probability);
+
+            Kind kind = invoke.node().kind();
+            if (!kind.isVoid()) {
+                FrameState stateAfter = invoke.stateAfter();
+                stateAfter = stateAfter.duplicate(stateAfter.bci);
+                stateAfter.replaceFirstInput(invoke.node(), result.node());
+                result.setStateAfter(stateAfter);
+            }
+
+            if (invoke instanceof InvokeWithExceptionNode) {
+                assert exceptionMerge != null && exceptionObjectPhi != null;
+
+                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+                FrameState stateAfterException = exceptionObject.stateAfter();
+
+                BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs();
+                ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs();
+                // set new state (pop old exception object, push new one)
+                newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject));
+                newExceptionEdge.setNext(newExceptionObject);
+
+                EndNode endNode = graph.add(new EndNode());
+                newExceptionObject.setNext(endNode);
+                exceptionMerge.addForwardEnd(endNode);
+                exceptionObjectPhi.addInput(newExceptionObject);
+
+                ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
+            }
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
+            builder.append(String.format(", %d methods with %d type checks:", concretes.size(), ptypes.length));
+            for (int i = 0; i < concretes.size(); i++) {
+                builder.append(MetaUtil.format("  %H.%n(%p):%r", concretes.get(i)));
+            }
+            return builder.toString();
+        }
+
+        @Override
+        public boolean canDeopt() {
+            return true;
+        }
+    }
+
+
+    /**
+     * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method,
+     * but for which an assumption has to be registered because of non-final classes.
+     */
+    private static class AssumptionInlineInfo extends ExactInlineInfo {
+        public final ResolvedJavaType context;
+
+        public AssumptionInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaType context, ResolvedJavaMethod concrete) {
+            super(invoke, weight, level, concrete);
+            this.context = context;
+        }
+
+        @Override
+        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
+            if (Debug.isLogEnabled()) {
+                String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod());
+                String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete);
+                Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName);
+            }
+            callback.recordConcreteMethodAssumption(invoke.methodCallTarget().targetMethod(), context, concrete);
+
+            super.inline(graph, runtime, callback);
+        }
+
+        @Override
+        public String toString() {
+            return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
+        }
+
+        @Override
+        public boolean canDeopt() {
+            return true;
+        }
+    }
+
+    /**
+     * Determines if inlining is possible at the given invoke node.
+     * @param invoke the invoke that should be inlined
+     * @param level the number of nested inlinings that lead to this invoke, or 0 if the invoke was part of the initial graph
+     * @param runtime a GraalRuntime instance used to determine of the invoke can be inlined and/or should be intrinsified
+     * @param callback a callback that is used to determine the weight of a specific inlining
+     * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
+     */
+    public static InlineInfo getInlineInfo(Invoke invoke, int level, GraalCodeCacheProvider runtime, Assumptions assumptions, InliningCallback callback, OptimisticOptimizations optimisticOpts) {
+        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
+            // The invoke has already been lowered , or has been created as a low-level node. We have no method information.
+            return null;
+        }
+        ResolvedJavaMethod parent = invoke.stateAfter().method();
+        MethodCallTargetNode callTarget = invoke.methodCallTarget();
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+        if (targetMethod == null) {
+            return null;
+        }
+        if (!checkInvokeConditions(invoke)) {
+            return null;
+        }
+
+        if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
+            if (checkTargetConditions(invoke, targetMethod, optimisticOpts)) {
+                double weight = callback == null ? 0 : callback.inliningWeight(parent, targetMethod, invoke);
+                return new ExactInlineInfo(invoke, weight, level, targetMethod);
+            }
+            return null;
+        }
+        ObjectStamp receiverStamp = callTarget.receiver().objectStamp();
+        ResolvedJavaType receiverType = receiverStamp.type();
+        if (receiverStamp.isExactType()) {
+            assert receiverType.isSubtypeOf(targetMethod.holder()) : receiverType + " subtype of " + targetMethod.holder() + " for " + targetMethod;
+            ResolvedJavaMethod resolved = receiverType.resolveMethodImpl(targetMethod);
+            if (checkTargetConditions(invoke, resolved, optimisticOpts)) {
+                double weight = callback == null ? 0 : callback.inliningWeight(parent, resolved, invoke);
+                return new ExactInlineInfo(invoke, weight, level, resolved);
+            }
+            return null;
+        }
+        ResolvedJavaType holder = targetMethod.holder();
+
+        if (receiverStamp.type() != null) {
+            // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...)
+            // TODO (lstadler) fix this
+            if (receiverType != null && receiverType.isSubtypeOf(holder)) {
+                holder = receiverType;
+            }
+        }
+        // TODO (thomaswue) fix this
+        if (assumptions != null) {
+            ResolvedJavaMethod concrete = holder.uniqueConcreteMethod(targetMethod);
+            if (concrete != null) {
+                if (checkTargetConditions(invoke, concrete, optimisticOpts)) {
+                    double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
+                    return new AssumptionInlineInfo(invoke, weight, level, holder, concrete);
+                }
+                return null;
+            }
+        }
+
+        // type check based inlining
+        return getTypeCheckedInlineInfo(invoke, level, callback, parent, targetMethod, optimisticOpts);
+    }
+
+    private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, int level, InliningCallback callback, ResolvedJavaMethod parent, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) {
+        ProfilingInfo profilingInfo = parent.profilingInfo();
+        JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
+        if (typeProfile != null) {
+            ProfiledType[] ptypes = typeProfile.getTypes();
+
+            if (ptypes != null && ptypes.length > 0) {
+                double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
+                if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
+                    if (optimisticOpts.inlineMonomorphicCalls()) {
+                        ResolvedJavaType type = ptypes[0].type;
+                        ResolvedJavaMethod concrete = type.resolveMethodImpl(targetMethod);
+                        if (checkTargetConditions(invoke, concrete, optimisticOpts)) {
+                            double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
+                            return new TypeGuardInlineInfo(invoke, weight, level, concrete, type);
+                        }
+
+                        Debug.log("not inlining %s because method can't be inlined", methodName(targetMethod, invoke));
+                        return null;
+                    } else {
+                        Debug.log("not inlining %s because GraalOptions.InlineMonomorphicCalls == false", methodName(targetMethod, invoke));
+                        return null;
+                    }
+                } else {
+                    invoke.setMegamorphic(true);
+                    if (optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0 || optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
+                        // TODO (chaeubl) inlining of multiple methods should work differently
+                        // 1. check which methods can be inlined
+                        // 2. for those methods, use weight and probability to compute which of them should be inlined
+                        // 3. do the inlining
+                        //    a) all seen methods can be inlined -> do so and guard with deopt
+                        //    b) some methods can be inlined -> inline them and fall back to invocation if violated
+                        // TODO (chaeubl) sort types by probability
+
+                        // determine concrete methods and map type to specific method
+                        ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
+                        int[] typesToConcretes = new int[ptypes.length];
+                        for (int i = 0; i < ptypes.length; i++) {
+                            ResolvedJavaMethod concrete = ptypes[i].type.resolveMethodImpl(targetMethod);
+
+                            int index = concreteMethods.indexOf(concrete);
+                            if (index < 0) {
+                                index = concreteMethods.size();
+                                concreteMethods.add(concrete);
+                            }
+                            typesToConcretes[i] = index;
+                        }
+
+                        double totalWeight = 0;
+                        boolean canInline = true;
+                        for (ResolvedJavaMethod concrete: concreteMethods) {
+                            if (!checkTargetConditions(invoke, concrete, optimisticOpts)) {
+                                canInline = false;
+                                break;
+                            }
+                            totalWeight += callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
+                        }
+
+                        if (canInline) {
+                            return new MultiTypeGuardInlineInfo(invoke, totalWeight, level, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability);
+                        } else {
+                            Debug.log("not inlining %s because it is a polymorphic method call and at least one invoked method cannot be inlined", methodName(targetMethod, invoke));
+                            return null;
+                        }
+                    } else {
+                        if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
+                            Debug.log("not inlining %s because GraalOptions.InlinePolymorphicCalls == false", methodName(targetMethod, invoke));
+                        } else {
+                            Debug.log("not inlining %s because GraalOptions.InlineMegamorphicCalls == false", methodName(targetMethod, invoke));
+                        }
+                        return null;
+                    }
+                }
+            }
+
+            Debug.log("not inlining %s because no types/probabilities were recorded", methodName(targetMethod, invoke));
+            return null;
+        } else {
+            Debug.log("not inlining %s because no type profile exists", methodName(targetMethod, invoke));
+            return null;
+        }
+    }
+
+    private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
+        // to avoid that floating reads on receiver fields float above the type check
+        return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType)));
+    }
+
+    private static boolean checkInvokeConditions(Invoke invoke) {
+        if (invoke.stateAfter() == null) {
+            Debug.log("not inlining %s because the invoke has no after state", methodName(invoke.methodCallTarget().targetMethod(), invoke));
+            return false;
+        }
+        if (invoke.predecessor() == null) {
+            Debug.log("not inlining %s because the invoke is dead code", methodName(invoke.methodCallTarget().targetMethod(), invoke));
+            return false;
+        }
+        if (!invoke.useForInlining()) {
+            Debug.log("not inlining %s because invoke is marked to be not used for inlining", methodName(invoke.methodCallTarget().targetMethod(), invoke));
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean checkTargetConditions(Invoke invoke, JavaMethod method, OptimisticOptimizations optimisticOpts) {
+        if (method == null) {
+            Debug.log("not inlining because method is not resolved");
+            return false;
+        }
+        if (!(method instanceof ResolvedJavaMethod)) {
+            Debug.log("not inlining %s because it is unresolved", method.toString());
+            return false;
+        }
+        ResolvedJavaMethod resolvedMethod = (ResolvedJavaMethod) method;
+        if (Modifier.isNative(resolvedMethod.accessFlags())) {
+            Debug.log("not inlining %s because it is a native method", methodName(resolvedMethod, invoke));
+            return false;
+        }
+        if (Modifier.isAbstract(resolvedMethod.accessFlags())) {
+            Debug.log("not inlining %s because it is an abstract method", methodName(resolvedMethod, invoke));
+            return false;
+        }
+        if (!resolvedMethod.holder().isInitialized()) {
+            Debug.log("not inlining %s because of non-initialized class", methodName(resolvedMethod, invoke));
+            return false;
+        }
+        if (!resolvedMethod.canBeInlined()) {
+            Debug.log("not inlining %s because it is marked non-inlinable", methodName(resolvedMethod, invoke));
+            return false;
+        }
+        if (computeRecursiveInliningLevel(invoke.stateAfter(), (ResolvedJavaMethod) method) > GraalOptions.MaximumRecursiveInlining) {
+            Debug.log("not inlining %s because it exceeds the maximum recursive inlining depth", methodName(resolvedMethod, invoke));
+            return false;
+        }
+        OptimisticOptimizations calleeOpts = new OptimisticOptimizations(resolvedMethod);
+        if (calleeOpts.lessOptimisticThan(optimisticOpts)) {
+            Debug.log("not inlining %s because callee uses less optimistic optimizations than caller", methodName(resolvedMethod, invoke));
+            return false;
+        }
+
+        return true;
+    }
+
+    private static int computeRecursiveInliningLevel(FrameState state, ResolvedJavaMethod method) {
+        assert state != null;
+
+        int count = 0;
+        FrameState curState = state;
+        while (curState != null) {
+            if (curState.method() == method) {
+                count++;
+            }
+            curState = curState.outerFrameState();
+        }
+        return count;
+    }
+
+    /**
+     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
+     *
+     * @param invoke the invoke that will be replaced
+     * @param inlineGraph the graph that the invoke will be replaced with
+     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
+     */
+    public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+        InliningIdentifier identifier = new InliningIdentifier(inlineGraph.method(), invoke);
+        NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
+        StructuredGraph graph = (StructuredGraph) invoke.node().graph();
+
+        FrameState stateAfter = invoke.stateAfter();
+        assert stateAfter.isAlive();
+
+        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
+        ArrayList<Node> nodes = new ArrayList<>();
+        ReturnNode returnNode = null;
+        UnwindNode unwindNode = null;
+        StartNode entryPointNode = inlineGraph.start();
+        FixedNode firstCFGNode = entryPointNode.next();
+        for (Node node : inlineGraph.getNodes()) {
+            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
+                // Do nothing.
+            } else if (node instanceof LocalNode) {
+                replacements.put(node, parameters.get(((LocalNode) node).index()));
+            } else {
+                nodes.add(node);
+                if (node instanceof ReturnNode) {
+                    assert returnNode == null;
+                    returnNode = (ReturnNode) node;
+                } else if (node instanceof UnwindNode) {
+                    assert unwindNode == null;
+                    unwindNode = (UnwindNode) node;
+                }
+            }
+        }
+        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode
+
+        assert invoke.node().successors().first() != null : invoke;
+        assert invoke.node().predecessor() != null;
+
+        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
+        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+        if (receiverNullCheck) {
+            receiverNullCheck(invoke);
+        }
+        invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate);
+
+        FrameState stateAtExceptionEdge = null;
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
+            if (unwindNode != null) {
+                assert unwindNode.predecessor() != null;
+                assert invokeWithException.exceptionEdge().successors().count() == 1;
+                ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next();
+                stateAtExceptionEdge = obj.stateAfter();
+                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+                obj.replaceAtUsages(unwindDuplicate.exception());
+                unwindDuplicate.clearInputs();
+                Node n = obj.next();
+                obj.setNext(null);
+                unwindDuplicate.replaceAndDelete(n);
+            } else {
+                invokeWithException.killExceptionEdge();
+            }
+        } else {
+            if (unwindNode != null) {
+                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+                DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler, invoke.leafGraphId());
+                unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode));
+                // move the deopt upwards if there is a monitor exit that tries to use the "after exception" frame state
+                // (because there is no "after exception" frame state!)
+                if (deoptimizeNode.predecessor() instanceof MonitorExitNode) {
+                    MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor();
+                    if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) {
+                        FrameState monitorFrameState = monitorExit.stateAfter();
+                        graph.removeFixed(monitorExit);
+                        monitorFrameState.safeDelete();
+                    }
+                }
+            }
+        }
+
+        FrameState outerFrameState = null;
+        double invokeProbability = invoke.node().probability();
+        for (Node node : duplicates.values()) {
+            if (GraalOptions.ProbabilityAnalysis) {
+                if (node instanceof FixedNode) {
+                    FixedNode fixed = (FixedNode) node;
+                    double newProbability = fixed.probability() * invokeProbability;
+                    if (GraalOptions.LimitInlinedProbability) {
+                        newProbability = Math.min(newProbability, invokeProbability);
+                    }
+                    fixed.setProbability(newProbability);
+                }
+            }
+            if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+                assert frameState.bci != FrameState.BEFORE_BCI;
+                if (frameState.bci == FrameState.AFTER_BCI) {
+                    frameState.replaceAndDelete(stateAfter);
+                } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) {
+                    if (frameState.isAlive()) {
+                        assert stateAtExceptionEdge != null;
+                        frameState.replaceAndDelete(stateAtExceptionEdge);
+                    } else {
+                        assert stateAtExceptionEdge == null;
+                    }
+                } else {
+                    // only handle the outermost frame states
+                    if (frameState.outerFrameState() == null) {
+                        assert frameState.method() == inlineGraph.method();
+                        if (outerFrameState == null) {
+                            outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind());
+                            outerFrameState.setDuringCall(true);
+                        }
+                        frameState.setOuterFrameState(outerFrameState);
+                        frameState.setInliningIdentifier(identifier);
+                    }
+                }
+            }
+        }
+
+        Node returnValue = null;
+        if (returnNode != null) {
+            if (returnNode.result() instanceof LocalNode) {
+                returnValue = replacements.get(returnNode.result());
+            } else {
+                returnValue = duplicates.get(returnNode.result());
+            }
+            invoke.node().replaceAtUsages(returnValue);
+            Node returnDuplicate = duplicates.get(returnNode);
+            returnDuplicate.clearInputs();
+            Node n = invoke.next();
+            invoke.setNext(null);
+            returnDuplicate.replaceAndDelete(n);
+        }
+
+        invoke.node().clearInputs();
+        invoke.node().replaceAtUsages(null);
+        GraphUtil.killCFG(invoke.node());
+
+        if (stateAfter.usages().isEmpty()) {
+            stateAfter.safeDelete();
+        }
+    }
+
+    public static void receiverNullCheck(Invoke invoke) {
+        MethodCallTargetNode callTarget = invoke.methodCallTarget();
+        StructuredGraph graph = (StructuredGraph) invoke.graph();
+        NodeInputList<ValueNode> parameters = callTarget.arguments();
+        ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
+        if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) {
+            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, true, invoke.leafGraphId())));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InsertStateAfterPlaceholderPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.phases.*;
+
+public class InsertStateAfterPlaceholderPhase extends Phase {
+
+    private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, LIRLowerable, Canonicalizable {
+        public PlaceholderNode() {
+            super(StampFactory.forVoid());
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            // nothing to do
+        }
+
+        @Override
+        public boolean hasSideEffect(CodeCacheProvider runtime) {
+            return false;
+        }
+
+        @Override
+        public ValueNode canonical(CanonicalizerTool tool) {
+            if (stateAfter() == null) {
+                return null;
+            }
+            return this;
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (ReturnNode ret : graph.getNodes(ReturnNode.class)) {
+            PlaceholderNode p = graph.add(new PlaceholderNode());
+            p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI)));
+            graph.addBeforeFixed(ret, p);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IntrinsificationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+
+public class IntrinsificationPhase extends Phase {
+
+    private final GraalCodeCacheProvider runtime;
+
+    public IntrinsificationPhase(GraalCodeCacheProvider runtime) {
+        this.runtime = runtime;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (InvokeNode invoke : graph.getNodes(InvokeNode.class)) {
+            tryIntrinsify(invoke, runtime);
+        }
+        for (InvokeWithExceptionNode invoke : graph.getNodes(InvokeWithExceptionNode.class)) {
+            tryIntrinsify(invoke, runtime);
+        }
+    }
+
+    public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
+        return getIntrinsicGraph(invoke, target, runtime) != null;
+    }
+
+    private static void tryIntrinsify(Invoke invoke, GraalCodeCacheProvider runtime) {
+        if (invoke.callTarget() instanceof MethodCallTargetNode && invoke.methodCallTarget().targetMethod() != null) {
+            tryIntrinsify(invoke, invoke.methodCallTarget().targetMethod(), runtime);
+        }
+    }
+
+    private static void tryIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
+        StructuredGraph intrinsicGraph = getIntrinsicGraph(invoke, target, runtime);
+        if (intrinsicGraph != null) {
+            Debug.log(" > Intrinsify %s", target);
+            InliningUtil.inline(invoke, intrinsicGraph, true);
+        }
+    }
+
+    private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
+        StructuredGraph intrinsicGraph = (StructuredGraph) target.compilerStorage().get(Graph.class);
+        if (intrinsicGraph == null) {
+            // TODO remove once all intrinsics are available via compilerStorage
+            intrinsicGraph = runtime.intrinsicGraph(invoke.stateAfter().method(), invoke.bci(), target, invoke.callTarget().arguments());
+        }
+        return intrinsicGraph;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeCheckCastEliminationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Graph.InputChangedListener;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+
+public class IterativeCheckCastEliminationPhase extends Phase {
+    private final TargetDescription target;
+    private final MetaAccessProvider runtime;
+    private final Assumptions assumptions;
+
+    public IterativeCheckCastEliminationPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) {
+        this.target = target;
+        this.runtime = runtime;
+        this.assumptions = assumptions;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        Set<Node> canonicalizationRoots = new HashSet<>();
+        CheckCastEliminationPhase eliminate = new CheckCastEliminationPhase();
+        Listener listener = new Listener(canonicalizationRoots);
+        while (true) {
+            graph.trackInputChange(listener);
+            eliminate.apply(graph);
+            graph.stopTrackingInputChange();
+            if (canonicalizationRoots.isEmpty()) {
+                break;
+            }
+            new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots, null).apply(graph);
+            canonicalizationRoots.clear();
+        }
+    }
+
+    private static class Listener implements InputChangedListener {
+        private final Set<Node> canonicalizationRoots;
+        public Listener(Set<Node> canonicalizationRoots) {
+            this.canonicalizationRoots = canonicalizationRoots;
+        }
+        @Override
+        public void inputChanged(Node node) {
+            canonicalizationRoots.add(node);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.util.*;
+
+/**
+ * Adds safepoints to loops.
+ */
+public class LoopSafepointInsertionPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        nextLoop:
+        for (LoopEndNode loopEnd : graph.getNodes(LoopEndNode.class)) {
+            if (!loopEnd.canSafepoint()) {
+                continue;
+            }
+            if (GraalOptions.OptSafepointElimination) {
+                // We 'eliminate' safepoints by simply never placing them into loops that have at least one call
+                NodeIterable<FixedNode> it = NodeIterators.dominators(loopEnd).until(loopEnd.loopBegin());
+                for (FixedNode n : it) {
+                    if (n instanceof Invoke) {
+                        continue nextLoop;
+                    }
+                }
+            }
+            SafepointNode safepoint = graph.add(new SafepointNode());
+            graph.addBeforeFixed(loopEnd, safepoint);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.schedule.*;
+
+/**
+ * Processes all {@link Lowerable} nodes to do their lowering.
+ */
+public class LoweringPhase extends Phase {
+
+    final class LoweringToolImpl implements LoweringTool {
+
+        final FixedNode guardAnchor;
+        final NodeBitMap activeGuards;
+        FixedWithNextNode lastFixedNode;
+
+        public LoweringToolImpl(FixedNode guardAnchor, NodeBitMap activeGuards) {
+            this.guardAnchor = guardAnchor;
+            this.activeGuards = activeGuards;
+        }
+
+        @Override
+        public GraalCodeCacheProvider getRuntime() {
+            return runtime;
+        }
+
+        @Override
+        public ValueNode createNullCheckGuard(ValueNode object, long leafGraphId) {
+            return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, leafGraphId);
+        }
+
+        @Override
+        public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, long leafGraphId) {
+            return createGuard(condition, deoptReason, action, false, leafGraphId);
+        }
+
+        @Override
+        public Assumptions assumptions() {
+            return assumptions;
+        }
+
+        @Override
+        public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId) {
+            if (GraalOptions.OptEliminateGuards) {
+                for (Node usage : condition.usages()) {
+                    if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) {
+                        return (ValueNode) usage;
+                    }
+                }
+            }
+            GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, leafGraphId));
+            if (GraalOptions.OptEliminateGuards) {
+                activeGuards.grow();
+                activeGuards.mark(newGuard);
+            }
+            return newGuard;
+        }
+
+        public FixedWithNextNode lastFixedNode() {
+            return lastFixedNode;
+        }
+    }
+
+    private final GraalCodeCacheProvider runtime;
+    private final Assumptions assumptions;
+
+    public LoweringPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) {
+        this.runtime = runtime;
+        this.assumptions = assumptions;
+    }
+
+    private static boolean containsLowerable(NodeIterable<Node> nodes) {
+        for (Node n : nodes) {
+            if (n instanceof Lowerable) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void run(final StructuredGraph graph) {
+        int  i = 0;
+        NodeBitMap processed = graph.createNodeBitMap();
+        while (true) {
+            int mark = graph.getMark();
+            final SchedulePhase schedule = new SchedulePhase();
+            schedule.apply(graph, false);
+
+            processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed);
+            Debug.dump(graph, "Lowering iteration %d", i++);
+            new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph);
+
+            if (!containsLowerable(graph.getNewNodes(mark))) {
+                // No new lowerable nodes - done!
+                break;
+            }
+            assert graph.verify();
+            processed.grow();
+        }
+    }
+
+    private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor, SchedulePhase schedule, NodeBitMap processed) {
+
+        FixedNode anchor = parentAnchor;
+        if (anchor == null) {
+            anchor = block.getBeginNode();
+        }
+        process(block, activeGuards, anchor, schedule, processed);
+
+        // Process always reached block first.
+        Block alwaysReachedBlock = block.getPostdominator();
+        if (alwaysReachedBlock != null && alwaysReachedBlock.getDominator() == block) {
+            processBlock(alwaysReachedBlock, activeGuards, anchor, schedule, processed);
+        }
+
+        // Now go for the other dominators.
+        for (Block dominated : block.getDominated()) {
+            if (dominated != alwaysReachedBlock) {
+                assert dominated.getDominator() == block;
+                processBlock(dominated, activeGuards, null, schedule, processed);
+            }
+        }
+
+        if (parentAnchor == null && GraalOptions.OptEliminateGuards) {
+            for (GuardNode guard : anchor.usages().filter(GuardNode.class)) {
+                activeGuards.clear(guard);
+            }
+        }
+    }
+
+    private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor, SchedulePhase schedule, NodeBitMap processed) {
+
+        final LoweringToolImpl loweringTool = new LoweringToolImpl(anchor, activeGuards);
+
+        // Lower the instructions of this block.
+        List<ScheduledNode> nodes = schedule.nodesFor(b);
+
+        for (Node node : nodes) {
+            FixedNode lastFixedNext = null;
+            if (node instanceof FixedWithNextNode) {
+                FixedWithNextNode fixed = (FixedWithNextNode) node;
+                lastFixedNext = fixed.next();
+                loweringTool.lastFixedNode = fixed;
+            }
+
+            if (node.isAlive() && !processed.isMarked(node)) {
+                processed.mark(node);
+                if (node instanceof Lowerable) {
+                    ((Lowerable) node).lower(loweringTool);
+                }
+            }
+
+            if (loweringTool.lastFixedNode == node && !node.isAlive()) {
+                if (lastFixedNext == null) {
+                    loweringTool.lastFixedNode = null;
+                } else {
+                    Node prev = lastFixedNext.predecessor();
+                    if (prev != node && prev instanceof FixedWithNextNode) {
+                        loweringTool.lastFixedNode = (FixedWithNextNode) prev;
+                    } else if (lastFixedNext instanceof FixedWithNextNode) {
+                        loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext;
+                    } else {
+                        loweringTool.lastFixedNode = null;
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/PhiStampPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+public class PhiStampPhase extends Phase {
+    @Override
+    protected void run(StructuredGraph graph) {
+        // Infer phis stopping at loop phis.
+        for (PhiNode phi : graph.getNodes(PhiNode.class)) {
+            inferPhi(phi);
+        }
+
+        // Start iterative inference for loop phis.
+        if (graph.hasLoops()) {
+            for (PhiNode phi : graph.getNodes(PhiNode.class)) {
+                if (phi.isLoopPhi()) {
+                    iterativeInferPhi(phi);
+                }
+            }
+        }
+    }
+
+    private void iterativeInferPhi(PhiNode phi) {
+        if (phi.inferPhiStamp()) {
+            for (PhiNode phiUsage : phi.usages().filter(PhiNode.class)) {
+                iterativeInferPhi(phiUsage);
+            }
+        }
+    }
+
+    private void inferPhi(PhiNode phi) {
+        for (PhiNode phiInput : phi.values().filter(PhiNode.class)) {
+            if (!phiInput.isLoopPhi()) {
+                inferPhi(phiInput);
+            }
+        }
+        phi.inferPhiStamp();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.*;
+
+public class ReadEliminationPhase extends Phase {
+    private Queue<PhiNode> newPhis;
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        newPhis = new LinkedList<>();
+        for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) {
+            if (isReadEliminable(n)) {
+                NodeMap<ValueNode> nodeMap = n.graph().createNodeMap();
+                ValueNode value = getValue(n, n.lastLocationAccess(), nodeMap);
+                Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value);
+                graph.replaceFloating(n, value);
+            }
+        }
+    }
+
+    private boolean isReadEliminable(FloatingReadNode n) {
+        return isWrites(n, n.lastLocationAccess(), n.graph().createNodeBitMap());
+    }
+
+    private boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) {
+        if (lastLocationAccess == null) {
+            return false;
+        }
+        if (visited.isMarked(lastLocationAccess)) {
+            return true; // dataflow loops must come from Phis assume them ok until proven wrong
+        }
+        if (lastLocationAccess instanceof ValueProxyNode) {
+            return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited);
+        }
+        if (lastLocationAccess instanceof WriteNode) {
+            WriteNode other = (WriteNode) lastLocationAccess;
+            return other.object() == n.object() && other.location() == n.location();
+        }
+        if (lastLocationAccess instanceof PhiNode) {
+            visited.mark(lastLocationAccess);
+            for (ValueNode value : ((PhiNode) lastLocationAccess).values()) {
+                if (!isWrites(n, value, visited)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private ValueNode getValue(FloatingReadNode n, Node lastLocationAccess, NodeMap<ValueNode> nodeMap) {
+        ValueNode exisiting = nodeMap.get(lastLocationAccess);
+        if (exisiting != null) {
+            return exisiting;
+        }
+        if (lastLocationAccess instanceof ValueProxyNode) {
+            ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess;
+            ValueNode value = getValue(n, proxy.value(), nodeMap);
+            return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value));
+        }
+        if (lastLocationAccess instanceof WriteNode) {
+            return ((WriteNode) lastLocationAccess).value();
+        }
+        if (lastLocationAccess instanceof PhiNode) {
+            PhiNode phi = (PhiNode) lastLocationAccess;
+            PhiNode newPhi = phi.graph().add(new PhiNode(n.kind(), phi.merge()));
+            nodeMap.set(lastLocationAccess, newPhi);
+            for (ValueNode value : phi.values()) {
+                newPhi.addInput(getValue(n, value, nodeMap));
+            }
+            newPhis.add(newPhi);
+            return newPhi;
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+
+public class RemoveValueProxyPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) {
+            graph.replaceFloating(vpn, vpn.value());
+        }
+        for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) {
+            FrameState stateAfter = exit.stateAfter();
+            if (stateAfter != null) {
+                exit.setStateAfter(null);
+                if (stateAfter.usages().count() == 0) {
+                    stateAfter.safeDelete();
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.Graph.DuplicationReplacement;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.VirtualState.NodeClosure;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+/**
+ * This class is a phase that looks for opportunities for tail duplication. The static method
+ * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail duplication from
+ * other places, e.g., inlining.
+ */
+public class TailDuplicationPhase extends Phase {
+
+    /*
+     * Various metrics on the circumstances in which tail duplication was/wasn't performed.
+     */
+    private static final DebugMetric metricDuplicationMonitors = Debug.metric("DuplicationMonitors");
+    private static final DebugMetric metricDuplicationEnd = Debug.metric("DuplicationEnd");
+    private static final DebugMetric metricDuplicationEndPerformed = Debug.metric("DuplicationEndPerformed");
+    private static final DebugMetric metricDuplicationOther = Debug.metric("DuplicationOther");
+    private static final DebugMetric metricDuplicationOtherPerformed = Debug.metric("DuplicationOtherPerformed");
+
+    /**
+     * This interface is used by tail duplication to let clients decide if tail duplication should be performed.
+     */
+    public interface TailDuplicationDecision {
+
+        /**
+         * Queries if tail duplication should be performed at the given merge. If this method returns true then the tail
+         * duplication will be performed, because all other checks have happened before.
+         *
+         * @param merge The merge at which tail duplication can be performed.
+         * @param fixedNodeCount The size of the set of fixed nodes that forms the base for the duplicated set of nodes.
+         * @return true if the tail duplication should be performed, false otherwise.
+         */
+        boolean doTransform(MergeNode merge, int fixedNodeCount);
+    }
+
+    /**
+     * A tail duplication decision closure that employs the default algorithm: Check if there are any phis on the merge
+     * whose stamps improve and that have usages within the duplicated set of fixed nodes.
+     */
+    public static final TailDuplicationDecision DEFAULT_DECISION = new TailDuplicationDecision() {
+
+        public boolean doTransform(MergeNode merge, int fixedNodeCount) {
+            if (fixedNodeCount < GraalOptions.TailDuplicationTrivialSize) {
+                return true;
+            }
+            HashSet<PhiNode> improvements = new HashSet<>();
+            for (PhiNode phi : merge.phis()) {
+                Stamp phiStamp = phi.stamp();
+                for (ValueNode input : phi.values()) {
+                    if (!input.stamp().equals(phiStamp)) {
+                        improvements.add(phi);
+                        break;
+                    }
+                }
+            }
+            if (improvements.isEmpty()) {
+                return false;
+            }
+            FixedNode current = merge;
+            int opportunities = 0;
+            while (current instanceof FixedWithNextNode) {
+                current = ((FixedWithNextNode) current).next();
+                for (PhiNode phi : improvements) {
+                    for (Node input : current.inputs()) {
+                        if (input == phi) {
+                            opportunities++;
+                        }
+                        if (input.inputs().contains(phi)) {
+                            opportunities++;
+                        }
+                    }
+                }
+            }
+            return opportunities > 0;
+        }
+    };
+
+    /**
+     * A tail duplication decision closure that always returns true.
+     */
+    public static final TailDuplicationDecision TRUE_DECISION = new TailDuplicationDecision() {
+
+        @Override
+        public boolean doTransform(MergeNode merge, int fixedNodeCount) {
+            return true;
+        }
+    };
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        // A snapshot is taken here, so that new MergeNode instances aren't considered for tail duplication.
+        for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
+            if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) {
+                tailDuplicate(merge, DEFAULT_DECISION, null);
+            }
+        }
+    }
+
+    /**
+     * This method attempts to duplicate the tail of the given merge. The merge must not be a {@link LoopBeginNode}. If
+     * the merge is eligible for duplication (at least one fixed node in its tail, no {@link MonitorEnterNode}/
+     * {@link MonitorExitNode}, non-null {@link MergeNode#stateAfter()}) then the decision callback is used to determine
+     * whether the tail duplication should actually be performed. If replacements is non-null, then this list of
+     * {@link PiNode}s is used to replace one value per merge end.
+     *
+     * @param merge The merge whose tail should be duplicated.
+     * @param decision A callback that can make the final decision if tail duplication should occur or not.
+     * @param replacements A list of {@link PiNode}s, or null. If this list is non-null then its size needs to match the
+     *            merge's end count. Each entry can either be null or a {@link PiNode}, and is used to replace
+     *            {@link PiNode#object()} with the {@link PiNode} in the duplicated branch that corresponds to the
+     *            entry.
+     */
+    public static void tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements) {
+        assert !(merge instanceof LoopBeginNode);
+        assert replacements == null || replacements.size() == merge.forwardEndCount();
+        FixedNode fixed = merge;
+        int fixedCount = 0;
+        boolean containsMonitor = false;
+        while (fixed instanceof FixedWithNextNode) {
+            if (fixed instanceof MonitorEnterNode || fixed instanceof MonitorExitNode) {
+                containsMonitor = true;
+            }
+            fixed = ((FixedWithNextNode) fixed).next();
+            fixedCount++;
+        }
+        if (containsMonitor) {
+            // cannot currently be handled
+            // TODO (ls) re-evaluate this limitation after changes to the lock representation and the LIR generator
+            metricDuplicationMonitors.increment();
+        } else if (fixedCount > 1) {
+            if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) {
+                metricDuplicationEnd.increment();
+                if (decision.doTransform(merge, fixedCount)) {
+                    metricDuplicationEndPerformed.increment();
+                    new DuplicationOperation(merge, replacements).duplicate();
+                }
+            } else if (merge.stateAfter() != null) {
+                metricDuplicationOther.increment();
+                if (decision.doTransform(merge, fixedCount)) {
+                    metricDuplicationOtherPerformed.increment();
+                    new DuplicationOperation(merge, replacements).duplicate();
+                }
+            }
+        }
+    }
+
+    /**
+     * This class encapsulates one tail duplication operation on a specific {@link MergeNode}.
+     */
+    private static class DuplicationOperation {
+
+        private final MergeNode merge;
+        private final StructuredGraph graph;
+
+        private final HashMap<ValueNode, PhiNode> bottomPhis = new HashMap<>();
+        private final List<PiNode> replacements;
+
+        /**
+         * Initializes the tail duplication operation without actually performing any work.
+         *
+         * @param merge The merge whose tail should be duplicated.
+         * @param replacements A list of replacement {@link PiNode}s, or null. If this is non-null, then the size of the
+         *            list needs to match the number of end nodes at the merge.
+         */
+        public DuplicationOperation(MergeNode merge, List<PiNode> replacements) {
+            this.merge = merge;
+            this.replacements = replacements;
+            this.graph = (StructuredGraph) merge.graph();
+        }
+
+        /**
+         * Performs the actual tail duplication:
+         * <ul>
+         * <li>Creates a new {@link ValueAnchorNode} at the beginning of the duplicated area, an transfers all
+         * dependencies from the merge to this anchor.</li>
+         * <li>Determines the set of fixed nodes to be duplicated.</li>
+         * <li>Creates the new merge at the bottom of the duplicated area.</li>
+         * <li>Determines the complete set of duplicated nodes.</li>
+         * <li>Performs the actual duplication.</li>
+         * </ul>
+         */
+        private void duplicate() {
+            Debug.log("tail duplication at merge %s in %s (prob %f)", merge, graph.method(), merge.probability());
+
+            ValueAnchorNode anchor = addValueAnchor();
+
+            // determine the fixed nodes that should be duplicated (currently: all nodes up until the first control
+            // split, end node, deopt or return.
+            ArrayList<FixedNode> fixedNodes = new ArrayList<>();
+            FixedNode fixed = merge.next();
+            FrameState stateAfter = merge.stateAfter();
+            while (fixed instanceof FixedWithNextNode) {
+                fixedNodes.add(fixed);
+                if (fixed instanceof StateSplit && ((StateSplit) fixed).stateAfter() != null) {
+                    stateAfter = ((StateSplit) fixed).stateAfter();
+                }
+                fixed = ((FixedWithNextNode) fixed).next();
+            }
+
+            EndNode endAfter = createNewMerge(fixed, stateAfter);
+            MergeNode mergeAfter = endAfter.merge();
+            fixedNodes.add(endAfter);
+            final HashSet<Node> duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter);
+            mergeAfter.clearEnds();
+            expandDuplicated(duplicatedNodes, mergeAfter);
+            retargetDependencies(duplicatedNodes, anchor);
+
+            List<EndNode> endSnapshot = merge.forwardEnds().snapshot();
+            List<PhiNode> phiSnapshot = merge.phis().snapshot();
+
+            int endIndex = 0;
+            for (final EndNode forwardEnd : merge.forwardEnds()) {
+                Map<Node, Node> duplicates;
+                if (replacements == null || replacements.get(endIndex) == null) {
+                    duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null);
+                } else {
+                    HashMap<Node, Node> replace = new HashMap<>();
+                    replace.put(replacements.get(endIndex).object(), replacements.get(endIndex));
+                    duplicates = graph.addDuplicates(duplicatedNodes, replace);
+                }
+                for (Map.Entry<ValueNode, PhiNode> phi : bottomPhis.entrySet()) {
+                    phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey()));
+                }
+                mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter));
+
+                // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding EndNode
+                FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor);
+                ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate);
+                // move dependencies on the ValueAnchorNode to the previous BeginNode
+                BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate);
+                anchorDuplicate.replaceAtUsages(prevBegin);
+
+                // re-wire the phi duplicates to the correct input
+                for (PhiNode phi : phiSnapshot) {
+                    PhiNode phiDuplicate = (PhiNode) duplicates.get(phi);
+                    for (Node usage : phiDuplicate.usages()) {
+                        if (usage instanceof ValueNode) {
+                            ((ValueNode) usage).dependencies().add(prevBegin);
+                        }
+                    }
+                    phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd));
+                    phiDuplicate.safeDelete();
+                }
+                endIndex++;
+            }
+            GraphUtil.killCFG(merge);
+            for (EndNode forwardEnd : endSnapshot) {
+                forwardEnd.safeDelete();
+            }
+            for (PhiNode phi : phiSnapshot) {
+                // these phis should go away, but they still need to be anchored to a merge to be valid...
+                if (phi.isAlive()) {
+                    phi.setMerge(mergeAfter);
+                }
+            }
+            Debug.dump(graph, "After tail duplication at %s", merge);
+        }
+
+        /**
+         * Inserts a new ValueAnchorNode after the merge and transfers all dependency-usages (not phis) to this
+         * ValueAnchorNode.
+         *
+         * @return The new {@link ValueAnchorNode} that was created.
+         */
+        private ValueAnchorNode addValueAnchor() {
+            ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
+            graph.addAfterFixed(merge, anchor);
+            for (Node usage : merge.usages().snapshot()) {
+                if (usage instanceof PhiNode && ((PhiNode) usage).merge() == merge) {
+                    // nothing to do
+                } else {
+                    usage.replaceFirstInput(merge, anchor);
+                }
+            }
+            return anchor;
+        }
+
+        /**
+         * Given a set of fixed nodes, this method determines the set of fixed and floating nodes that needs to be
+         * duplicated, i.e., all nodes that due to data flow and other dependencies needs to be duplicated.
+         *
+         * @param fixedNodes The set of fixed nodes that should be duplicated.
+         * @param stateAfter The frame state of the merge that follows the set of fixed nodes. All {@link ValueNode}s
+         *            reachable from this state are considered to be reachable from within the duplicated set of nodes.
+         * @return The set of nodes that need to be duplicated.
+         */
+        private HashSet<Node> buildDuplicatedNodeSet(final ArrayList<FixedNode> fixedNodes, FrameState stateAfter) {
+            final NodeBitMap aboveBound = graph.createNodeBitMap();
+            final NodeBitMap belowBound = graph.createNodeBitMap();
+
+            final Deque<Node> worklist = new ArrayDeque<>();
+
+            // Build the set of nodes that have (transitive) usages within the duplicatedNodes.
+            // This is achieved by iterating all nodes that are reachable via inputs from the the fixed nodes.
+            aboveBound.markAll(fixedNodes);
+            worklist.addAll(fixedNodes);
+
+            // the phis at the original merge should always be duplicated
+            for (PhiNode phi : merge.phis()) {
+                aboveBound.mark(phi);
+                worklist.add(phi);
+            }
+
+            NodeClosure<Node> aboveClosure = new NodeClosure<Node>() {
+
+                @Override
+                public void apply(Node usage, Node node) {
+                    if (node instanceof PhiNode && !fixedNodes.contains(((PhiNode) node).merge())) {
+                        // stop iterating: phis belonging to outside merges are known to be outside.
+                    } else if (node instanceof FixedNode) {
+                        // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other
+                        // fixed nodes are known to be outside.
+                    } else if (!aboveBound.isMarked(node)) {
+                        worklist.add(node);
+                        aboveBound.mark(node);
+                    }
+                }
+            };
+
+            if (stateAfter != null) {
+                stateAfter.applyToNonVirtual(aboveClosure);
+            }
+            while (!worklist.isEmpty()) {
+                Node current = worklist.remove();
+                for (Node input : current.inputs()) {
+                    aboveClosure.apply(current, input);
+                }
+            }
+
+            // Build the set of nodes that have (transitive) inputs within the duplicatedNodes.
+            // This is achieved by iterating all nodes that are reachable via usages from the fixed nodes.
+            belowBound.markAll(fixedNodes);
+            worklist.addAll(fixedNodes);
+
+            // the phis at the original merge should always be duplicated
+            for (PhiNode phi : merge.phis()) {
+                belowBound.mark(phi);
+                worklist.add(phi);
+            }
+
+            while (!worklist.isEmpty()) {
+                Node current = worklist.remove();
+                for (Node usage : current.usages()) {
+                    if (usage instanceof PhiNode && !fixedNodes.contains(((PhiNode) usage).merge())) {
+                        // stop iterating: phis belonging to outside merges are known to be outside.
+                    } else if (usage instanceof FixedNode) {
+                        // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other
+                        // fixed nodes are known to be outside.
+                    } else if (!belowBound.isMarked(usage)) {
+                        worklist.add(usage);
+                        belowBound.mark(usage);
+                    }
+                }
+            }
+
+            // build the intersection
+            belowBound.intersect(aboveBound);
+            HashSet<Node> result = new HashSet<>();
+            for (Node node : belowBound) {
+                result.add(node);
+            }
+            return result;
+        }
+
+        /**
+         * Creates a new merge and end node construct at the end of the duplicated area. While it is useless in itself
+         * (merge with only one end) it simplifies the later duplication step.
+         *
+         * @param successor The successor of the duplicated set of nodes, i.e., the first node that should not be
+         *            duplicated.
+         * @param stateAfterMerge The frame state that should be used for the merge.
+         * @return The newly created end node.
+         */
+        private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
+            MergeNode newBottomMerge = graph.add(new MergeNode());
+            newBottomMerge.setProbability(successor.probability());
+            EndNode newBottomEnd = graph.add(new EndNode());
+            newBottomMerge.addForwardEnd(newBottomEnd);
+            newBottomMerge.setStateAfter(stateAfterMerge);
+            ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd);
+            newBottomMerge.setNext(successor);
+            return newBottomEnd;
+        }
+
+        /**
+         * Expands the set of nodes to be duplicated by looking at a number of conditions:
+         * <ul>
+         * <li>{@link ValueNode}s that have usages on the outside need to be replaced with phis for the outside usages.</li>
+         * <li>Non-{@link ValueNode} nodes that have outside usages (frame states, virtual object states, ...) need to
+         * be cloned immediately for the outside usages.</li>
+         * <li>Nodes that have a {@link StampFactory#extension()} or {@link StampFactory#condition()} stamp need to be
+         * cloned immediately for the outside usages.</li>
+         * <li>Dependencies into the duplicated nodes will be replaced with dependencies on the merge.</li>
+         * <li>Outside non-{@link ValueNode}s with usages within the duplicated set of nodes need to also be duplicated.
+         * </li>
+         * <li>Outside {@link ValueNode}s with {@link StampFactory#extension()} or {@link StampFactory#condition()}
+         * stamps that have usages within the duplicated set of nodes need to also be duplicated.</li>
+         * </ul>
+         *
+         * @param duplicatedNodes The set of duplicated nodes that will be modified (expanded).
+         * @param newBottomMerge The merge that follows the duplicated set of nodes. It will be used for newly created
+         *            phis and to as a target for dependencies that pointed into the duplicated set of nodes.
+         */
+        private void expandDuplicated(HashSet<Node> duplicatedNodes, MergeNode newBottomMerge) {
+            Deque<Node> worklist = new ArrayDeque<>(duplicatedNodes);
+
+            while (!worklist.isEmpty()) {
+                Node duplicated = worklist.remove();
+                if (hasUsagesOutside(duplicated, duplicatedNodes)) {
+                    boolean cloneForOutsideUsages = false;
+                    if (duplicated instanceof ValueNode) {
+                        ValueNode node = (ValueNode) duplicated;
+                        if (node.stamp() == StampFactory.dependency()) {
+                            // re-route dependencies to the merge
+                            replaceUsagesOutside(node, newBottomMerge, duplicatedNodes);
+                            // TODO(ls) maybe introduce phis for dependencies
+                        } else if (node.stamp() == StampFactory.extension() || node.stamp() == StampFactory.condition()) {
+                            cloneForOutsideUsages = true;
+                        } else {
+                            // introduce a new phi
+                            PhiNode newPhi = bottomPhis.get(node);
+                            if (newPhi == null) {
+                                newPhi = graph.add(new PhiNode(node.kind(), newBottomMerge));
+                                bottomPhis.put(node, newPhi);
+                                newPhi.addInput(node);
+                            }
+                            replaceUsagesOutside(node, newPhi, duplicatedNodes);
+                        }
+                    } else {
+                        cloneForOutsideUsages = true;
+                    }
+                    if (cloneForOutsideUsages) {
+                        // clone the offending node to the outside
+                        Node newOutsideClone = duplicated.copyWithInputs();
+                        replaceUsagesOutside(duplicated, newOutsideClone, duplicatedNodes);
+                        // this might cause other nodes to have outside usages, we need to look at those as well
+                        for (Node input : newOutsideClone.inputs()) {
+                            if (duplicatedNodes.contains(input)) {
+                                worklist.add(input);
+                            }
+                        }
+                    }
+                }
+                // check if this node has an input that lies outside and cannot be shared
+                for (Node input : duplicated.inputs()) {
+                    if (!duplicatedNodes.contains(input)) {
+                        boolean duplicateInput = false;
+                        if (input instanceof VirtualState) {
+                            duplicateInput = true;
+                        } else if (input instanceof ValueNode) {
+                            Stamp inputStamp = ((ValueNode) input).stamp();
+                            if (inputStamp == StampFactory.extension() || inputStamp == StampFactory.condition()) {
+                                duplicateInput = true;
+                            }
+                        }
+                        if (duplicateInput) {
+                            duplicatedNodes.add(input);
+                            worklist.add(input);
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Moves all depdendencies that point outside the duplicated area to the supplied value anchor node.
+         *
+         * @param duplicatedNodes The set of duplicated nodes.
+         * @param anchor The node that will be the new target for all dependencies that point outside the duplicated set of nodes.
+         */
+        private static void retargetDependencies(HashSet<Node> duplicatedNodes, ValueAnchorNode anchor) {
+            for (Node node : duplicatedNodes) {
+                if (node instanceof ValueNode) {
+                    NodeInputList<ValueNode> dependencies = ((ValueNode) node).dependencies();
+                    for (int i = 0; i < dependencies.size(); i++) {
+                        Node dependency = dependencies.get(i);
+                        if (dependency != null && !duplicatedNodes.contains(dependency)) {
+                            Debug.log("retargeting dependency %s to %s on %s", dependency, anchor, node);
+                            dependencies.set(i, anchor);
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks if the given node has usages that are not within the given set of nodes.
+         *
+         * @param node The node whose usages are checked.
+         * @param nodeSet The set of nodes that are considered to be "within".
+         * @return true if the given node has usages on the outside, false otherwise.
+         */
+        private static boolean hasUsagesOutside(Node node, HashSet<Node> nodeSet) {
+            for (Node usage : node.usages()) {
+                if (!nodeSet.contains(usage)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Replaces the given node with the given replacement at all usages that are not within the given set of nodes.
+         *
+         * @param node The node to be replaced at outside usages.
+         * @param replacement The node that replaced the given node at outside usages.
+         * @param nodeSet The set of nodes that are considered to be "within".
+         */
+        private static void replaceUsagesOutside(Node node, Node replacement, HashSet<Node> nodeSet) {
+            for (Node usage : node.usages().snapshot()) {
+                if (!nodeSet.contains(usage)) {
+                    usage.replaceFirstInput(node, replacement);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/Phase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+
+public abstract class Phase {
+
+    private String name;
+    private static final DebugMetric metricPhaseRuns = Debug.metric("Runs");
+    protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes");
+
+    protected Phase() {
+        this.name = this.getClass().getSimpleName();
+        if (name.endsWith("Phase")) {
+            name = name.substring(0, name.length() - "Phase".length());
+        }
+    }
+
+    protected Phase(String name) {
+        this.name = name;
+    }
+
+    protected String getDetailedName() {
+        return getName();
+    }
+
+    public final void apply(final StructuredGraph graph) {
+        apply(graph, true);
+    }
+
+    public final void apply(final StructuredGraph graph, final boolean dumpGraph) {
+        Debug.scope(name, this, new Runnable() {
+            public void run() {
+                Phase.this.run(graph);
+                metricPhaseRuns.increment();
+                if (dumpGraph) {
+                    Debug.dump(graph, "After phase %s", name);
+                }
+                assert graph.verify();
+            }
+        });
+    }
+
+    public final String getName() {
+        return name;
+    }
+
+    protected abstract void run(StructuredGraph graph);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhasePlan.java	Sun Oct 07 14:27:50 2012 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases;
+
+import java.util.*;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * Tells the compiler about additional phases that need to be executed during compilation.
+ */
+public class PhasePlan {
+    /**
+     * The compilation is split into the following sections:
+     * ========================================================================
+     * Period 1: High-level nodes. (Graph building)
+     * ========================================================================
+     * Runtime-specific lowering.
+     * ========================================================================
+     * Period 2: Mid-level nodes. (Memory dependence graph)
+     * ========================================================================
+     * Target-specific lowering, de-SSA.
+     * ========================================================================
+     * Period 3: Low-level nodes. (Register allocation, code generation)
+     * ========================================================================
+     *
+     * A compiler extension phase can chose to run at the end of periods 1-3.
+     */
+    public static enum PhasePosition {
+        AFTER_PARSING,
+        HIGH_LEVEL,
+        MID_LEVEL,
+        LOW_LEVEL
+    }
+
+    @SuppressWarnings("unchecked")
+    private final ArrayList<Phase>[] phases = new ArrayList[PhasePosition.values().length];
+    private final Set<Class<? extends Phase>> disabledPhases = new HashSet<>();
+
+    public void addPhase(PhasePosition pos, Phase phase) {
+        if (phases[pos.ordinal()] == null) {
+            phases[pos.ordinal()] = new ArrayList<>();
+        }
+        phases[pos.ordinal()].add(phase);
+    }
+
+    public void runPhases(PhasePosition pos, StructuredGraph graph) {
+        if (phases[pos.ordinal()] != null) {
+            for (Phase p : phases[pos.ordinal()]) {
+                p.apply(graph);
+            }
+        }
+    }
+
+    public void disablePhase(Class<? extends Phase> clazz) {
+        disabledPhases.add(clazz);
+    }
+
+    public boolean isPhaseDisabled(Class<? extends Phase> clazz) {
+        return disabledPhases.contains(clazz);
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/BoxingEliminationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-
-public class BoxingEliminationPhase extends Phase {
-
-    private int virtualIds = Integer.MIN_VALUE;
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.getNodes(UnboxNode.class).isNotEmpty()) {
-
-            Map<PhiNode, PhiNode> phiReplacements = new HashMap<>();
-            for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) {
-                tryEliminate(graph, unboxNode, phiReplacements);
-            }
-
-            new DeadCodeEliminationPhase().apply(graph);
-
-            for (BoxNode boxNode : graph.getNodes(BoxNode.class)) {
-                tryEliminate(boxNode);
-            }
-        }
-    }
-
-    private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map<PhiNode, PhiNode> phiReplacements) {
-        ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements);
-        if (unboxedValue != null) {
-            assert unboxedValue.kind() == unboxNode.kind();
-            unboxNode.replaceAtUsages(unboxedValue);
-            graph.removeFixed(unboxNode);
-        }
-    }
-
-    private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map<PhiNode, PhiNode> phiReplacements) {
-        if (!phiReplacements.containsKey(phiNode)) {
-            PhiNode result = null;
-            ObjectStamp stamp = phiNode.objectStamp();
-            if (stamp.nonNull() && stamp.isExactType()) {
-                ResolvedJavaType type = stamp.type();
-                if (type != null && type.toJava() == kind.toBoxedJavaClass()) {
-                    StructuredGraph graph = (StructuredGraph) phiNode.graph();
-                    result = graph.add(new PhiNode(kind, phiNode.merge()));
-                    phiReplacements.put(phiNode, result);
-                    virtualizeUsages(phiNode, result, type);
-                    int i = 0;
-                    for (ValueNode n : phiNode.values()) {
-                        ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements);
-                        if (unboxedValue != null) {
-                            assert unboxedValue.kind() == kind;
-                            result.addInput(unboxedValue);
-                        } else {
-                            UnboxNode unboxNode = graph.add(new UnboxNode(kind, n));
-                            FixedNode pred = phiNode.merge().phiPredecessorAt(i);
-                            graph.addBeforeFixed(pred, unboxNode);
-                            result.addInput(unboxNode);
-                        }
-                        ++i;
-                    }
-                }
-            }
-        }
-        return phiReplacements.get(phiNode);
-    }
-
-    private ValueNode unboxedValue(ValueNode n, Kind kind, Map<PhiNode, PhiNode> phiReplacements) {
-        if (n instanceof BoxNode) {
-            BoxNode boxNode = (BoxNode) n;
-            return boxNode.source();
-        } else if (n instanceof PhiNode) {
-            PhiNode phiNode = (PhiNode) n;
-            return getReplacementPhi(phiNode, kind, phiReplacements);
-        } else {
-            return null;
-        }
-    }
-
-    private void tryEliminate(BoxNode boxNode) {
-
-        assert boxNode.objectStamp().isExactType();
-        virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type());
-
-        if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) {
-            // Elimination failed, because boxing object escapes.
-            return;
-        }
-
-        FrameState stateAfter = boxNode.stateAfter();
-        boxNode.setStateAfter(null);
-        stateAfter.safeDelete();
-
-        ((StructuredGraph) boxNode.graph()).removeFixed(boxNode);
-    }
-
-    private void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) {
-        ValueNode virtualValueNode = null;
-        VirtualObjectNode virtualObjectNode = null;
-        for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) {
-            if (virtualValueNode == null) {
-                virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(virtualIds++, exactType, replacement));
-            }
-            n.replaceFirstInput(boxNode, virtualObjectNode);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/CanonicalizerPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,331 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-import java.util.concurrent.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.InputChangedListener;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-
-public class CanonicalizerPhase extends Phase {
-    private static final int MAX_ITERATION_PER_NODE = 10;
-    private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes");
-    private static final DebugMetric METRIC_CANONICALIZATION_CONSIDERED_NODES = Debug.metric("CanonicalizationConsideredNodes");
-    private static final DebugMetric METRIC_INFER_STAMP_CALLED = Debug.metric("InferStampCalled");
-    private static final DebugMetric METRIC_STAMP_CHANGED = Debug.metric("StampChanged");
-    private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes");
-    public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits");
-
-    private final int newNodesMark;
-    private final TargetDescription target;
-    private final Assumptions assumptions;
-    private final MetaAccessProvider runtime;
-    private final IsImmutablePredicate immutabilityPredicate;
-    private final Iterable<Node> initWorkingSet;
-
-    private NodeWorkList workList;
-    private Tool tool;
-    private List<Node> snapshotTemp;
-
-    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) {
-        this(target, runtime, assumptions, null, 0, null);
-    }
-
-    /**
-     * @param target
-     * @param runtime
-     * @param assumptions
-     * @param workingSet the initial working set of nodes on which the canonicalizer works, should be an auto-grow node bitmap
-     * @param immutabilityPredicate
-     */
-    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, IsImmutablePredicate immutabilityPredicate) {
-        this(target, runtime, assumptions, workingSet, 0, immutabilityPredicate);
-    }
-
-    /**
-     * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by
-     *            this mark are processed otherwise all nodes in the graph are processed
-     */
-    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, IsImmutablePredicate immutabilityPredicate) {
-        this(target, runtime, assumptions, null, newNodesMark, immutabilityPredicate);
-    }
-
-    private CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, int newNodesMark, IsImmutablePredicate immutabilityPredicate) {
-        this.newNodesMark = newNodesMark;
-        this.target = target;
-        this.assumptions = assumptions;
-        this.runtime = runtime;
-        this.immutabilityPredicate = immutabilityPredicate;
-        this.initWorkingSet = workingSet;
-        this.snapshotTemp = new ArrayList<>();
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (initWorkingSet == null) {
-            workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE);
-            if (newNodesMark > 0) {
-                workList.addAll(graph.getNewNodes(newNodesMark));
-            }
-        } else {
-            workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE);
-            workList.addAll(initWorkingSet);
-        }
-        tool = new Tool(workList, runtime, target, assumptions, immutabilityPredicate);
-        processWorkSet(graph);
-    }
-
-    public interface IsImmutablePredicate {
-        /**
-         * Determines if a given constant is an object/array whose current
-         * fields/elements will never change.
-         */
-        boolean apply(Constant constant);
-    }
-
-    private void processWorkSet(StructuredGraph graph) {
-        graph.trackInputChange(new InputChangedListener() {
-            @Override
-            public void inputChanged(Node node) {
-                workList.addAgain(node);
-            }
-        });
-
-        for (Node n : workList) {
-            processNode(n, graph);
-        }
-
-        graph.stopTrackingInputChange();
-    }
-
-    private void processNode(Node node, StructuredGraph graph) {
-        if (node.isAlive()) {
-            METRIC_PROCESSED_NODES.increment();
-
-            if (tryGlobalValueNumbering(node, graph)) {
-                return;
-            }
-            int mark = graph.getMark();
-            if (!tryKillUnused(node)) {
-                node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
-                if (!tryCanonicalize(node, graph, tool)) {
-                    tryInferStamp(node, graph);
-                } else {
-                    for (Node in : snapshotTemp) {
-                        if (in.isAlive() && in.usages().isEmpty()) {
-                            GraphUtil.killWithUnusedFloatingInputs(in);
-                        }
-                    }
-                }
-                snapshotTemp.clear();
-            }
-
-            for (Node newNode : graph.getNewNodes(mark)) {
-                workList.add(newNode);
-            }
-        }
-    }
-
-    private static boolean tryKillUnused(Node node) {
-        if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) {
-            GraphUtil.killWithUnusedFloatingInputs(node);
-            return true;
-        }
-        return false;
-    }
-
-    public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) {
-        if (node.getNodeClass().valueNumberable()) {
-            Node newNode = graph.findDuplicate(node);
-            if (newNode != null) {
-                assert !(node instanceof FixedNode || newNode instanceof FixedNode);
-                node.replaceAtUsages(newNode);
-                node.safeDelete();
-                METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment();
-                Debug.log("GVN applied and new node is %1s", newNode);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) {
-        if (node instanceof Canonicalizable) {
-            assert !(node instanceof Simplifiable);
-            METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
-            return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>(){
-                public Boolean call() {
-                    ValueNode canonical = ((Canonicalizable) node).canonical(tool);
-//     cases:                                           original node:
-//                                         |Floating|Fixed-unconnected|Fixed-connected|
-//                                         --------------------------------------------
-//                                     null|   1    |        X        |       3       |
-//                                         --------------------------------------------
-//                                 Floating|   2    |        X        |       4       |
-//       canonical node:                   --------------------------------------------
-//                        Fixed-unconnected|   X    |        X        |       5       |
-//                                         --------------------------------------------
-//                          Fixed-connected|   2    |        X        |       6       |
-//                                         --------------------------------------------
-//       X: must not happen (checked with assertions)
-                    if (canonical == node) {
-                        Debug.log("Canonicalizer: work on %s", node);
-                        return false;
-                    } else {
-                        Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
-                        METRIC_CANONICALIZED_NODES.increment();
-                        if (node instanceof FloatingNode) {
-                            if (canonical == null) {
-                                // case 1
-                                graph.removeFloating((FloatingNode) node);
-                            } else {
-                                // case 2
-                                assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode) : node + " -> " + canonical +
-                                                " : replacement should be floating or fixed and connected";
-                                graph.replaceFloating((FloatingNode) node, canonical);
-                            }
-                        } else {
-                            assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
-                            if (canonical == null) {
-                                // case 3
-                                graph.removeFixed((FixedWithNextNode) node);
-                            } else if (canonical instanceof FloatingNode) {
-                                // case 4
-                                graph.replaceFixedWithFloating((FixedWithNextNode) node, (FloatingNode) canonical);
-                            } else {
-                                assert canonical instanceof FixedNode;
-                                if (canonical.predecessor() == null) {
-                                    assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors";
-                                    // case 5
-                                    graph.replaceFixedWithFixed((FixedWithNextNode) node, (FixedWithNextNode) canonical);
-                                } else {
-                                    assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
-                                    // case 6
-                                    node.replaceAtUsages(canonical);
-                                    graph.removeFixed((FixedWithNextNode) node);
-                                }
-                            }
-                        }
-                        return true;
-                    }
-                }
-            });
-        } else if (node instanceof Simplifiable) {
-            Debug.log("Canonicalizer: simplifying %s", node);
-            METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
-            Debug.scope("SimplifyNode", node, new Runnable() {
-                public void run() {
-                    ((Simplifiable) node).simplify(tool);
-                }
-            });
-        }
-        return node.isDeleted();
-    }
-
-    /**
-     * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that the stamp has
-     * changed), re-queues the node's usages . If the stamp has changed then this method also checks if the stamp
-     * now describes a constant integer value, in which case the node is replaced with a constant.
-     */
-    private void tryInferStamp(Node node, StructuredGraph graph) {
-        if (node.isAlive() && node instanceof ValueNode) {
-            ValueNode valueNode = (ValueNode) node;
-            METRIC_INFER_STAMP_CALLED.increment();
-            if (valueNode.inferStamp()) {
-                METRIC_STAMP_CHANGED.increment();
-                if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) {
-                    ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph);
-                    Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement);
-                    valueNode.replaceAtUsages(replacement);
-                } else {
-                    for (Node usage : valueNode.usages()) {
-                        workList.addAgain(usage);
-                    }
-                }
-            }
-        }
-    }
-
-    private static final class Tool implements SimplifierTool {
-
-        private final NodeWorkList nodeWorkSet;
-        private final MetaAccessProvider runtime;
-        private final TargetDescription target;
-        private final Assumptions assumptions;
-        private final IsImmutablePredicate immutabilityPredicate;
-
-        public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, TargetDescription target, Assumptions assumptions, IsImmutablePredicate immutabilityPredicate) {
-            this.nodeWorkSet = nodeWorkSet;
-            this.runtime = runtime;
-            this.target = target;
-            this.assumptions = assumptions;
-            this.immutabilityPredicate = immutabilityPredicate;
-        }
-
-        @Override
-        public void deleteBranch(FixedNode branch) {
-            branch.predecessor().replaceFirstSuccessor(branch, null);
-            GraphUtil.killCFG(branch);
-        }
-
-        /**
-         * @return the current target or {@code null} if no target is available in the current context.
-         */
-        @Override
-        public TargetDescription target() {
-            return target;
-        }
-
-        /**
-         * @return an object that can be used for recording assumptions or {@code null} if assumptions are not allowed in the current context.
-         */
-        @Override
-        public Assumptions assumptions() {
-            return assumptions;
-        }
-
-        @Override
-        public MetaAccessProvider runtime() {
-            return runtime;
-        }
-
-        @Override
-        public void addToWorkList(Node node) {
-            nodeWorkSet.add(node);
-        }
-
-        @Override
-        public boolean isImmutable(Constant objectConstant) {
-            return immutabilityPredicate != null && immutabilityPredicate.apply(objectConstant);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/CheckCastEliminationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,383 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.graph.*;
-
-public class CheckCastEliminationPhase extends Phase {
-
-    private static final DebugMetric metricInstanceOfRegistered = Debug.metric("InstanceOfRegistered");
-    private static final DebugMetric metricNullCheckRegistered = Debug.metric("NullCheckRegistered");
-    private static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved");
-    private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved");
-    private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved");
-    private static final DebugMetric metricNullCheckGuardRemoved = Debug.metric("NullCheckGuardRemoved");
-    private static final DebugMetric metricGuardsReplaced = Debug.metric("GuardsReplaced");
-
-    private StructuredGraph graph;
-
-    @Override
-    protected void run(StructuredGraph inputGraph) {
-        graph = inputGraph;
-        new EliminateCheckCasts(graph.start(), new State()).apply();
-    }
-
-    public static class State implements MergeableState<State> {
-
-        private IdentityHashMap<ValueNode, ResolvedJavaType> knownTypes;
-        private HashSet<ValueNode> knownNotNull;
-        private HashSet<ValueNode> knownNull;
-        private IdentityHashMap<BooleanNode, ValueNode> trueConditions;
-        private IdentityHashMap<BooleanNode, ValueNode> falseConditions;
-
-        public State() {
-            this.knownTypes = new IdentityHashMap<>();
-            this.knownNotNull = new HashSet<>();
-            this.knownNull = new HashSet<>();
-            this.trueConditions = new IdentityHashMap<>();
-            this.falseConditions = new IdentityHashMap<>();
-        }
-
-        public State(State other) {
-            this.knownTypes = new IdentityHashMap<>(other.knownTypes);
-            this.knownNotNull = new HashSet<>(other.knownNotNull);
-            this.knownNull = new HashSet<>(other.knownNull);
-            this.trueConditions = new IdentityHashMap<>(other.trueConditions);
-            this.falseConditions = new IdentityHashMap<>(other.falseConditions);
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<State> withStates) {
-            IdentityHashMap<ValueNode, ResolvedJavaType> newKnownTypes = new IdentityHashMap<>();
-            HashSet<ValueNode> newKnownNotNull = new HashSet<>();
-            HashSet<ValueNode> newKnownNull = new HashSet<>();
-            IdentityHashMap<BooleanNode, ValueNode> newTrueConditions = new IdentityHashMap<>();
-            IdentityHashMap<BooleanNode, ValueNode> newFalseConditions = new IdentityHashMap<>();
-
-            for (Map.Entry<ValueNode, ResolvedJavaType> entry : knownTypes.entrySet()) {
-                ValueNode node = entry.getKey();
-                ResolvedJavaType type = entry.getValue();
-
-                for (State other : withStates) {
-                    ResolvedJavaType otherType = other.getNodeType(node);
-                    type = widen(type, otherType);
-                    if (type == null) {
-                        break;
-                    }
-                }
-                if (type == null && type != node.objectStamp().type()) {
-                    newKnownTypes.put(node, type);
-                }
-            }
-            for (ValueNode node : knownNotNull) {
-                boolean notNull = true;
-                for (State other : withStates) {
-                    if (!other.knownNotNull.contains(node)) {
-                        notNull = false;
-                        break;
-                    }
-                }
-                if (notNull) {
-                    newKnownNotNull.add(node);
-                }
-            }
-            for (ValueNode node : knownNull) {
-                boolean nul = true;
-                for (State other : withStates) {
-                    if (!other.knownNull.contains(node)) {
-                        nul = false;
-                        break;
-                    }
-                }
-                if (nul) {
-                    newKnownNull.add(node);
-                }
-            }
-            for (Map.Entry<BooleanNode, ValueNode> entry : trueConditions.entrySet()) {
-                BooleanNode check = entry.getKey();
-                ValueNode guard = entry.getValue();
-
-                for (State other : withStates) {
-                    ValueNode otherGuard = other.trueConditions.get(check);
-                    if (otherGuard == null) {
-                        guard = null;
-                        break;
-                    }
-                    if (otherGuard != guard) {
-                        guard = merge;
-                    }
-                }
-                if (guard != null) {
-                    newTrueConditions.put(check, guard);
-                }
-            }
-            for (Map.Entry<BooleanNode, ValueNode> entry : falseConditions.entrySet()) {
-                BooleanNode check = entry.getKey();
-                ValueNode guard = entry.getValue();
-
-                for (State other : withStates) {
-                    ValueNode otherGuard = other.falseConditions.get(check);
-                    if (otherGuard == null) {
-                        guard = null;
-                        break;
-                    }
-                    if (otherGuard != guard) {
-                        guard = merge;
-                    }
-                }
-                if (guard != null) {
-                    newFalseConditions.put(check, guard);
-                }
-            }
-
-            /*
-            // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values)
-            if (!(merge instanceof LoopBeginNode)) {
-                for (PhiNode phi : merge.phis()) {
-                    if (phi.type() == PhiType.Value && phi.kind() == Kind.Object) {
-                        ValueNode firstValue = phi.valueAt(0);
-                        ResolvedJavaType type = getNodeType(firstValue);
-                        boolean notNull = knownNotNull.contains(firstValue);
-                        boolean nul = knownNull.contains(firstValue);
-
-                        for (int i = 0; i < withStates.size(); i++) {
-                            State otherState = withStates.get(i);
-                            ValueNode value = phi.valueAt(i + 1);
-                            ResolvedJavaType otherType = otherState.getNodeType(value);
-                            type = widen(type, otherType);
-                            notNull &= otherState.knownNotNull.contains(value);
-                            nul &= otherState.knownNull.contains(value);
-                        }
-                        if (type == null && type != phi.declaredType()) {
-                            newKnownTypes.put(phi, type);
-                        }
-                        if (notNull) {
-                            newKnownNotNull.add(phi);
-                        }
-                        if (nul) {
-                            newKnownNull.add(phi);
-                        }
-                    }
-                }
-            }
-            */
-            this.knownTypes = newKnownTypes;
-            this.knownNotNull = newKnownNotNull;
-            this.knownNull = newKnownNull;
-            this.trueConditions = newTrueConditions;
-            this.falseConditions = newFalseConditions;
-            return true;
-        }
-
-        public ResolvedJavaType getNodeType(ValueNode node) {
-            ResolvedJavaType result = knownTypes.get(node);
-            return result == null ? node.objectStamp().type() : result;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) {
-        }
-
-        @Override
-        public void afterSplit(FixedNode node) {
-        }
-
-        @Override
-        public State clone() {
-            return new State(this);
-        }
-    }
-
-    public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) {
-        if (a == null || b == null) {
-            return null;
-        } else if (a == b) {
-            return a;
-        } else {
-            return a.leastCommonAncestor(b);
-        }
-    }
-
-    public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) {
-        if (a == null) {
-            return b;
-        } else if (b == null) {
-            return a;
-        } else if (a == b) {
-            return a;
-        } else if (a.isSubtypeOf(b)) {
-            return a;
-        } else if (b.isSubtypeOf(a)) {
-            return b;
-        } else {
-            return a;
-        }
-    }
-
-    public class EliminateCheckCasts extends PostOrderNodeIterator<State> {
-        private BeginNode lastBegin = null;
-
-        public EliminateCheckCasts(FixedNode start, State initialState) {
-            super(start, initialState);
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            if (node instanceof BeginNode) {
-                BeginNode begin = (BeginNode) node;
-                lastBegin = begin;
-                Node pred = node.predecessor();
-                if (pred != null && pred instanceof IfNode) {
-                    IfNode ifNode = (IfNode) pred;
-                    if (!(ifNode.compare() instanceof ConstantNode)) {
-                        boolean isTrue = (node == ifNode.trueSuccessor());
-                        if (isTrue) {
-                            state.trueConditions.put(ifNode.compare(), begin);
-                        } else {
-                            state.falseConditions.put(ifNode.compare(), begin);
-                        }
-                    }
-                    if (ifNode.compare() instanceof InstanceOfNode) {
-                        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare();
-                        if ((node == ifNode.trueSuccessor())) {
-                            ValueNode object = instanceOf.object();
-                            state.knownNotNull.add(object);
-                            state.knownTypes.put(object, tighten(instanceOf.targetClass(), state.getNodeType(object)));
-                            metricInstanceOfRegistered.increment();
-                        }
-                    } else if (ifNode.compare() instanceof IsNullNode) {
-                        IsNullNode nullCheck = (IsNullNode) ifNode.compare();
-                        boolean isNull = (node == ifNode.trueSuccessor());
-                        if (isNull) {
-                            state.knownNull.add(nullCheck.object());
-                        } else {
-                            state.knownNotNull.add(nullCheck.object());
-                        }
-                        metricNullCheckRegistered.increment();
-                    }
-                }
-                for (GuardNode guard : begin.guards().snapshot()) {
-                    BooleanNode condition = guard.condition();
-                    ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition);
-                    if (existingGuards != null) {
-                        guard.replaceAtUsages(existingGuards);
-                        GraphUtil.killWithUnusedFloatingInputs(guard);
-                        metricGuardsReplaced.increment();
-                    } else {
-                        boolean removeCheck = false;
-                        if (condition instanceof IsNullNode) {
-                            IsNullNode isNull = (IsNullNode) condition;
-                            if (guard.negated() && state.knownNotNull.contains(isNull.object())) {
-                                removeCheck = true;
-                            } else if (!guard.negated() && state.knownNull.contains(isNull.object())) {
-                                removeCheck = true;
-                            }
-                            if (removeCheck) {
-                                metricNullCheckGuardRemoved.increment();
-                            }
-                        }
-                        if (removeCheck) {
-                            guard.replaceAtUsages(begin);
-                            GraphUtil.killWithUnusedFloatingInputs(guard);
-                        } else {
-                            if (guard.negated()) {
-                                state.falseConditions.put(condition, guard);
-                            } else {
-                                state.trueConditions.put(condition, guard);
-                            }
-                        }
-                    }
-                }
-            } else if (node instanceof CheckCastNode) {
-                CheckCastNode checkCast = (CheckCastNode) node;
-                ResolvedJavaType type = state.getNodeType(checkCast.object());
-                if (checkCast.targetClass() != null && type != null && type.isSubtypeOf(checkCast.targetClass())) {
-                    PiNode piNode;
-                    boolean nonNull = state.knownNotNull.contains(checkCast.object());
-                    piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, nonNull ? StampFactory.declaredNonNull(type) : StampFactory.declared(type)));
-                    checkCast.replaceAtUsages(piNode);
-                    graph.removeFixed(checkCast);
-                    metricCheckCastRemoved.increment();
-                }
-            } else if (node instanceof IfNode) {
-                IfNode ifNode = (IfNode) node;
-                BooleanNode replaceWith = null;
-                BooleanNode compare = ifNode.compare();
-
-                if (state.trueConditions.containsKey(compare)) {
-                    replaceWith = ConstantNode.forBoolean(true, graph);
-                } else if (state.falseConditions.containsKey(compare)) {
-                    replaceWith = ConstantNode.forBoolean(false, graph);
-                } else {
-                    if (compare instanceof InstanceOfNode) {
-                        InstanceOfNode instanceOf = (InstanceOfNode) compare;
-                        ValueNode object = instanceOf.object();
-                        if (state.knownNull.contains(object)) {
-                            replaceWith = ConstantNode.forBoolean(false, graph);
-                        } else if (state.knownNotNull.contains(object)) {
-                            ResolvedJavaType type = state.getNodeType(object);
-                            if (type != null && type.isSubtypeOf(instanceOf.targetClass())) {
-                                replaceWith = ConstantNode.forBoolean(true, graph);
-                            }
-                        }
-                        if (replaceWith != null) {
-                            metricInstanceOfRemoved.increment();
-                        }
-                    } else if (compare instanceof IsNullNode) {
-                        IsNullNode isNull = (IsNullNode) compare;
-                        ValueNode object = isNull.object();
-                        if (state.knownNull.contains(object)) {
-                            replaceWith = ConstantNode.forBoolean(true, graph);
-                        } else if (state.knownNotNull.contains(object)) {
-                            replaceWith = ConstantNode.forBoolean(false, graph);
-                        }
-                        if (replaceWith != null) {
-                            metricNullCheckRemoved.increment();
-                        }
-                    }
-                }
-                if (replaceWith != null) {
-                    ifNode.setCompare(replaceWith);
-                    if (compare.usages().isEmpty()) {
-                        GraphUtil.killWithUnusedFloatingInputs(compare);
-                    }
-                }
-            }
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ComputeProbabilityPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,372 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.cfg.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-
-public class ComputeProbabilityPhase extends Phase {
-    private static final double EPSILON = 1d / Integer.MAX_VALUE;
-
-    /*
-     * The computation of absolute probabilities works in three steps:
-     *
-     * - The first step, "PropagateProbability", traverses the graph in post order (merges after their ends, ...) and keeps track of the "probability state".
-     *   Whenever it encounters a ControlSplit it uses the split's probability information to divide the probability upon the successors.
-     *   Whenever it encounters an Invoke it assumes that the exception edge is unlikely and propagates the whole probability to the normal successor.
-     *   Whenever it encounters a Merge it sums up the probability of all predecessors.
-     *   It also maintains a set of active loops (whose LoopBegin has been visited) and builds def/use information for the second step.
-     *
-     * - The third step propagates the loop frequencies and multiplies each FixedNode's probability with its loop frequency.
-     *
-     *   TODO: add exception probability information to Invokes
-     */
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        new PropagateProbability(graph.start()).apply();
-        Debug.dump(graph, "After PropagateProbability");
-        computeLoopFactors();
-        Debug.dump(graph, "After computeLoopFactors");
-        new PropagateLoopFrequency(graph.start()).apply();
-
-        if (GraalOptions.LoopFrequencyPropagationPolicy < 0) {
-            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
-            BitSet visitedBlocks = new BitSet(cfg.getBlocks().length);
-            for (Loop loop : cfg.getLoops()) {
-                if (loop.parent == null) {
-                    correctLoopFrequencies(loop, 1, visitedBlocks);
-                }
-            }
-        }
-    }
-
-    private void correctLoopFrequencies(Loop loop, double parentFrequency, BitSet visitedBlocks) {
-        LoopBeginNode loopBegin = ((LoopBeginNode) loop.header.getBeginNode());
-        double frequency = parentFrequency * loopBegin.loopFrequency();
-        for (Loop child : loop.children) {
-            correctLoopFrequencies(child, frequency, visitedBlocks);
-        }
-
-        double factor = getCorrectionFactor(loopBegin.probability(), frequency);
-        for (Block block : loop.blocks) {
-            int blockId = block.getId();
-            if (!visitedBlocks.get(blockId)) {
-                visitedBlocks.set(blockId);
-
-                FixedNode node = block.getBeginNode();
-                while (node != block.getEndNode()) {
-                    node.setProbability(node.probability() * factor);
-                    node = ((FixedWithNextNode) node).next();
-                }
-                node.setProbability(node.probability() * factor);
-            }
-        }
-    }
-
-    private static double getCorrectionFactor(double probability, double frequency) {
-        switch (GraalOptions.LoopFrequencyPropagationPolicy) {
-            case -1:
-                return 1 / frequency;
-            case -2:
-                return (1 / frequency) * (Math.log(Math.E + frequency) - 1);
-            case -3:
-                double originalProbability = probability / frequency;
-                assert isRelativeProbability(originalProbability);
-                return (1 / frequency) * Math.max(1, Math.pow(originalProbability, 1.5) * Math.log10(frequency));
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    private void computeLoopFactors() {
-        for (LoopInfo info : loopInfos) {
-            double frequency = info.loopFrequency();
-            assert frequency != -1;
-        }
-    }
-
-    private static boolean isRelativeProbability(double prob) {
-        // 1.01 to allow for some rounding errors
-        return prob >= 0 && prob <= 1.01;
-    }
-
-    public static class LoopInfo {
-        public final LoopBeginNode loopBegin;
-
-        public final NodeMap<Set<LoopInfo>> requires;
-
-        private double loopFrequency = -1;
-        public boolean ended = false;
-
-        public LoopInfo(LoopBeginNode loopBegin) {
-            this.loopBegin = loopBegin;
-            this.requires = loopBegin.graph().createNodeMap();
-        }
-
-        public double loopFrequency() {
-            if (loopFrequency == -1 && ended) {
-                double backEdgeProb = 0.0;
-                for (LoopEndNode le : loopBegin.loopEnds()) {
-                    double factor = 1;
-                    Set<LoopInfo> requireds = requires.get(le);
-                    for (LoopInfo required : requireds) {
-                        double t = required.loopFrequency();
-                        if (t == -1) {
-                            return -1;
-                        }
-                        factor *= t;
-                    }
-                    backEdgeProb += le.probability() * factor;
-                }
-                double d = loopBegin.probability() - backEdgeProb;
-                if (d < EPSILON) {
-                    d = EPSILON;
-                }
-                loopFrequency = loopBegin.probability() / d;
-                loopBegin.setLoopFrequency(loopFrequency);
-            }
-            return loopFrequency;
-        }
-    }
-
-    public Set<LoopInfo> loopInfos = new HashSet<>();
-    public Map<MergeNode, Set<LoopInfo>> mergeLoops = new IdentityHashMap<>();
-
-    private class Probability implements MergeableState<Probability> {
-        public double probability;
-        public HashSet<LoopInfo> loops;
-        public LoopInfo loopInfo;
-
-        public Probability(double probability, HashSet<LoopInfo> loops) {
-            this.probability = probability;
-            this.loops = new HashSet<>(4);
-            if (loops != null) {
-                this.loops.addAll(loops);
-            }
-        }
-
-        @Override
-        public Probability clone() {
-            return new Probability(probability, loops);
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<Probability> withStates) {
-            if (merge.forwardEndCount() > 1) {
-                HashSet<LoopInfo> intersection = new HashSet<>(loops);
-                for (Probability other : withStates) {
-                    intersection.retainAll(other.loops);
-                }
-                for (LoopInfo info : loops) {
-                    if (!intersection.contains(info)) {
-                        double loopFrequency = info.loopFrequency();
-                        if (loopFrequency == -1) {
-                            return false;
-                        }
-                        probability *= loopFrequency;
-                    }
-                }
-                for (Probability other : withStates) {
-                    double prob = other.probability;
-                    for (LoopInfo info : other.loops) {
-                        if (!intersection.contains(info)) {
-                            double loopFrequency = info.loopFrequency();
-                            if (loopFrequency == -1) {
-                                return false;
-                            }
-                            prob *= loopFrequency;
-                        }
-                    }
-                    probability += prob;
-                }
-                loops = intersection;
-                mergeLoops.put(merge, new HashSet<>(intersection));
-                assert isRelativeProbability(probability) : probability;
-            }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            loopInfo = new LoopInfo(loopBegin);
-            loopInfos.add(loopInfo);
-            loops.add(loopInfo);
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<Probability> loopEndStates) {
-            assert loopInfo != null;
-            List<LoopEndNode> loopEnds = loopBegin.orderedLoopEnds();
-            int i = 0;
-            for (Probability proba : loopEndStates) {
-                LoopEndNode loopEnd = loopEnds.get(i++);
-                Set<LoopInfo> requires = loopInfo.requires.get(loopEnd);
-                if (requires == null) {
-                    requires = new HashSet<>();
-                    loopInfo.requires.set(loopEnd, requires);
-                }
-                for (LoopInfo innerLoop : proba.loops) {
-                    if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) {
-                        requires.add(innerLoop);
-                    }
-                }
-            }
-            loopInfo.ended = true;
-        }
-
-        @Override
-        public void afterSplit(FixedNode node) {
-            assert node.predecessor() != null;
-            Node pred = node.predecessor();
-            if (pred instanceof Invoke) {
-                Invoke x = (Invoke) pred;
-                if (x.next() != node) {
-                    probability = 0;
-                }
-            } else {
-                assert pred instanceof ControlSplitNode;
-                ControlSplitNode x = (ControlSplitNode) pred;
-                double sum = 0;
-                for (int i = 0; i < x.blockSuccessorCount(); i++) {
-                    if (x.blockSuccessor(i) == node) {
-                        sum += x.probability(i);
-                    }
-                }
-                probability *= sum;
-            }
-        }
-    }
-
-    private class PropagateProbability extends PostOrderNodeIterator<Probability> {
-
-        public PropagateProbability(FixedNode start) {
-            super(start, new Probability(1d, null));
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            node.setProbability(state.probability);
-        }
-    }
-
-    private class LoopCount implements MergeableState<LoopCount> {
-        public double count;
-
-        public LoopCount(double count) {
-            this.count = count;
-        }
-
-        @Override
-        public LoopCount clone() {
-            return new LoopCount(count);
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<LoopCount> withStates) {
-            assert merge.forwardEndCount() == withStates.size() + 1;
-            if (merge.forwardEndCount() > 1) {
-                Set<LoopInfo> loops = mergeLoops.get(merge);
-                assert loops != null;
-                double countProd = 1;
-                for (LoopInfo loop : loops) {
-                    countProd *= loop.loopFrequency();
-                }
-                count = countProd;
-            }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            count *= loopBegin.loopFrequency();
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<LoopCount> loopEndStates) {
-            // nothing to do...
-        }
-
-        @Override
-        public void afterSplit(FixedNode node) {
-            // nothing to do...
-        }
-    }
-
-    private class PropagateLoopFrequency extends PostOrderNodeIterator<LoopCount> {
-
-        private final FrequencyPropagationPolicy policy;
-
-        public PropagateLoopFrequency(FixedNode start) {
-            super(start, new LoopCount(1d));
-            this.policy = createFrequencyPropagationPolicy();
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            node.setProbability(policy.compute(node.probability(), state.count));
-        }
-
-    }
-
-    private static FrequencyPropagationPolicy createFrequencyPropagationPolicy() {
-        switch (GraalOptions.LoopFrequencyPropagationPolicy) {
-            case -3:
-            case -2:
-            case -1:
-            case 0:
-                return new FullFrequencyPropagation();
-            case 1:
-                return new NoFrequencyPropagation();
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    private interface FrequencyPropagationPolicy {
-
-        double compute(double probability, double frequency);
-    }
-
-    private static class FullFrequencyPropagation implements FrequencyPropagationPolicy {
-
-        @Override
-        public double compute(double probability, double frequency) {
-            return probability * frequency;
-        }
-    }
-
-    private static class NoFrequencyPropagation implements FrequencyPropagationPolicy {
-
-        @Override
-        public double compute(double probability, double frequency) {
-            return probability;
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ConvertDeoptimizeToGuardPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-
-public class ConvertDeoptimizeToGuardPhase extends Phase {
-
-    private static BeginNode findBeginNode(Node startNode) {
-        Node n = startNode;
-        while (true) {
-            if (n instanceof BeginNode) {
-                return (BeginNode) n;
-            } else {
-                n = n.predecessor();
-            }
-        }
-    }
-
-    @Override
-    protected void run(final StructuredGraph graph) {
-        if (graph.getNodes(DeoptimizeNode.class).isEmpty()) {
-            return;
-        }
-
-        for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) {
-            visitDeoptBegin(findBeginNode(d), d, graph);
-        }
-
-        new DeadCodeEliminationPhase().apply(graph);
-    }
-
-    private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) {
-        if (deoptBegin instanceof MergeNode) {
-            MergeNode mergeNode = (MergeNode) deoptBegin;
-            Debug.log("Visiting %s followed by %s", mergeNode, deopt);
-            List<EndNode> ends = mergeNode.forwardEnds().snapshot();
-            for (EndNode end : ends) {
-                if (!end.isDeleted()) {
-                    BeginNode beginNode = findBeginNode(end);
-                    if (!(beginNode instanceof MergeNode)) {
-                        visitDeoptBegin(beginNode, deopt, graph);
-                    }
-                }
-            }
-            if (mergeNode.isDeleted()) {
-                if (!deopt.isDeleted()) {
-                    Debug.log("Merge deleted, deopt moved to %s", findBeginNode(deopt));
-                    visitDeoptBegin(findBeginNode(deopt), deopt, graph);
-                }
-            }
-        } else if (deoptBegin.predecessor() instanceof IfNode) {
-            IfNode ifNode = (IfNode) deoptBegin.predecessor();
-            BeginNode otherBegin = ifNode.trueSuccessor();
-            BooleanNode conditionNode = ifNode.compare();
-            boolean negated = false;
-            if (deoptBegin == ifNode.trueSuccessor()) {
-                negated = true;
-                otherBegin = ifNode.falseSuccessor();
-            }
-            BeginNode ifBlockBegin = findBeginNode(ifNode);
-            Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, ifBlockBegin);
-            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), negated, deopt.leafGraphId()));
-            otherBegin.replaceAtUsages(ifBlockBegin);
-            FixedNode next = otherBegin.next();
-            otherBegin.setNext(null);
-            guard.setNext(next);
-            ifNode.replaceAtPredecessor(guard);
-            GraphUtil.killCFG(ifNode);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ConvertUnreachedToGuardPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-
-
-public class ConvertUnreachedToGuardPhase extends Phase {
-    private OptimisticOptimizations opt;
-
-    public ConvertUnreachedToGuardPhase(OptimisticOptimizations opt) {
-        this.opt = opt;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (!opt.removeNeverExecutedCode()) {
-            return;
-        }
-        for (Node node : graph.getNodes()) {
-            if (node instanceof IfNode) {
-                IfNode ifNode = (IfNode) node;
-                BeginNode insertGuard = null;
-                BeginNode delete = null;
-                boolean inverted = false;
-                if (ifNode.probability(IfNode.TRUE_EDGE) == 0) {
-                    insertGuard = ifNode.falseSuccessor();
-                    delete = ifNode.trueSuccessor();
-                    inverted = true;
-                } else if (ifNode.probability(IfNode.FALSE_EDGE) == 0) {
-                    insertGuard = ifNode.trueSuccessor();
-                    delete = ifNode.falseSuccessor();
-                }
-                if (insertGuard != null) {
-                    GuardNode guard = graph.unique(new GuardNode(ifNode.compare(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, inverted, ifNode.leafGraphId()));
-                    graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard)));
-                    GraphUtil.killCFG(delete);
-                    graph.removeSplit(ifNode, inverted ? IfNode.FALSE_EDGE : IfNode.TRUE_EDGE);
-                }
-            }
-        }
-
-    }
-
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/CullFrameStatesPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.graph.*;
-
-/**
- * This phase culls unused FrameStates from the graph.
- * It does a post order iteration over the graph, and
- */
-public class CullFrameStatesPhase extends Phase {
-
-    private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled");
-    private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed");
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        new CullFrameStates(graph.start(), new State(null)).apply();
-    }
-
-    public static class State implements MergeableState<State> {
-
-        private FrameState lastFrameState;
-
-        public State(FrameState lastFrameState) {
-            this.lastFrameState = lastFrameState;
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<State> withStates) {
-            FrameState stateAfter = merge.stateAfter();
-            if (merge instanceof LoopBeginNode) {
-                if (stateAfter != null) {
-                    lastFrameState = stateAfter;
-                }
-                return true;
-            }
-            metricMergesTraversed.increment();
-            if (stateAfter != null) {
-                for (State other : withStates) {
-                    if (other.lastFrameState != lastFrameState) {
-                        lastFrameState = stateAfter;
-                        return true;
-                    }
-                }
-                metricFrameStatesCulled.increment();
-                merge.setStateAfter(null);
-                if (stateAfter.usages().isEmpty()) {
-                    GraphUtil.killWithUnusedFloatingInputs(stateAfter);
-                }
-            }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) {
-        }
-
-        @Override
-        public void afterSplit(FixedNode node) {
-        }
-
-        @Override
-        public State clone() {
-            return new State(lastFrameState);
-        }
-    }
-
-    public static class CullFrameStates extends PostOrderNodeIterator<State> {
-
-        public CullFrameStates(FixedNode start, State initialState) {
-            super(start, initialState);
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            if (node instanceof StateSplit) {
-                FrameState stateAfter = ((StateSplit) node).stateAfter();
-                if (stateAfter != null) {
-                    state.lastFrameState = stateAfter;
-                }
-            }
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/DeadCodeEliminationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-
-
-public class DeadCodeEliminationPhase extends Phase {
-
-    // Metrics
-    private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved");
-
-    private NodeFlood flood;
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        this.flood = graph.createNodeFlood();
-
-        flood.add(graph.start());
-        iterateSuccessors();
-        disconnectCFGNodes(graph);
-        iterateInputs(graph);
-        deleteNodes(graph);
-
-        // remove chained Merges
-        for (MergeNode merge : graph.getNodes(MergeNode.class)) {
-            if (merge.forwardEndCount() == 1 && !(merge instanceof LoopBeginNode)) {
-                graph.reduceTrivialMerge(merge);
-            }
-        }
-    }
-
-    private void iterateSuccessors() {
-        for (Node current : flood) {
-            if (current instanceof EndNode) {
-                EndNode end = (EndNode) current;
-                flood.add(end.merge());
-            } else {
-                for (Node successor : current.successors()) {
-                    flood.add(successor);
-                }
-            }
-        }
-    }
-
-    private void disconnectCFGNodes(StructuredGraph graph) {
-        for (EndNode node : graph.getNodes(EndNode.class)) {
-            if (!flood.isMarked(node)) {
-                MergeNode merge = node.merge();
-                if (merge != null && flood.isMarked(merge)) {
-                    // We are a dead end node leading to a live merge.
-                    merge.removeEnd(node);
-                }
-            }
-        }
-        for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.class)) {
-            if (flood.isMarked(loop)) {
-                boolean reachable = false;
-                for (LoopEndNode end : loop.loopEnds()) {
-                    if (flood.isMarked(end)) {
-                        reachable = true;
-                        break;
-                    }
-                }
-                if (!reachable) {
-                    Debug.log("Removing loop with unreachable end: %s", loop);
-                    for (LoopEndNode end : loop.loopEnds().snapshot()) {
-                        loop.removeEnd(end);
-                    }
-                    graph.reduceDegenerateLoopBegin(loop);
-                }
-            }
-        }
-    }
-
-    private void deleteNodes(StructuredGraph graph) {
-        for (Node node : graph.getNodes()) {
-            if (!flood.isMarked(node)) {
-                node.clearInputs();
-                node.clearSuccessors();
-            }
-        }
-        for (Node node : graph.getNodes()) {
-            if (!flood.isMarked(node)) {
-                metricNodesRemoved.increment();
-                node.safeDelete();
-            }
-        }
-    }
-
-    private void iterateInputs(StructuredGraph graph) {
-        for (Node node : graph.getNodes()) {
-            if (node instanceof LocalNode) {
-                flood.add(node);
-            }
-            if (flood.isMarked(node)) {
-                for (Node input : node.inputs()) {
-                    flood.add(input);
-                }
-            }
-        }
-        for (Node current : flood) {
-            for (Node input : current.inputs()) {
-                flood.add(input);
-            }
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ExpandBoxingNodesPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-public class ExpandBoxingNodesPhase extends Phase {
-
-    private final BoxingMethodPool pool;
-
-    public ExpandBoxingNodesPhase(BoxingMethodPool pool) {
-        this.pool = pool;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (BoxNode boxNode : graph.getNodes(BoxNode.class)) {
-            boxNode.expand(pool);
-        }
-
-        for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) {
-            unboxNode.expand(pool);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/FloatingReadPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,294 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.phases.graph.*;
-
-public class FloatingReadPhase extends Phase {
-
-    private IdentityHashMap<LoopBeginNode, List<MemoryMap>> loopEndStatesMap;
-
-    private static class LoopState {
-        public LoopBeginNode loopBegin;
-        public MemoryMap state;
-        public IdentityHashMap<PhiNode, Object> loopPhiLocations = new IdentityHashMap<>();
-        public ValueNode loopEntryAnyLocation;
-        public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) {
-            this.loopBegin = loopBegin;
-            this.state = state;
-            this.loopEntryAnyLocation = loopEntryAnyLocation;
-        }
-
-        @Override
-        public String toString() {
-            return "State@" + loopBegin;
-        }
-    }
-
-    private class MemoryMap implements MergeableState<MemoryMap> {
-        private IdentityHashMap<Object, ValueNode> lastMemorySnapshot;
-        private LinkedList<LoopState> loops;
-
-        public MemoryMap(MemoryMap memoryMap) {
-            lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
-            loops = new LinkedList<>(memoryMap.loops);
-        }
-
-        public MemoryMap() {
-            lastMemorySnapshot = new IdentityHashMap<>();
-            loops = new LinkedList<>();
-        }
-
-        @Override
-        public String toString() {
-            return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString();
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<MemoryMap> withStates) {
-            if (withStates.size() == 0) {
-                return true;
-            }
-
-            int minLoops = loops.size();
-            for (MemoryMap other : withStates) {
-                int otherLoops = other.loops.size();
-                if (otherLoops < minLoops) {
-                    minLoops = otherLoops;
-                }
-            }
-            while (loops.size() > minLoops) {
-                loops.pop();
-            }
-            for (MemoryMap other : withStates) {
-                while (other.loops.size() > minLoops) {
-                    other.loops.pop();
-                }
-            }
-
-            Set<Object> keys = new HashSet<>();
-            for (Object key : lastMemorySnapshot.keySet()) {
-                keys.add(key);
-            }
-            for (MemoryMap other : withStates) {
-                assert other.loops.size() == loops.size();
-                assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin;
-                for (Object key : other.lastMemorySnapshot.keySet()) {
-                    keys.add(key);
-                }
-            }
-            @SuppressWarnings("unchecked")
-            IdentityHashMap<Object, ValueNode> newMemorySnapshot = (IdentityHashMap<Object, ValueNode>) lastMemorySnapshot.clone();
-
-            for (Object key : keys) {
-                ValueNode merged = lastMemorySnapshot.get(key);
-                if (merged == null) {
-                    merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                }
-                int mergedStatesCount = 1;
-                boolean isPhi = false;
-                for (MemoryMap other : withStates) {
-                    ValueNode otherValue = other.lastMemorySnapshot.get(key);
-                    if (otherValue == null) {
-                        otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                    }
-                    if (isPhi) {
-                        ((PhiNode) merged).addInput(otherValue);
-                    } else if (merged != otherValue) {
-                        PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
-                        for (int j = 0; j < mergedStatesCount; j++) {
-                            phi.addInput(merged);
-                        }
-                        phi.addInput(otherValue);
-                        merged = phi;
-                        isPhi = true;
-                        newMemorySnapshot.put(key, phi);
-                    }
-                    mergedStatesCount++;
-                }
-            }
-
-            lastMemorySnapshot = newMemorySnapshot;
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION));
-            for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) {
-                PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin));
-                phi.addInput(entry.getValue());
-                entry.setValue(phi);
-                loopState.loopPhiLocations.put(phi, entry.getKey());
-            }
-            loops.push(loopState);
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) {
-            loopEndStatesMap.put(loopBegin, loopEndStates);
-            tryFinishLoopPhis(this, loopBegin);
-        }
-
-        @Override
-        public void afterSplit(FixedNode node) {
-            // nothing
-        }
-
-        @Override
-        public MemoryMap clone() {
-            return new MemoryMap(this);
-        }
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        loopEndStatesMap = new IdentityHashMap<>();
-        new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) {
-            @Override
-            protected void node(FixedNode node) {
-                processNode(node, state);
-            }
-        }.apply();
-    }
-
-    private void processNode(FixedNode node, MemoryMap state) {
-        if (node instanceof ReadNode) {
-            processRead((ReadNode) node, state);
-        } else if (node instanceof WriteNode) {
-            processWrite((WriteNode) node, state);
-        } else if (node instanceof MemoryCheckpoint) {
-            processCheckpoint((MemoryCheckpoint) node, state);
-        } else if (node instanceof LoopExitNode) {
-            processLoopExit((LoopExitNode) node, state);
-        }
-    }
-
-    private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) {
-        processAnyLocationWrite((ValueNode) checkpoint, state);
-    }
-
-    private static void processWrite(WriteNode writeNode, MemoryMap state) {
-        if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) {
-            processAnyLocationWrite(writeNode, state);
-        }
-        state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode);
-    }
-
-    private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) {
-        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
-            entry.setValue(modifiying);
-        }
-        state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying);
-        state.loops.clear();
-    }
-
-    private void processRead(ReadNode readNode, MemoryMap state) {
-        StructuredGraph graph = (StructuredGraph) readNode.graph();
-        assert readNode.getNullCheck() == false;
-        Object locationIdentity = readNode.location().locationIdentity();
-        ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity);
-        FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies()));
-        floatingRead.setNullCheck(readNode.getNullCheck());
-        ValueAnchorNode anchor = null;
-        for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) {
-            if (anchor == null) {
-                anchor = graph.add(new ValueAnchorNode());
-            }
-            anchor.addAnchoredNode(guard);
-        }
-        if (anchor != null) {
-            graph.addAfterFixed(readNode, anchor);
-        }
-        graph.replaceFixedWithFloating(readNode, floatingRead);
-    }
-
-    private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) {
-        ValueNode lastLocationAccess;
-        if (locationIdentity == LocationNode.FINAL_LOCATION) {
-            lastLocationAccess = null;
-        } else {
-            lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity);
-            if (lastLocationAccess == null) {
-                LoopState lastLoop = state.loops.peek();
-                if (lastLoop == null) {
-                    lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                } else {
-                    ValueNode phiInit;
-                    if (state.loops.size() > 1) {
-                        phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity);
-                    } else {
-                        phiInit = lastLoop.loopEntryAnyLocation;
-                    }
-                    PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin));
-                    phi.addInput(phiInit);
-                    lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi);
-                    lastLoop.loopPhiLocations.put(phi, locationIdentity);
-                    tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin);
-                    lastLocationAccess = phi;
-                }
-                state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess);
-            }
-        }
-        return lastLocationAccess;
-    }
-
-    private static void processLoopExit(LoopExitNode exit, MemoryMap state) {
-        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
-            entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory)));
-        }
-        if (!state.loops.isEmpty()) {
-            state.loops.pop();
-        }
-    }
-
-    private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) {
-        List<MemoryMap> loopEndStates = loopEndStatesMap.get(loopBegin);
-        if (loopEndStates == null) {
-            return;
-        }
-        LoopState loopState = loopMemory.loops.get(0);
-        int i = 0;
-        while (loopState.loopBegin != loopBegin) {
-            loopState = loopMemory.loops.get(++i);
-        }
-        for (PhiNode phi : loopBegin.phis()) {
-            if (phi.type() == PhiType.Memory && phi.valueCount() == 1) {
-                Object location = loopState.loopPhiLocations.get(phi);
-                assert location != null : "unknown location for " + phi;
-                for (MemoryMap endState : loopEndStates) {
-                    ValueNode otherNode = endState.lastMemorySnapshot.get(location);
-                    if (otherNode == null) {
-                        otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                    }
-                    phi.addInput(otherNode);
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/GlobalValueNumberingPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-
-public class GlobalValueNumberingPhase extends Phase {
-
-    public static final DebugMetric metricGlobalValueNumberingHits = Debug.metric("GlobalValueNumberingHits");
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        NodeBitMap visited = graph.createNodeBitMap();
-        for (Node n : graph.getNodes()) {
-            apply(n, visited, graph);
-        }
-    }
-
-    private void apply(Node n, NodeBitMap visited, StructuredGraph compilerGraph) {
-        if (!visited.isMarked(n)) {
-            visited.mark(n);
-            for (Node input : n.inputs()) {
-                apply(input, visited, compilerGraph);
-            }
-            if (n.getNodeClass().valueNumberable()) {
-                Node newNode = compilerGraph.findDuplicate(n);
-                if (newNode != null) {
-                    assert !(n instanceof FixedNode || newNode instanceof FixedNode);
-                    n.replaceAtUsages(newNode);
-                    n.safeDelete();
-                    metricGlobalValueNumberingHits.increment();
-                    Debug.log("GVN applied and new node is %1s", newNode);
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/IdentifyBoxingPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-
-public class IdentifyBoxingPhase extends Phase {
-
-    private final BoxingMethodPool pool;
-
-    public IdentifyBoxingPhase(BoxingMethodPool pool) {
-        this.pool = pool;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (Invoke invoke : graph.getInvokes()) {
-            tryIntrinsify(invoke);
-        }
-    }
-
-    public void tryIntrinsify(Invoke invoke) {
-        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
-            return;
-        }
-        MethodCallTargetNode callTarget = invoke.methodCallTarget();
-        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-        if (pool.isSpecialMethod(targetMethod)) {
-            assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument";
-            Kind returnKind = callTarget.returnKind();
-            ValueNode sourceValue = callTarget.arguments().get(0);
-
-            // Check whether this is a boxing or an unboxing.
-            Node newNode = null;
-            if (returnKind == Kind.Object) {
-                // We have a boxing method here.
-                assert Modifier.isStatic(targetMethod.accessFlags()) : "boxing method must be static";
-                Kind sourceKind = targetMethod.signature().argumentKindAt(0);
-                newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.holder(), sourceKind, invoke.bci()));
-            } else {
-                // We have an unboxing method here.
-                assert !Modifier.isStatic(targetMethod.accessFlags()) : "unboxing method must be an instance method";
-                newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue));
-            }
-
-            // Intrinsify the invoke to the special node.
-            invoke.intrinsify(newNode);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/InliningPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,420 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.concurrent.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.internal.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.PhasePlan.*;
-import com.oracle.graal.phases.util.*;
-import com.oracle.graal.phases.util.InliningUtil.*;
-
-
-public class InliningPhase extends Phase implements InliningCallback {
-    /*
-     * - Detect method which only call another method with some parameters set to constants: void foo(a) -> void foo(a, b) -> void foo(a, b, c) ...
-     *   These should not be taken into account when determining inlining depth.
-     * - honor the result of overrideInliningDecision(0, caller, invoke.bci, method, true);
-     */
-
-    private final TargetDescription target;
-    private final GraalCodeCacheProvider runtime;
-
-    private final Collection<? extends Invoke> hints;
-
-    private final PriorityQueue<InlineInfo> inlineCandidates = new PriorityQueue<>();
-    private Assumptions assumptions;
-
-    private final PhasePlan plan;
-    private final GraphCache cache;
-    private final WeightComputationPolicy weightComputationPolicy;
-    private final InliningPolicy inliningPolicy;
-    private final OptimisticOptimizations optimisticOpts;
-
-    // Metrics
-    private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
-    private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
-    private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
-
-    public InliningPhase(TargetDescription target, GraalCodeCacheProvider runtime, Collection<? extends Invoke> hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
-        this.target = target;
-        this.runtime = runtime;
-        this.hints = hints;
-        this.assumptions = assumptions;
-        this.cache = cache;
-        this.plan = plan;
-        this.optimisticOpts = optimisticOpts;
-        this.weightComputationPolicy = createWeightComputationPolicy();
-        this.inliningPolicy = createInliningPolicy();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    protected void run(final StructuredGraph graph) {
-        graph.createNodeMap();
-
-        if (hints != null) {
-            scanInvokes((Iterable<? extends Node>) Util.uncheckedCast(this.hints));
-        } else {
-            scanInvokes(graph.getNodes(InvokeNode.class));
-            scanInvokes(graph.getNodes(InvokeWithExceptionNode.class));
-        }
-
-        while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) {
-            InlineInfo candidate = inlineCandidates.remove();
-            if (!candidate.invoke.node().isAlive()) {
-                continue;
-            }
-            // refresh infos
-            final InlineInfo info = InliningUtil.getInlineInfo(candidate.invoke, candidate.level, runtime, assumptions, this, optimisticOpts);
-
-            boolean inline = Debug.scope("InliningDecisions", new Callable<Boolean>() {
-                @Override
-                public Boolean call() throws Exception {
-                    return info != null && inliningPolicy.isWorthInlining(graph, info);
-                }
-            });
-
-            if (inline) {
-                int mark = graph.getMark();
-                Iterable<Node> newNodes = null;
-                try {
-                    info.inline(graph, runtime, this);
-                    Debug.dump(graph, "after %s", info);
-                    newNodes = graph.getNewNodes(mark);
-                    if (GraalOptions.OptCanonicalizer) {
-                        new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph);
-                    }
-//                    if (GraalOptions.Intrinsify) {
-//                        new IntrinsificationPhase(runtime).apply(graph);
-//                    }
-                    metricInliningPerformed.increment();
-                } catch (BailoutException bailout) {
-                    // TODO determine if we should really bail out of the whole compilation.
-                    throw bailout;
-                } catch (AssertionError e) {
-                    throw new GraalInternalError(e).addContext(info.toString());
-                } catch (RuntimeException e) {
-                    throw new GraalInternalError(e).addContext(info.toString());
-                } catch (GraalInternalError e) {
-                    throw e.addContext(info.toString());
-                }
-
-                if (newNodes != null && info.level < GraalOptions.MaximumInlineLevel) {
-                    scanInvokes(newNodes);
-                }
-            }
-        }
-
-        if (GraalOptions.Debug && graph.getNodeCount() >= GraalOptions.MaximumDesiredSize) {
-            Debug.scope("InliningDecisions", new Runnable() {
-                public void run() {
-                    for (InlineInfo info : inlineCandidates) {
-                        Debug.log("not inlining %s because inlining cut off by MaximumDesiredSize", InliningUtil.methodName(info));
-                    }
-                }
-            });
-
-            metricInliningStoppedByMaxDesiredSize.increment();
-        }
-    }
-
-    private void scanInvokes(final Iterable<? extends Node> nodes) {
-        Debug.scope("InliningDecisions", new Runnable() {
-            public void run() {
-                for (Node node : nodes) {
-                    if (node != null) {
-                        if (node instanceof Invoke) {
-                            Invoke invoke = (Invoke) node;
-                            scanInvoke(invoke);
-                        }
-                        for (Node usage : node.usages().filterInterface(Invoke.class).snapshot()) {
-                            scanInvoke((Invoke) usage);
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    private void scanInvoke(Invoke invoke) {
-        InlineInfo info = InliningUtil.getInlineInfo(invoke, computeInliningLevel(invoke), runtime, assumptions, this, optimisticOpts);
-        if (info != null) {
-            metricInliningConsidered.increment();
-            inlineCandidates.add(info);
-        }
-    }
-
-    public static final Map<JavaMethod, Integer> parsedMethods = new HashMap<>();
-
-
-
-    private static final DebugMetric metricInliningRuns = Debug.metric("Runs");
-
-    @Override
-    public StructuredGraph buildGraph(final ResolvedJavaMethod method) {
-        metricInliningRuns.increment();
-        if (GraalOptions.CacheGraphs && cache != null) {
-            StructuredGraph cachedGraph = cache.get(method);
-            if (cachedGraph != null) {
-                return cachedGraph;
-            }
-        }
-        StructuredGraph newGraph = new StructuredGraph(method);
-        if (plan != null) {
-            plan.runPhases(PhasePosition.AFTER_PARSING, newGraph);
-        }
-        assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
-
-        if (GraalOptions.ProbabilityAnalysis) {
-            new DeadCodeEliminationPhase().apply(newGraph);
-            new ComputeProbabilityPhase().apply(newGraph);
-        }
-        if (GraalOptions.OptCanonicalizer) {
-            new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph);
-        }
-        if (GraalOptions.Intrinsify) {
-            new IntrinsificationPhase(runtime).apply(newGraph);
-        }
-        if (GraalOptions.CullFrameStates) {
-            new CullFrameStatesPhase().apply(newGraph);
-        }
-        if (GraalOptions.CacheGraphs && cache != null) {
-            cache.put(newGraph);
-        }
-        return newGraph;
-    }
-
-    @Override
-    public double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke) {
-        boolean preferred = hints != null && hints.contains(invoke);
-        return weightComputationPolicy.computeWeight(caller, method, invoke, preferred);
-    }
-
-    public static int graphComplexity(StructuredGraph graph) {
-        int result = 0;
-        for (Node node : graph.getNodes()) {
-            if (node instanceof ConstantNode || node instanceof LocalNode || node instanceof BeginNode || node instanceof ReturnNode || node instanceof UnwindNode) {
-                result += 0;
-            } else if (node instanceof PhiNode) {
-                result += 5;
-            } else if (node instanceof MergeNode || node instanceof Invoke || node instanceof LoopEndNode || node instanceof EndNode) {
-                result += 0;
-            } else if (node instanceof ControlSplitNode) {
-                result += ((ControlSplitNode) node).blockSuccessorCount();
-            } else {
-                result += 1;
-            }
-        }
-        return Math.max(1, result);
-    }
-
-
-    @Override
-    public void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) {
-        assumptions.recordConcreteMethod(method, context, impl);
-    }
-
-    @Override
-    public void recordMethodContentsAssumption(ResolvedJavaMethod method) {
-        if (assumptions != null) {
-            assumptions.recordMethodContents(method);
-        }
-    }
-
-    private static int computeInliningLevel(Invoke invoke) {
-        int count = -1;
-        FrameState curState = invoke.stateAfter();
-        while (curState != null) {
-            count++;
-            curState = curState.outerFrameState();
-        }
-        return count;
-    }
-
-    private static InliningPolicy createInliningPolicy() {
-        switch(GraalOptions.InliningPolicy) {
-            case 0: return new WeightBasedInliningPolicy();
-            case 1: return new C1StaticSizeBasedInliningPolicy();
-            case 2: return new MinimumCodeSizeBasedInliningPolicy();
-            case 3: return new DynamicSizeBasedInliningPolicy();
-            case 4: return new GreedySizeBasedInliningPolicy();
-            default:
-                GraalInternalError.shouldNotReachHere();
-                return null;
-        }
-    }
-
-    private static WeightComputationPolicy createWeightComputationPolicy() {
-        switch(GraalOptions.WeightComputationPolicy) {
-            case 0: throw new GraalInternalError("removed because of invokation counter changes");
-            case 1: return new BytecodeSizeBasedWeightComputationPolicy();
-            case 2: return new ComplexityBasedWeightComputationPolicy();
-            default:
-                GraalInternalError.shouldNotReachHere();
-                return null;
-        }
-    }
-
-    private interface InliningPolicy {
-        boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info);
-    }
-
-    private static class WeightBasedInliningPolicy implements InliningPolicy {
-        @Override
-        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
-            if (!checkCompiledCodeSize(info)) {
-                return false;
-            }
-
-            double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, callerGraph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp;
-            if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) {
-                Debug.log("not inlining %s (cut off by weight %e)", InliningUtil.methodName(info), info.weight);
-                return false;
-            }
-
-            Debug.log("inlining %s (weight %f): %s", InliningUtil.methodName(info), info.weight);
-            return true;
-        }
-    }
-
-    private static class C1StaticSizeBasedInliningPolicy implements InliningPolicy {
-        @Override
-        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
-            double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize);
-            return decideSizeBasedInlining(info, maxSize);
-        }
-    }
-
-    private static class MinimumCodeSizeBasedInliningPolicy implements InliningPolicy {
-        @Override
-        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
-            assert GraalOptions.ProbabilityAnalysis;
-            if (!checkCompiledCodeSize(info)) {
-                return false;
-            }
-
-            double inlineWeight = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability());
-            double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize * inlineWeight;
-            maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize);
-
-            return decideSizeBasedInlining(info, maxSize);
-        }
-    }
-
-    private static class DynamicSizeBasedInliningPolicy implements InliningPolicy {
-        @Override
-        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
-            assert GraalOptions.ProbabilityAnalysis;
-            if (!checkCompiledCodeSize(info)) {
-                return false;
-            }
-
-            double inlineBoost = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()) + Math.log10(Math.max(1, info.invoke.probability() - GraalOptions.ProbabilityCapForInlining + 1));
-            double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize;
-            maxSize = maxSize + maxSize * inlineBoost;
-            maxSize = Math.min(GraalOptions.MaximumGreedyInlineSize, Math.max(GraalOptions.MaximumTrivialSize, maxSize));
-
-            return decideSizeBasedInlining(info, maxSize);
-        }
-    }
-
-    private static class GreedySizeBasedInliningPolicy implements InliningPolicy {
-        @Override
-        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
-            assert GraalOptions.ProbabilityAnalysis;
-            if (!checkCompiledCodeSize(info)) {
-                return false;
-            }
-
-            double maxSize = GraalOptions.MaximumGreedyInlineSize;
-            if (GraalOptions.InliningBonusPerTransferredValue != 0) {
-                Signature signature = info.invoke.methodCallTarget().targetMethod().signature();
-                int transferredValues = signature.argumentCount(!Modifier.isStatic(info.invoke.methodCallTarget().targetMethod().accessFlags()));
-                if (signature.returnKind() != Kind.Void) {
-                    transferredValues++;
-                }
-                maxSize += transferredValues * GraalOptions.InliningBonusPerTransferredValue;
-            }
-
-            double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability());
-            maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * maxSize * inlineRatio;
-            maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize);
-
-            return decideSizeBasedInlining(info, maxSize);
-        }
-    }
-
-    private static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) {
-        boolean success = info.weight <= maxSize;
-        if (DebugScope.getInstance().isLogEnabled()) {
-            String formatterString = success ? "inlining %s (size %f <= %f)" : "not inlining %s (too large %f > %f)";
-            Debug.log(formatterString, InliningUtil.methodName(info), info.weight, maxSize);
-        }
-        return success;
-    }
-
-    private static boolean checkCompiledCodeSize(InlineInfo info) {
-        if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) {
-            Debug.log("not inlining %s (CompiledCodeSize %d > %d)", InliningUtil.methodName(info), info.compiledCodeSize(), GraalOptions.SmallCompiledCodeSize);
-            return false;
-        }
-        return true;
-    }
-
-
-    private interface WeightComputationPolicy {
-        double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke);
-    }
-
-    private static class BytecodeSizeBasedWeightComputationPolicy implements WeightComputationPolicy {
-        @Override
-        public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) {
-            double codeSize = method.codeSize();
-            if (preferredInvoke) {
-                codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis;
-            }
-            return codeSize;
-        }
-    }
-
-    private static class ComplexityBasedWeightComputationPolicy implements WeightComputationPolicy {
-        @Override
-        public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) {
-            double complexity = method.compilationComplexity();
-            if (preferredInvoke) {
-                complexity = complexity / GraalOptions.BoostInliningForEscapeAnalysis;
-            }
-            return complexity;
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/InsertStateAfterPlaceholderPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-public class InsertStateAfterPlaceholderPhase extends Phase {
-
-    private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, LIRLowerable, Canonicalizable {
-        public PlaceholderNode() {
-            super(StampFactory.forVoid());
-        }
-
-        @Override
-        public void generate(LIRGeneratorTool gen) {
-            // nothing to do
-        }
-
-        @Override
-        public boolean hasSideEffect(CodeCacheProvider runtime) {
-            return false;
-        }
-
-        @Override
-        public ValueNode canonical(CanonicalizerTool tool) {
-            if (stateAfter() == null) {
-                return null;
-            }
-            return this;
-        }
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (ReturnNode ret : graph.getNodes(ReturnNode.class)) {
-            PlaceholderNode p = graph.add(new PlaceholderNode());
-            p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI)));
-            graph.addBeforeFixed(ret, p);
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/IntrinsificationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.util.*;
-
-public class IntrinsificationPhase extends Phase {
-
-    private final GraalCodeCacheProvider runtime;
-
-    public IntrinsificationPhase(GraalCodeCacheProvider runtime) {
-        this.runtime = runtime;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (InvokeNode invoke : graph.getNodes(InvokeNode.class)) {
-            tryIntrinsify(invoke, runtime);
-        }
-        for (InvokeWithExceptionNode invoke : graph.getNodes(InvokeWithExceptionNode.class)) {
-            tryIntrinsify(invoke, runtime);
-        }
-    }
-
-    public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
-        return getIntrinsicGraph(invoke, target, runtime) != null;
-    }
-
-    private static void tryIntrinsify(Invoke invoke, GraalCodeCacheProvider runtime) {
-        if (invoke.callTarget() instanceof MethodCallTargetNode && invoke.methodCallTarget().targetMethod() != null) {
-            tryIntrinsify(invoke, invoke.methodCallTarget().targetMethod(), runtime);
-        }
-    }
-
-    private static void tryIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
-        StructuredGraph intrinsicGraph = getIntrinsicGraph(invoke, target, runtime);
-        if (intrinsicGraph != null) {
-            Debug.log(" > Intrinsify %s", target);
-            InliningUtil.inline(invoke, intrinsicGraph, true);
-        }
-    }
-
-    private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) {
-        StructuredGraph intrinsicGraph = (StructuredGraph) target.compilerStorage().get(Graph.class);
-        if (intrinsicGraph == null) {
-            // TODO remove once all intrinsics are available via compilerStorage
-            intrinsicGraph = runtime.intrinsicGraph(invoke.stateAfter().method(), invoke.bci(), target, invoke.callTarget().arguments());
-        }
-        return intrinsicGraph;
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/IterativeCheckCastEliminationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.Graph.InputChangedListener;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-
-
-public class IterativeCheckCastEliminationPhase extends Phase {
-    private final TargetDescription target;
-    private final MetaAccessProvider runtime;
-    private final Assumptions assumptions;
-
-    public IterativeCheckCastEliminationPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) {
-        this.target = target;
-        this.runtime = runtime;
-        this.assumptions = assumptions;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        Set<Node> canonicalizationRoots = new HashSet<>();
-        CheckCastEliminationPhase eliminate = new CheckCastEliminationPhase();
-        Listener listener = new Listener(canonicalizationRoots);
-        while (true) {
-            graph.trackInputChange(listener);
-            eliminate.apply(graph);
-            graph.stopTrackingInputChange();
-            if (canonicalizationRoots.isEmpty()) {
-                break;
-            }
-            new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots, null).apply(graph);
-            canonicalizationRoots.clear();
-        }
-    }
-
-    private static class Listener implements InputChangedListener {
-        private final Set<Node> canonicalizationRoots;
-        public Listener(Set<Node> canonicalizationRoots) {
-            this.canonicalizationRoots = canonicalizationRoots;
-        }
-        @Override
-        public void inputChanged(Node node) {
-            canonicalizationRoots.add(node);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/LoopSafepointInsertionPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.util.*;
-
-/**
- * Adds safepoints to loops.
- */
-public class LoopSafepointInsertionPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        nextLoop:
-        for (LoopEndNode loopEnd : graph.getNodes(LoopEndNode.class)) {
-            if (!loopEnd.canSafepoint()) {
-                continue;
-            }
-            if (GraalOptions.OptSafepointElimination) {
-                // We 'eliminate' safepoints by simply never placing them into loops that have at least one call
-                NodeIterable<FixedNode> it = NodeIterators.dominators(loopEnd).until(loopEnd.loopBegin());
-                for (FixedNode n : it) {
-                    if (n instanceof Invoke) {
-                        continue nextLoop;
-                    }
-                }
-            }
-            SafepointNode safepoint = graph.add(new SafepointNode());
-            graph.addBeforeFixed(loopEnd, safepoint);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/LoweringPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.lir.cfg.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.schedule.*;
-
-/**
- * Processes all {@link Lowerable} nodes to do their lowering.
- */
-public class LoweringPhase extends Phase {
-
-    final class LoweringToolImpl implements LoweringTool {
-
-        final FixedNode guardAnchor;
-        final NodeBitMap activeGuards;
-        FixedWithNextNode lastFixedNode;
-
-        public LoweringToolImpl(FixedNode guardAnchor, NodeBitMap activeGuards) {
-            this.guardAnchor = guardAnchor;
-            this.activeGuards = activeGuards;
-        }
-
-        @Override
-        public GraalCodeCacheProvider getRuntime() {
-            return runtime;
-        }
-
-        @Override
-        public ValueNode createNullCheckGuard(ValueNode object, long leafGraphId) {
-            return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, leafGraphId);
-        }
-
-        @Override
-        public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, long leafGraphId) {
-            return createGuard(condition, deoptReason, action, false, leafGraphId);
-        }
-
-        @Override
-        public Assumptions assumptions() {
-            return assumptions;
-        }
-
-        @Override
-        public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId) {
-            if (GraalOptions.OptEliminateGuards) {
-                for (Node usage : condition.usages()) {
-                    if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) {
-                        return (ValueNode) usage;
-                    }
-                }
-            }
-            GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, leafGraphId));
-            if (GraalOptions.OptEliminateGuards) {
-                activeGuards.grow();
-                activeGuards.mark(newGuard);
-            }
-            return newGuard;
-        }
-
-        public FixedWithNextNode lastFixedNode() {
-            return lastFixedNode;
-        }
-    }
-
-    private final GraalCodeCacheProvider runtime;
-    private final Assumptions assumptions;
-
-    public LoweringPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) {
-        this.runtime = runtime;
-        this.assumptions = assumptions;
-    }
-
-    private static boolean containsLowerable(NodeIterable<Node> nodes) {
-        for (Node n : nodes) {
-            if (n instanceof Lowerable) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected void run(final StructuredGraph graph) {
-        int  i = 0;
-        NodeBitMap processed = graph.createNodeBitMap();
-        while (true) {
-            int mark = graph.getMark();
-            final SchedulePhase schedule = new SchedulePhase();
-            schedule.apply(graph, false);
-
-            processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed);
-            Debug.dump(graph, "Lowering iteration %d", i++);
-            new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph);
-
-            if (!containsLowerable(graph.getNewNodes(mark))) {
-                // No new lowerable nodes - done!
-                break;
-            }
-            assert graph.verify();
-            processed.grow();
-        }
-    }
-
-    private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor, SchedulePhase schedule, NodeBitMap processed) {
-
-        FixedNode anchor = parentAnchor;
-        if (anchor == null) {
-            anchor = block.getBeginNode();
-        }
-        process(block, activeGuards, anchor, schedule, processed);
-
-        // Process always reached block first.
-        Block alwaysReachedBlock = block.getPostdominator();
-        if (alwaysReachedBlock != null && alwaysReachedBlock.getDominator() == block) {
-            processBlock(alwaysReachedBlock, activeGuards, anchor, schedule, processed);
-        }
-
-        // Now go for the other dominators.
-        for (Block dominated : block.getDominated()) {
-            if (dominated != alwaysReachedBlock) {
-                assert dominated.getDominator() == block;
-                processBlock(dominated, activeGuards, null, schedule, processed);
-            }
-        }
-
-        if (parentAnchor == null && GraalOptions.OptEliminateGuards) {
-            for (GuardNode guard : anchor.usages().filter(GuardNode.class)) {
-                activeGuards.clear(guard);
-            }
-        }
-    }
-
-    private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor, SchedulePhase schedule, NodeBitMap processed) {
-
-        final LoweringToolImpl loweringTool = new LoweringToolImpl(anchor, activeGuards);
-
-        // Lower the instructions of this block.
-        List<ScheduledNode> nodes = schedule.nodesFor(b);
-
-        for (Node node : nodes) {
-            FixedNode lastFixedNext = null;
-            if (node instanceof FixedWithNextNode) {
-                FixedWithNextNode fixed = (FixedWithNextNode) node;
-                lastFixedNext = fixed.next();
-                loweringTool.lastFixedNode = fixed;
-            }
-
-            if (node.isAlive() && !processed.isMarked(node)) {
-                processed.mark(node);
-                if (node instanceof Lowerable) {
-                    ((Lowerable) node).lower(loweringTool);
-                }
-            }
-
-            if (loweringTool.lastFixedNode == node && !node.isAlive()) {
-                if (lastFixedNext == null) {
-                    loweringTool.lastFixedNode = null;
-                } else {
-                    Node prev = lastFixedNext.predecessor();
-                    if (prev != node && prev instanceof FixedWithNextNode) {
-                        loweringTool.lastFixedNode = (FixedWithNextNode) prev;
-                    } else if (lastFixedNext instanceof FixedWithNextNode) {
-                        loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext;
-                    } else {
-                        loweringTool.lastFixedNode = null;
-                    }
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/Phase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.nodes.*;
-
-public abstract class Phase {
-
-    private String name;
-    private static final DebugMetric metricPhaseRuns = Debug.metric("Runs");
-    protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes");
-
-    protected Phase() {
-        this.name = this.getClass().getSimpleName();
-        if (name.endsWith("Phase")) {
-            name = name.substring(0, name.length() - "Phase".length());
-        }
-    }
-
-    protected Phase(String name) {
-        this.name = name;
-    }
-
-    protected String getDetailedName() {
-        return getName();
-    }
-
-    public final void apply(final StructuredGraph graph) {
-        apply(graph, true);
-    }
-
-    public final void apply(final StructuredGraph graph, final boolean dumpGraph) {
-        Debug.scope(name, this, new Runnable() {
-            public void run() {
-                Phase.this.run(graph);
-                metricPhaseRuns.increment();
-                if (dumpGraph) {
-                    Debug.dump(graph, "After phase %s", name);
-                }
-                assert graph.verify();
-            }
-        });
-    }
-
-    public final String getName() {
-        return name;
-    }
-
-    protected abstract void run(StructuredGraph graph);
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/PhasePlan.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.nodes.*;
-
-/**
- * Tells the compiler about additional phases that need to be executed during compilation.
- */
-public class PhasePlan {
-    /**
-     * The compilation is split into the following sections:
-     * ========================================================================
-     * Period 1: High-level nodes. (Graph building)
-     * ========================================================================
-     * Runtime-specific lowering.
-     * ========================================================================
-     * Period 2: Mid-level nodes. (Memory dependence graph)
-     * ========================================================================
-     * Target-specific lowering, de-SSA.
-     * ========================================================================
-     * Period 3: Low-level nodes. (Register allocation, code generation)
-     * ========================================================================
-     *
-     * A compiler extension phase can chose to run at the end of periods 1-3.
-     */
-    public static enum PhasePosition {
-        AFTER_PARSING,
-        HIGH_LEVEL,
-        MID_LEVEL,
-        LOW_LEVEL
-    }
-
-    @SuppressWarnings("unchecked")
-    private final ArrayList<Phase>[] phases = new ArrayList[PhasePosition.values().length];
-    private final Set<Class<? extends Phase>> disabledPhases = new HashSet<>();
-
-    public void addPhase(PhasePosition pos, Phase phase) {
-        if (phases[pos.ordinal()] == null) {
-            phases[pos.ordinal()] = new ArrayList<>();
-        }
-        phases[pos.ordinal()].add(phase);
-    }
-
-    public void runPhases(PhasePosition pos, StructuredGraph graph) {
-        if (phases[pos.ordinal()] != null) {
-            for (Phase p : phases[pos.ordinal()]) {
-                p.apply(graph);
-            }
-        }
-    }
-
-    public void disablePhase(Class<? extends Phase> clazz) {
-        disabledPhases.add(clazz);
-    }
-
-    public boolean isPhaseDisabled(Class<? extends Phase> clazz) {
-        return disabledPhases.contains(clazz);
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/PhiStampPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.nodes.*;
-
-public class PhiStampPhase extends Phase {
-    @Override
-    protected void run(StructuredGraph graph) {
-        // Infer phis stopping at loop phis.
-        for (PhiNode phi : graph.getNodes(PhiNode.class)) {
-            inferPhi(phi);
-        }
-
-        // Start iterative inference for loop phis.
-        if (graph.hasLoops()) {
-            for (PhiNode phi : graph.getNodes(PhiNode.class)) {
-                if (phi.isLoopPhi()) {
-                    iterativeInferPhi(phi);
-                }
-            }
-        }
-    }
-
-    private void iterativeInferPhi(PhiNode phi) {
-        if (phi.inferPhiStamp()) {
-            for (PhiNode phiUsage : phi.usages().filter(PhiNode.class)) {
-                iterativeInferPhi(phiUsage);
-            }
-        }
-    }
-
-    private void inferPhi(PhiNode phi) {
-        for (PhiNode phiInput : phi.values().filter(PhiNode.class)) {
-            if (!phiInput.isLoopPhi()) {
-                inferPhi(phiInput);
-            }
-        }
-        phi.inferPhiStamp();
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/ReadEliminationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
-import com.oracle.graal.nodes.extended.*;
-
-public class ReadEliminationPhase extends Phase {
-    private Queue<PhiNode> newPhis;
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        newPhis = new LinkedList<>();
-        for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) {
-            if (isReadEliminable(n)) {
-                NodeMap<ValueNode> nodeMap = n.graph().createNodeMap();
-                ValueNode value = getValue(n, n.lastLocationAccess(), nodeMap);
-                Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value);
-                graph.replaceFloating(n, value);
-            }
-        }
-    }
-
-    private boolean isReadEliminable(FloatingReadNode n) {
-        return isWrites(n, n.lastLocationAccess(), n.graph().createNodeBitMap());
-    }
-
-    private boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) {
-        if (lastLocationAccess == null) {
-            return false;
-        }
-        if (visited.isMarked(lastLocationAccess)) {
-            return true; // dataflow loops must come from Phis assume them ok until proven wrong
-        }
-        if (lastLocationAccess instanceof ValueProxyNode) {
-            return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited);
-        }
-        if (lastLocationAccess instanceof WriteNode) {
-            WriteNode other = (WriteNode) lastLocationAccess;
-            return other.object() == n.object() && other.location() == n.location();
-        }
-        if (lastLocationAccess instanceof PhiNode) {
-            visited.mark(lastLocationAccess);
-            for (ValueNode value : ((PhiNode) lastLocationAccess).values()) {
-                if (!isWrites(n, value, visited)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private ValueNode getValue(FloatingReadNode n, Node lastLocationAccess, NodeMap<ValueNode> nodeMap) {
-        ValueNode exisiting = nodeMap.get(lastLocationAccess);
-        if (exisiting != null) {
-            return exisiting;
-        }
-        if (lastLocationAccess instanceof ValueProxyNode) {
-            ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess;
-            ValueNode value = getValue(n, proxy.value(), nodeMap);
-            return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value));
-        }
-        if (lastLocationAccess instanceof WriteNode) {
-            return ((WriteNode) lastLocationAccess).value();
-        }
-        if (lastLocationAccess instanceof PhiNode) {
-            PhiNode phi = (PhiNode) lastLocationAccess;
-            PhiNode newPhi = phi.graph().add(new PhiNode(n.kind(), phi.merge()));
-            nodeMap.set(lastLocationAccess, newPhi);
-            for (ValueNode value : phi.values()) {
-                newPhi.addInput(getValue(n, value, nodeMap));
-            }
-            newPhis.add(newPhi);
-            return newPhi;
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/RemoveValueProxyPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import com.oracle.graal.nodes.*;
-
-public class RemoveValueProxyPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) {
-            graph.replaceFloating(vpn, vpn.value());
-        }
-        for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) {
-            FrameState stateAfter = exit.stateAfter();
-            if (stateAfter != null) {
-                exit.setStateAfter(null);
-                if (stateAfter.usages().count() == 0) {
-                    stateAfter.safeDelete();
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/phases/TailDuplicationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,551 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.phases;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.VirtualState.NodeClosure;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-
-/**
- * This class is a phase that looks for opportunities for tail duplication. The static method
- * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail duplication from
- * other places, e.g., inlining.
- */
-public class TailDuplicationPhase extends Phase {
-
-    /*
-     * Various metrics on the circumstances in which tail duplication was/wasn't performed.
-     */
-    private static final DebugMetric metricDuplicationMonitors = Debug.metric("DuplicationMonitors");
-    private static final DebugMetric metricDuplicationEnd = Debug.metric("DuplicationEnd");
-    private static final DebugMetric metricDuplicationEndPerformed = Debug.metric("DuplicationEndPerformed");
-    private static final DebugMetric metricDuplicationOther = Debug.metric("DuplicationOther");
-    private static final DebugMetric metricDuplicationOtherPerformed = Debug.metric("DuplicationOtherPerformed");
-
-    /**
-     * This interface is used by tail duplication to let clients decide if tail duplication should be performed.
-     */
-    public interface TailDuplicationDecision {
-
-        /**
-         * Queries if tail duplication should be performed at the given merge. If this method returns true then the tail
-         * duplication will be performed, because all other checks have happened before.
-         *
-         * @param merge The merge at which tail duplication can be performed.
-         * @param fixedNodeCount The size of the set of fixed nodes that forms the base for the duplicated set of nodes.
-         * @return true if the tail duplication should be performed, false otherwise.
-         */
-        boolean doTransform(MergeNode merge, int fixedNodeCount);
-    }
-
-    /**
-     * A tail duplication decision closure that employs the default algorithm: Check if there are any phis on the merge
-     * whose stamps improve and that have usages within the duplicated set of fixed nodes.
-     */
-    public static final TailDuplicationDecision DEFAULT_DECISION = new TailDuplicationDecision() {
-
-        public boolean doTransform(MergeNode merge, int fixedNodeCount) {
-            if (fixedNodeCount < GraalOptions.TailDuplicationTrivialSize) {
-                return true;
-            }
-            HashSet<PhiNode> improvements = new HashSet<>();
-            for (PhiNode phi : merge.phis()) {
-                Stamp phiStamp = phi.stamp();
-                for (ValueNode input : phi.values()) {
-                    if (!input.stamp().equals(phiStamp)) {
-                        improvements.add(phi);
-                        break;
-                    }
-                }
-            }
-            if (improvements.isEmpty()) {
-                return false;
-            }
-            FixedNode current = merge;
-            int opportunities = 0;
-            while (current instanceof FixedWithNextNode) {
-                current = ((FixedWithNextNode) current).next();
-                for (PhiNode phi : improvements) {
-                    for (Node input : current.inputs()) {
-                        if (input == phi) {
-                            opportunities++;
-                        }
-                        if (input.inputs().contains(phi)) {
-                            opportunities++;
-                        }
-                    }
-                }
-            }
-            return opportunities > 0;
-        }
-    };
-
-    /**
-     * A tail duplication decision closure that always returns true.
-     */
-    public static final TailDuplicationDecision TRUE_DECISION = new TailDuplicationDecision() {
-
-        @Override
-        public boolean doTransform(MergeNode merge, int fixedNodeCount) {
-            return true;
-        }
-    };
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        // A snapshot is taken here, so that new MergeNode instances aren't considered for tail duplication.
-        for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
-            if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) {
-                tailDuplicate(merge, DEFAULT_DECISION, null);
-            }
-        }
-    }
-
-    /**
-     * This method attempts to duplicate the tail of the given merge. The merge must not be a {@link LoopBeginNode}. If
-     * the merge is eligible for duplication (at least one fixed node in its tail, no {@link MonitorEnterNode}/
-     * {@link MonitorExitNode}, non-null {@link MergeNode#stateAfter()}) then the decision callback is used to determine
-     * whether the tail duplication should actually be performed. If replacements is non-null, then this list of
-     * {@link PiNode}s is used to replace one value per merge end.
-     *
-     * @param merge The merge whose tail should be duplicated.
-     * @param decision A callback that can make the final decision if tail duplication should occur or not.
-     * @param replacements A list of {@link PiNode}s, or null. If this list is non-null then its size needs to match the
-     *            merge's end count. Each entry can either be null or a {@link PiNode}, and is used to replace
-     *            {@link PiNode#object()} with the {@link PiNode} in the duplicated branch that corresponds to the
-     *            entry.
-     */
-    public static void tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements) {
-        assert !(merge instanceof LoopBeginNode);
-        assert replacements == null || replacements.size() == merge.forwardEndCount();
-        FixedNode fixed = merge;
-        int fixedCount = 0;
-        boolean containsMonitor = false;
-        while (fixed instanceof FixedWithNextNode) {
-            if (fixed instanceof MonitorEnterNode || fixed instanceof MonitorExitNode) {
-                containsMonitor = true;
-            }
-            fixed = ((FixedWithNextNode) fixed).next();
-            fixedCount++;
-        }
-        if (containsMonitor) {
-            // cannot currently be handled
-            // TODO (ls) re-evaluate this limitation after changes to the lock representation and the LIR generator
-            metricDuplicationMonitors.increment();
-        } else if (fixedCount > 1) {
-            if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) {
-                metricDuplicationEnd.increment();
-                if (decision.doTransform(merge, fixedCount)) {
-                    metricDuplicationEndPerformed.increment();
-                    new DuplicationOperation(merge, replacements).duplicate();
-                }
-            } else if (merge.stateAfter() != null) {
-                metricDuplicationOther.increment();
-                if (decision.doTransform(merge, fixedCount)) {
-                    metricDuplicationOtherPerformed.increment();
-                    new DuplicationOperation(merge, replacements).duplicate();
-                }
-            }
-        }
-    }
-
-    /**
-     * This class encapsulates one tail duplication operation on a specific {@link MergeNode}.
-     */
-    private static class DuplicationOperation {
-
-        private final MergeNode merge;
-        private final StructuredGraph graph;
-
-        private final HashMap<ValueNode, PhiNode> bottomPhis = new HashMap<>();
-        private final List<PiNode> replacements;
-
-        /**
-         * Initializes the tail duplication operation without actually performing any work.
-         *
-         * @param merge The merge whose tail should be duplicated.
-         * @param replacements A list of replacement {@link PiNode}s, or null. If this is non-null, then the size of the
-         *            list needs to match the number of end nodes at the merge.
-         */
-        public DuplicationOperation(MergeNode merge, List<PiNode> replacements) {
-            this.merge = merge;
-            this.replacements = replacements;
-            this.graph = (StructuredGraph) merge.graph();
-        }
-
-        /**
-         * Performs the actual tail duplication:
-         * <ul>
-         * <li>Creates a new {@link ValueAnchorNode} at the beginning of the duplicated area, an transfers all
-         * dependencies from the merge to this anchor.</li>
-         * <li>Determines the set of fixed nodes to be duplicated.</li>
-         * <li>Creates the new merge at the bottom of the duplicated area.</li>
-         * <li>Determines the complete set of duplicated nodes.</li>
-         * <li>Performs the actual duplication.</li>
-         * </ul>
-         */
-        private void duplicate() {
-            Debug.log("tail duplication at merge %s in %s (prob %f)", merge, graph.method(), merge.probability());
-
-            ValueAnchorNode anchor = addValueAnchor();
-
-            // determine the fixed nodes that should be duplicated (currently: all nodes up until the first control
-            // split, end node, deopt or return.
-            ArrayList<FixedNode> fixedNodes = new ArrayList<>();
-            FixedNode fixed = merge.next();
-            FrameState stateAfter = merge.stateAfter();
-            while (fixed instanceof FixedWithNextNode) {
-                fixedNodes.add(fixed);
-                if (fixed instanceof StateSplit && ((StateSplit) fixed).stateAfter() != null) {
-                    stateAfter = ((StateSplit) fixed).stateAfter();
-                }
-                fixed = ((FixedWithNextNode) fixed).next();
-            }
-
-            EndNode endAfter = createNewMerge(fixed, stateAfter);
-            MergeNode mergeAfter = endAfter.merge();
-            fixedNodes.add(endAfter);
-            final HashSet<Node> duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter);
-            mergeAfter.clearEnds();
-            expandDuplicated(duplicatedNodes, mergeAfter);
-            retargetDependencies(duplicatedNodes, anchor);
-
-            List<EndNode> endSnapshot = merge.forwardEnds().snapshot();
-            List<PhiNode> phiSnapshot = merge.phis().snapshot();
-
-            int endIndex = 0;
-            for (final EndNode forwardEnd : merge.forwardEnds()) {
-                Map<Node, Node> duplicates;
-                if (replacements == null || replacements.get(endIndex) == null) {
-                    duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null);
-                } else {
-                    HashMap<Node, Node> replace = new HashMap<>();
-                    replace.put(replacements.get(endIndex).object(), replacements.get(endIndex));
-                    duplicates = graph.addDuplicates(duplicatedNodes, replace);
-                }
-                for (Map.Entry<ValueNode, PhiNode> phi : bottomPhis.entrySet()) {
-                    phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey()));
-                }
-                mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter));
-
-                // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding EndNode
-                FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor);
-                ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate);
-                // move dependencies on the ValueAnchorNode to the previous BeginNode
-                BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate);
-                anchorDuplicate.replaceAtUsages(prevBegin);
-
-                // re-wire the phi duplicates to the correct input
-                for (PhiNode phi : phiSnapshot) {
-                    PhiNode phiDuplicate = (PhiNode) duplicates.get(phi);
-                    for (Node usage : phiDuplicate.usages()) {
-                        if (usage instanceof ValueNode) {
-                            ((ValueNode) usage).dependencies().add(prevBegin);
-                        }
-                    }
-                    phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd));
-                    phiDuplicate.safeDelete();
-                }
-                endIndex++;
-            }
-            GraphUtil.killCFG(merge);
-            for (EndNode forwardEnd : endSnapshot) {
-                forwardEnd.safeDelete();
-            }
-            for (PhiNode phi : phiSnapshot) {
-                // these phis should go away, but they still need to be anchored to a merge to be valid...
-                if (phi.isAlive()) {
-                    phi.setMerge(mergeAfter);
-                }
-            }
-            Debug.dump(graph, "After tail duplication at %s", merge);
-        }
-
-        /**
-         * Inserts a new ValueAnchorNode after the merge and transfers all dependency-usages (not phis) to this
-         * ValueAnchorNode.
-         *
-         * @return The new {@link ValueAnchorNode} that was created.
-         */
-        private ValueAnchorNode addValueAnchor() {
-            ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
-            graph.addAfterFixed(merge, anchor);
-            for (Node usage : merge.usages().snapshot()) {
-                if (usage instanceof PhiNode && ((PhiNode) usage).merge() == merge) {
-                    // nothing to do
-                } else {
-                    usage.replaceFirstInput(merge, anchor);
-                }
-            }
-            return anchor;
-        }
-
-        /**
-         * Given a set of fixed nodes, this method determines the set of fixed and floating nodes that needs to be
-         * duplicated, i.e., all nodes that due to data flow and other dependencies needs to be duplicated.
-         *
-         * @param fixedNodes The set of fixed nodes that should be duplicated.
-         * @param stateAfter The frame state of the merge that follows the set of fixed nodes. All {@link ValueNode}s
-         *            reachable from this state are considered to be reachable from within the duplicated set of nodes.
-         * @return The set of nodes that need to be duplicated.
-         */
-        private HashSet<Node> buildDuplicatedNodeSet(final ArrayList<FixedNode> fixedNodes, FrameState stateAfter) {
-            final NodeBitMap aboveBound = graph.createNodeBitMap();
-            final NodeBitMap belowBound = graph.createNodeBitMap();
-
-            final Deque<Node> worklist = new ArrayDeque<>();
-
-            // Build the set of nodes that have (transitive) usages within the duplicatedNodes.
-            // This is achieved by iterating all nodes that are reachable via inputs from the the fixed nodes.
-            aboveBound.markAll(fixedNodes);
-            worklist.addAll(fixedNodes);
-
-            // the phis at the original merge should always be duplicated
-            for (PhiNode phi : merge.phis()) {
-                aboveBound.mark(phi);
-                worklist.add(phi);
-            }
-
-            NodeClosure<Node> aboveClosure = new NodeClosure<Node>() {
-
-                @Override
-                public void apply(Node usage, Node node) {
-                    if (node instanceof PhiNode && !fixedNodes.contains(((PhiNode) node).merge())) {
-                        // stop iterating: phis belonging to outside merges are known to be outside.
-                    } else if (node instanceof FixedNode) {
-                        // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other
-                        // fixed nodes are known to be outside.
-                    } else if (!aboveBound.isMarked(node)) {
-                        worklist.add(node);
-                        aboveBound.mark(node);
-                    }
-                }
-            };
-
-            if (stateAfter != null) {
-                stateAfter.applyToNonVirtual(aboveClosure);
-            }
-            while (!worklist.isEmpty()) {
-                Node current = worklist.remove();
-                for (Node input : current.inputs()) {
-                    aboveClosure.apply(current, input);
-                }
-            }
-
-            // Build the set of nodes that have (transitive) inputs within the duplicatedNodes.
-            // This is achieved by iterating all nodes that are reachable via usages from the fixed nodes.
-            belowBound.markAll(fixedNodes);
-            worklist.addAll(fixedNodes);
-
-            // the phis at the original merge should always be duplicated
-            for (PhiNode phi : merge.phis()) {
-                belowBound.mark(phi);
-                worklist.add(phi);
-            }
-
-            while (!worklist.isEmpty()) {
-                Node current = worklist.remove();
-                for (Node usage : current.usages()) {
-                    if (usage instanceof PhiNode && !fixedNodes.contains(((PhiNode) usage).merge())) {
-                        // stop iterating: phis belonging to outside merges are known to be outside.
-                    } else if (usage instanceof FixedNode) {
-                        // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other
-                        // fixed nodes are known to be outside.
-                    } else if (!belowBound.isMarked(usage)) {
-                        worklist.add(usage);
-                        belowBound.mark(usage);
-                    }
-                }
-            }
-
-            // build the intersection
-            belowBound.intersect(aboveBound);
-            HashSet<Node> result = new HashSet<>();
-            for (Node node : belowBound) {
-                result.add(node);
-            }
-            return result;
-        }
-
-        /**
-         * Creates a new merge and end node construct at the end of the duplicated area. While it is useless in itself
-         * (merge with only one end) it simplifies the later duplication step.
-         *
-         * @param successor The successor of the duplicated set of nodes, i.e., the first node that should not be
-         *            duplicated.
-         * @param stateAfterMerge The frame state that should be used for the merge.
-         * @return The newly created end node.
-         */
-        private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
-            MergeNode newBottomMerge = graph.add(new MergeNode());
-            newBottomMerge.setProbability(successor.probability());
-            EndNode newBottomEnd = graph.add(new EndNode());
-            newBottomMerge.addForwardEnd(newBottomEnd);
-            newBottomMerge.setStateAfter(stateAfterMerge);
-            ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd);
-            newBottomMerge.setNext(successor);
-            return newBottomEnd;
-        }
-
-        /**
-         * Expands the set of nodes to be duplicated by looking at a number of conditions:
-         * <ul>
-         * <li>{@link ValueNode}s that have usages on the outside need to be replaced with phis for the outside usages.</li>
-         * <li>Non-{@link ValueNode} nodes that have outside usages (frame states, virtual object states, ...) need to
-         * be cloned immediately for the outside usages.</li>
-         * <li>Nodes that have a {@link StampFactory#extension()} or {@link StampFactory#condition()} stamp need to be
-         * cloned immediately for the outside usages.</li>
-         * <li>Dependencies into the duplicated nodes will be replaced with dependencies on the merge.</li>
-         * <li>Outside non-{@link ValueNode}s with usages within the duplicated set of nodes need to also be duplicated.
-         * </li>
-         * <li>Outside {@link ValueNode}s with {@link StampFactory#extension()} or {@link StampFactory#condition()}
-         * stamps that have usages within the duplicated set of nodes need to also be duplicated.</li>
-         * </ul>
-         *
-         * @param duplicatedNodes The set of duplicated nodes that will be modified (expanded).
-         * @param newBottomMerge The merge that follows the duplicated set of nodes. It will be used for newly created
-         *            phis and to as a target for dependencies that pointed into the duplicated set of nodes.
-         */
-        private void expandDuplicated(HashSet<Node> duplicatedNodes, MergeNode newBottomMerge) {
-            Deque<Node> worklist = new ArrayDeque<>(duplicatedNodes);
-
-            while (!worklist.isEmpty()) {
-                Node duplicated = worklist.remove();
-                if (hasUsagesOutside(duplicated, duplicatedNodes)) {
-                    boolean cloneForOutsideUsages = false;
-                    if (duplicated instanceof ValueNode) {
-                        ValueNode node = (ValueNode) duplicated;
-                        if (node.stamp() == StampFactory.dependency()) {
-                            // re-route dependencies to the merge
-                            replaceUsagesOutside(node, newBottomMerge, duplicatedNodes);
-                            // TODO(ls) maybe introduce phis for dependencies
-                        } else if (node.stamp() == StampFactory.extension() || node.stamp() == StampFactory.condition()) {
-                            cloneForOutsideUsages = true;
-                        } else {
-                            // introduce a new phi
-                            PhiNode newPhi = bottomPhis.get(node);
-                            if (newPhi == null) {
-                                newPhi = graph.add(new PhiNode(node.kind(), newBottomMerge));
-                                bottomPhis.put(node, newPhi);
-                                newPhi.addInput(node);
-                            }
-                            replaceUsagesOutside(node, newPhi, duplicatedNodes);
-                        }
-                    } else {
-                        cloneForOutsideUsages = true;
-                    }
-                    if (cloneForOutsideUsages) {
-                        // clone the offending node to the outside
-                        Node newOutsideClone = duplicated.copyWithInputs();
-                        replaceUsagesOutside(duplicated, newOutsideClone, duplicatedNodes);
-                        // this might cause other nodes to have outside usages, we need to look at those as well
-                        for (Node input : newOutsideClone.inputs()) {
-                            if (duplicatedNodes.contains(input)) {
-                                worklist.add(input);
-                            }
-                        }
-                    }
-                }
-                // check if this node has an input that lies outside and cannot be shared
-                for (Node input : duplicated.inputs()) {
-                    if (!duplicatedNodes.contains(input)) {
-                        boolean duplicateInput = false;
-                        if (input instanceof VirtualState) {
-                            duplicateInput = true;
-                        } else if (input instanceof ValueNode) {
-                            Stamp inputStamp = ((ValueNode) input).stamp();
-                            if (inputStamp == StampFactory.extension() || inputStamp == StampFactory.condition()) {
-                                duplicateInput = true;
-                            }
-                        }
-                        if (duplicateInput) {
-                            duplicatedNodes.add(input);
-                            worklist.add(input);
-                        }
-                    }
-                }
-            }
-        }
-
-        /**
-         * Moves all depdendencies that point outside the duplicated area to the supplied value anchor node.
-         *
-         * @param duplicatedNodes The set of duplicated nodes.
-         * @param anchor The node that will be the new target for all dependencies that point outside the duplicated set of nodes.
-         */
-        private static void retargetDependencies(HashSet<Node> duplicatedNodes, ValueAnchorNode anchor) {
-            for (Node node : duplicatedNodes) {
-                if (node instanceof ValueNode) {
-                    NodeInputList<ValueNode> dependencies = ((ValueNode) node).dependencies();
-                    for (int i = 0; i < dependencies.size(); i++) {
-                        Node dependency = dependencies.get(i);
-                        if (dependency != null && !duplicatedNodes.contains(dependency)) {
-                            Debug.log("retargeting dependency %s to %s on %s", dependency, anchor, node);
-                            dependencies.set(i, anchor);
-                        }
-                    }
-                }
-            }
-        }
-
-        /**
-         * Checks if the given node has usages that are not within the given set of nodes.
-         *
-         * @param node The node whose usages are checked.
-         * @param nodeSet The set of nodes that are considered to be "within".
-         * @return true if the given node has usages on the outside, false otherwise.
-         */
-        private static boolean hasUsagesOutside(Node node, HashSet<Node> nodeSet) {
-            for (Node usage : node.usages()) {
-                if (!nodeSet.contains(usage)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * Replaces the given node with the given replacement at all usages that are not within the given set of nodes.
-         *
-         * @param node The node to be replaced at outside usages.
-         * @param replacement The node that replaced the given node at outside usages.
-         * @param nodeSet The set of nodes that are considered to be "within".
-         */
-        private static void replaceUsagesOutside(Node node, Node replacement, HashSet<Node> nodeSet) {
-            for (Node usage : node.usages().snapshot()) {
-                if (!nodeSet.contains(usage)) {
-                    usage.replaceFirstInput(node, replacement);
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
 
 public class SchedulePhase extends Phase {
     private ControlFlowGraph cfg;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/InliningUtil.java	Sun Oct 07 14:15:44 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,960 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.util;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.concurrent.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.JavaType.Representation;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.FrameState.InliningIdentifier;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-
-public class InliningUtil {
-
-    private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
-
-    public interface InliningCallback {
-        StructuredGraph buildGraph(ResolvedJavaMethod method);
-        double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke);
-        void recordMethodContentsAssumption(ResolvedJavaMethod method);
-        void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl);
-    }
-
-    public static String methodName(ResolvedJavaMethod method, Invoke invoke) {
-        if (!Debug.isLogEnabled()) {
-            return null;
-        } else if (invoke != null && invoke.stateAfter() != null) {
-            return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)";
-        } else {
-            return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)";
-        }
-    }
-
-    public static String methodName(InlineInfo info) {
-        if (!Debug.isLogEnabled()) {
-            return null;
-        } else if (info.invoke != null && info.invoke.stateAfter() != null) {
-            return methodName(info.invoke.stateAfter(), info.invoke.bci()) + ": " + info.toString();
-        } else {
-            return info.toString();
-        }
-    }
-
-    private static String methodName(FrameState frameState, int bci) {
-        StringBuilder sb = new StringBuilder();
-        if (frameState.outerFrameState() != null) {
-            sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
-            sb.append("->");
-        }
-        sb.append(MetaUtil.format("%h.%n", frameState.method()));
-        sb.append("@").append(bci);
-        return sb.toString();
-    }
-
-    /**
-     * Represents an opportunity for inlining at the given invoke, with the given weight and level.
-     * The weight is the amortized weight of the additional code - so smaller is better.
-     * The level is the number of nested inlinings that lead to this invoke.
-     */
-    public abstract static class InlineInfo implements Comparable<InlineInfo> {
-        public final Invoke invoke;
-        public final double weight;
-        public final int level;
-
-        public InlineInfo(Invoke invoke, double weight, int level) {
-            this.invoke = invoke;
-            this.weight = weight;
-            this.level = level;
-        }
-
-        public abstract int compiledCodeSize();
-
-        @Override
-        public int compareTo(InlineInfo o) {
-            return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0;
-        }
-
-        protected static StructuredGraph getGraph(final ResolvedJavaMethod concrete, final InliningCallback callback) {
-            return Debug.scope("GetInliningGraph", concrete, new Callable<StructuredGraph>() {
-                @Override
-                public StructuredGraph call() throws Exception {
-                    return callback.buildGraph(concrete);
-                }
-            });
-        }
-
-        public abstract boolean canDeopt();
-
-        /**
-         * Performs the inlining described by this object and returns the node that represents the return value of the
-         * inlined method (or null for void methods and methods that have no non-exceptional exit).
-         *
-         * @param graph
-         * @param runtime
-         * @param callback
-         */
-        public abstract void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback);
-    }
-
-    /**
-     * Represents an inlining opportunity where the compiler can statically determine a monomorphic target method and
-     * therefore is able to determine the called method exactly.
-     */
-    private static class ExactInlineInfo extends InlineInfo {
-        public final ResolvedJavaMethod concrete;
-
-        public ExactInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete) {
-            super(invoke, weight, level);
-            this.concrete = concrete;
-        }
-
-        @Override
-        public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, final InliningCallback callback) {
-            StructuredGraph graph = getGraph(concrete, callback);
-            assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime);
-            callback.recordMethodContentsAssumption(concrete);
-            InliningUtil.inline(invoke, graph, true);
-        }
-
-        @Override
-        public int compiledCodeSize() {
-            return concrete.compiledCodeSize();
-        }
-
-        @Override
-        public String toString() {
-            return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-
-        @Override
-        public boolean canDeopt() {
-            return false;
-        }
-    }
-
-    /**
-     * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which
-     * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed.
-     */
-    private static class TypeGuardInlineInfo extends InlineInfo {
-        public final ResolvedJavaMethod concrete;
-        public final ResolvedJavaType type;
-
-        public TypeGuardInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete, ResolvedJavaType type) {
-            super(invoke, weight, level);
-            this.concrete = concrete;
-            this.type = type;
-        }
-
-        @Override
-        public int compiledCodeSize() {
-            return concrete.compiledCodeSize();
-        }
-
-        @Override
-        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
-            // receiver null check must be before the type check
-            InliningUtil.receiverNullCheck(invoke);
-            ValueNode receiver = invoke.methodCallTarget().receiver();
-            LoadHubNode receiverHub = graph.add(new LoadHubNode(receiver));
-            ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), runtime, graph);
-            ObjectEqualsNode typeCheck = graph.unique(new ObjectEqualsNode(receiverHub, typeHub));
-            FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, invoke.leafGraphId()));
-            ValueAnchorNode anchor = graph.add(new ValueAnchorNode());
-            assert invoke.predecessor() != null;
-
-            ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true);
-            invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-
-            graph.addBeforeFixed(invoke.node(), receiverHub);
-            graph.addBeforeFixed(invoke.node(), guard);
-            graph.addBeforeFixed(invoke.node(), anchor);
-
-            StructuredGraph calleeGraph = getGraph(concrete, callback);
-            assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime);
-            callback.recordMethodContentsAssumption(concrete);
-            InliningUtil.inline(invoke, calleeGraph, false);
-        }
-
-        @Override
-        public String toString() {
-            return "type-checked " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-
-        @Override
-        public boolean canDeopt() {
-            return true;
-        }
-    }
-
-    /**
-     * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable
-     * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered.
-     */
-    private static class MultiTypeGuardInlineInfo extends InlineInfo {
-        public final List<ResolvedJavaMethod> concretes;
-        public final ProfiledType[] ptypes;
-        public final int[] typesToConcretes;
-        public final double notRecordedTypeProbability;
-
-        public MultiTypeGuardInlineInfo(Invoke invoke, double weight, int level, List<ResolvedJavaMethod> concretes, ProfiledType[] ptypes,
-                        int[] typesToConcretes, double notRecordedTypeProbability) {
-            super(invoke, weight, level);
-            assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods";
-            assert ptypes.length == typesToConcretes.length : "array lengths must match";
-
-            this.concretes = concretes;
-            this.ptypes = ptypes;
-            this.typesToConcretes = typesToConcretes;
-            this.notRecordedTypeProbability = notRecordedTypeProbability;
-        }
-
-        @Override
-        public int compiledCodeSize() {
-            int result = 0;
-            for (ResolvedJavaMethod m: concretes) {
-                result += m.compiledCodeSize();
-            }
-            return result;
-        }
-
-        @Override
-        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
-            int numberOfMethods = concretes.size();
-            boolean hasReturnValue = invoke.node().kind() != Kind.Void;
-
-            // receiver null check must be the first node
-            InliningUtil.receiverNullCheck(invoke);
-            if (numberOfMethods > 1 || shouldFallbackToInvoke()) {
-                inlineMultipleMethods(graph, runtime, callback, numberOfMethods, hasReturnValue);
-            } else {
-                inlineSingleMethod(graph, runtime, callback);
-            }
-        }
-
-        private boolean shouldFallbackToInvoke() {
-            return notRecordedTypeProbability > 0;
-        }
-
-        private void inlineMultipleMethods(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, int numberOfMethods, boolean hasReturnValue) {
-            FixedNode continuation = invoke.next();
-
-            ValueNode originalReceiver = invoke.methodCallTarget().receiver();
-            // setup merge and phi nodes for results and exceptions
-            MergeNode returnMerge = graph.add(new MergeNode());
-            returnMerge.setProbability(invoke.probability());
-            returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci));
-
-            PhiNode returnValuePhi = null;
-            if (hasReturnValue) {
-                returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge));
-            }
-
-            MergeNode exceptionMerge = null;
-            PhiNode exceptionObjectPhi = null;
-            if (invoke instanceof InvokeWithExceptionNode) {
-                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge();
-                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
-
-                exceptionMerge = graph.add(new MergeNode());
-                exceptionMerge.setProbability(exceptionEdge.probability());
-
-                FixedNode exceptionSux = exceptionObject.next();
-                graph.addBeforeFixed(exceptionSux, exceptionMerge);
-                exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge));
-                exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Void, exceptionObjectPhi));
-            }
-
-            // create one separate block for each invoked method
-            BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods];
-            for (int i = 0; i < numberOfMethods; i++) {
-                int predecessors = 0;
-                double probability = 0;
-                for (int j = 0; j < typesToConcretes.length; j++) {
-                    if (typesToConcretes[j] == i) {
-                        predecessors++;
-                        probability += ptypes[j].probability;
-                    }
-                }
-
-                calleeEntryNodes[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, predecessors, invoke.probability() * probability, true);
-            }
-
-            // create the successor for an unknown type
-            FixedNode unknownTypeNode;
-            if (shouldFallbackToInvoke()) {
-                unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, notRecordedTypeProbability, false);
-            } else {
-                unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId()));
-            }
-
-            // replace the invoke exception edge
-            if (invoke instanceof InvokeWithExceptionNode) {
-                InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
-                BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge();
-                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
-                exceptionObject.replaceAtUsages(exceptionObjectPhi);
-                exceptionObject.setNext(null);
-                GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
-            }
-
-            // replace the invoke with a switch on the type of the actual receiver
-            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver()));
-            graph.addBeforeFixed(invoke.node(), receiverHub);
-            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, calleeEntryNodes, unknownTypeNode);
-
-            assert invoke.next() == continuation;
-            invoke.setNext(null);
-            returnMerge.setNext(continuation);
-            invoke.node().replaceAtUsages(returnValuePhi);
-            invoke.node().replaceAndDelete(dispatchOnType);
-
-            ArrayList<PiNode> replacements = new ArrayList<>();
-
-            // do the actual inlining for every invoke
-            for (int i = 0; i < calleeEntryNodes.length; i++) {
-                BeginNode node = calleeEntryNodes[i];
-                Invoke invokeForInlining = (Invoke) node.next();
-
-                ResolvedJavaType commonType = getLeastCommonType(i);
-                ValueNode receiver = invokeForInlining.methodCallTarget().receiver();
-                boolean exact = getTypeCount(i) == 1;
-                PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
-                invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-
-                ResolvedJavaMethod concrete = concretes.get(i);
-                StructuredGraph calleeGraph = getGraph(concrete, callback);
-                callback.recordMethodContentsAssumption(concrete);
-                assert !IntrinsificationPhase.canIntrinsify(invokeForInlining, concrete, runtime);
-                InliningUtil.inline(invokeForInlining, calleeGraph, false);
-                replacements.add(anchoredReceiver);
-            }
-            if (shouldFallbackToInvoke()) {
-                replacements.add(null);
-            }
-            if (GraalOptions.OptTailDuplication) {
-                /*
-                 * We might want to perform tail duplication at the merge after a type switch, if there are invokes that would
-                 * benefit from the improvement in type information.
-                 */
-                FixedNode current = returnMerge;
-                int opportunities = 0;
-                do {
-                    if (current instanceof InvokeNode && ((InvokeNode) current).methodCallTarget().receiver() == originalReceiver) {
-                        opportunities++;
-                    } else if (current.inputs().contains(originalReceiver)) {
-                        opportunities++;
-                    }
-                    current = ((FixedWithNextNode) current).next();
-                } while (current instanceof FixedWithNextNode);
-                if (opportunities > 0) {
-                    metricInliningTailDuplication.increment();
-                    Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements);
-                }
-            }
-        }
-
-        private int getTypeCount(int concreteMethodIndex) {
-            int count = 0;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
-                    count++;
-                }
-            }
-            return count;
-        }
-
-        private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
-            ResolvedJavaType commonType = null;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
-                    if (commonType == null) {
-                        commonType = ptypes[i].type;
-                    } else {
-                        commonType = commonType.leastCommonAncestor(ptypes[i].type);
-                    }
-                }
-            }
-            assert commonType != null;
-            return commonType;
-        }
-
-        private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
-            assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
-
-            MergeNode calleeEntryNode = graph.add(new MergeNode());
-            calleeEntryNode.setProbability(invoke.probability());
-            LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver()));
-            graph.addBeforeFixed(invoke.node(), receiverHub);
-
-            FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId()));
-            FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, new BeginNode[] {calleeEntryNode}, unknownTypeNode);
-
-            FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor();
-            pred.setNext(dispatchOnType);
-            calleeEntryNode.setNext(invoke.node());
-
-            ResolvedJavaMethod concrete = concretes.get(0);
-            StructuredGraph calleeGraph = getGraph(concrete, callback);
-            assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime);
-            callback.recordMethodContentsAssumption(concrete);
-            InliningUtil.inline(invoke, calleeGraph, false);
-        }
-
-        private FixedNode createDispatchOnType(StructuredGraph graph, LoadHubNode objectClassNode, BeginNode[] calleeEntryNodes, FixedNode unknownTypeSux) {
-            assert ptypes.length > 1;
-
-            ResolvedJavaType[] types = new ResolvedJavaType[ptypes.length];
-            double[] probabilities = new double[ptypes.length + 1];
-            BeginNode[] successors = new BeginNode[ptypes.length + 1];
-            int[] keySuccessors = new int[ptypes.length + 1];
-            for (int i = 0; i < ptypes.length; i++) {
-                types[i] = ptypes[i].type;
-                probabilities[i] = ptypes[i].probability;
-                FixedNode entry = calleeEntryNodes[typesToConcretes[i]];
-                if (entry instanceof MergeNode) {
-                    EndNode endNode = graph.add(new EndNode());
-                    ((MergeNode) entry).addForwardEnd(endNode);
-                    entry = endNode;
-                }
-                successors[i] = BeginNode.begin(entry);
-                keySuccessors[i] = i;
-            }
-            assert !(unknownTypeSux instanceof MergeNode);
-            successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
-            probabilities[successors.length - 1] = notRecordedTypeProbability;
-            keySuccessors[successors.length - 1] = successors.length - 1;
-
-            TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(objectClassNode, successors, probabilities, types, probabilities, keySuccessors));
-
-            return typeSwitch;
-        }
-
-        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi,
-                        MergeNode exceptionMerge, PhiNode exceptionObjectPhi, int predecessors, double probability, boolean useForInlining) {
-            Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability);
-            BeginNode calleeEntryNode = graph.add(predecessors > 1 ? new MergeNode() : new BeginNode());
-            calleeEntryNode.setNext(duplicatedInvoke.node());
-            calleeEntryNode.setProbability(probability);
-
-            EndNode endNode = graph.add(new EndNode());
-            endNode.setProbability(probability);
-
-            duplicatedInvoke.setNext(endNode);
-            returnMerge.addForwardEnd(endNode);
-
-            if (returnValuePhi != null) {
-                returnValuePhi.addInput(duplicatedInvoke.node());
-            }
-            return calleeEntryNode;
-        }
-
-        private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) {
-            Invoke result = (Invoke) invoke.node().copyWithInputs();
-            Node callTarget = result.callTarget().copyWithInputs();
-            result.node().replaceFirstInput(result.callTarget(), callTarget);
-            result.setUseForInlining(useForInlining);
-            result.setProbability(probability);
-
-            Kind kind = invoke.node().kind();
-            if (!kind.isVoid()) {
-                FrameState stateAfter = invoke.stateAfter();
-                stateAfter = stateAfter.duplicate(stateAfter.bci);
-                stateAfter.replaceFirstInput(invoke.node(), result.node());
-                result.setStateAfter(stateAfter);
-            }
-
-            if (invoke instanceof InvokeWithExceptionNode) {
-                assert exceptionMerge != null && exceptionObjectPhi != null;
-
-                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
-                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
-                FrameState stateAfterException = exceptionObject.stateAfter();
-
-                BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs();
-                ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs();
-                // set new state (pop old exception object, push new one)
-                newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject));
-                newExceptionEdge.setNext(newExceptionObject);
-
-                EndNode endNode = graph.add(new EndNode());
-                newExceptionObject.setNext(endNode);
-                exceptionMerge.addForwardEnd(endNode);
-                exceptionObjectPhi.addInput(newExceptionObject);
-
-                ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
-            }
-            return result;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
-            builder.append(String.format(", %d methods with %d type checks:", concretes.size(), ptypes.length));
-            for (int i = 0; i < concretes.size(); i++) {
-                builder.append(MetaUtil.format("  %H.%n(%p):%r", concretes.get(i)));
-            }
-            return builder.toString();
-        }
-
-        @Override
-        public boolean canDeopt() {
-            return true;
-        }
-    }
-
-
-    /**
-     * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method,
-     * but for which an assumption has to be registered because of non-final classes.
-     */
-    private static class AssumptionInlineInfo extends ExactInlineInfo {
-        public final ResolvedJavaType context;
-
-        public AssumptionInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaType context, ResolvedJavaMethod concrete) {
-            super(invoke, weight, level, concrete);
-            this.context = context;
-        }
-
-        @Override
-        public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) {
-            if (Debug.isLogEnabled()) {
-                String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod());
-                String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete);
-                Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName);
-            }
-            callback.recordConcreteMethodAssumption(invoke.methodCallTarget().targetMethod(), context, concrete);
-
-            super.inline(graph, runtime, callback);
-        }
-
-        @Override
-        public String toString() {
-            return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
-        }
-
-        @Override
-        public boolean canDeopt() {
-            return true;
-        }
-    }
-
-    /**
-     * Determines if inlining is possible at the given invoke node.
-     * @param invoke the invoke that should be inlined
-     * @param level the number of nested inlinings that lead to this invoke, or 0 if the invoke was part of the initial graph
-     * @param runtime a GraalRuntime instance used to determine of the invoke can be inlined and/or should be intrinsified
-     * @param callback a callback that is used to determine the weight of a specific inlining
-     * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
-     */
-    public static InlineInfo getInlineInfo(Invoke invoke, int level, GraalCodeCacheProvider runtime, Assumptions assumptions, InliningCallback callback, OptimisticOptimizations optimisticOpts) {
-        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
-            // The invoke has already been lowered , or has been created as a low-level node. We have no method information.
-            return null;
-        }
-        ResolvedJavaMethod parent = invoke.stateAfter().method();
-        MethodCallTargetNode callTarget = invoke.methodCallTarget();
-        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-        if (targetMethod == null) {
-            return null;
-        }
-        if (!checkInvokeConditions(invoke)) {
-            return null;
-        }
-
-        if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
-            if (checkTargetConditions(invoke, targetMethod, optimisticOpts)) {
-                double weight = callback == null ? 0 : callback.inliningWeight(parent, targetMethod, invoke);
-                return new ExactInlineInfo(invoke, weight, level, targetMethod);
-            }
-            return null;
-        }
-        ObjectStamp receiverStamp = callTarget.receiver().objectStamp();
-        ResolvedJavaType receiverType = receiverStamp.type();
-        if (receiverStamp.isExactType()) {
-            assert receiverType.isSubtypeOf(targetMethod.holder()) : receiverType + " subtype of " + targetMethod.holder() + " for " + targetMethod;
-            ResolvedJavaMethod resolved = receiverType.resolveMethodImpl(targetMethod);
-            if (checkTargetConditions(invoke, resolved, optimisticOpts)) {
-                double weight = callback == null ? 0 : callback.inliningWeight(parent, resolved, invoke);
-                return new ExactInlineInfo(invoke, weight, level, resolved);
-            }
-            return null;
-        }
-        ResolvedJavaType holder = targetMethod.holder();
-
-        if (receiverStamp.type() != null) {
-            // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...)
-            // TODO (lstadler) fix this
-            if (receiverType != null && receiverType.isSubtypeOf(holder)) {
-                holder = receiverType;
-            }
-        }
-        // TODO (thomaswue) fix this
-        if (assumptions != null) {
-            ResolvedJavaMethod concrete = holder.uniqueConcreteMethod(targetMethod);
-            if (concrete != null) {
-                if (checkTargetConditions(invoke, concrete, optimisticOpts)) {
-                    double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
-                    return new AssumptionInlineInfo(invoke, weight, level, holder, concrete);
-                }
-                return null;
-            }
-        }
-
-        // type check based inlining
-        return getTypeCheckedInlineInfo(invoke, level, callback, parent, targetMethod, optimisticOpts);
-    }
-
-    private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, int level, InliningCallback callback, ResolvedJavaMethod parent, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) {
-        ProfilingInfo profilingInfo = parent.profilingInfo();
-        JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
-        if (typeProfile != null) {
-            ProfiledType[] ptypes = typeProfile.getTypes();
-
-            if (ptypes != null && ptypes.length > 0) {
-                double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
-                if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
-                    if (optimisticOpts.inlineMonomorphicCalls()) {
-                        ResolvedJavaType type = ptypes[0].type;
-                        ResolvedJavaMethod concrete = type.resolveMethodImpl(targetMethod);
-                        if (checkTargetConditions(invoke, concrete, optimisticOpts)) {
-                            double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
-                            return new TypeGuardInlineInfo(invoke, weight, level, concrete, type);
-                        }
-
-                        Debug.log("not inlining %s because method can't be inlined", methodName(targetMethod, invoke));
-                        return null;
-                    } else {
-                        Debug.log("not inlining %s because GraalOptions.InlineMonomorphicCalls == false", methodName(targetMethod, invoke));
-                        return null;
-                    }
-                } else {
-                    invoke.setMegamorphic(true);
-                    if (optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0 || optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
-                        // TODO (chaeubl) inlining of multiple methods should work differently
-                        // 1. check which methods can be inlined
-                        // 2. for those methods, use weight and probability to compute which of them should be inlined
-                        // 3. do the inlining
-                        //    a) all seen methods can be inlined -> do so and guard with deopt
-                        //    b) some methods can be inlined -> inline them and fall back to invocation if violated
-                        // TODO (chaeubl) sort types by probability
-
-                        // determine concrete methods and map type to specific method
-                        ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
-                        int[] typesToConcretes = new int[ptypes.length];
-                        for (int i = 0; i < ptypes.length; i++) {
-                            ResolvedJavaMethod concrete = ptypes[i].type.resolveMethodImpl(targetMethod);
-
-                            int index = concreteMethods.indexOf(concrete);
-                            if (index < 0) {
-                                index = concreteMethods.size();
-                                concreteMethods.add(concrete);
-                            }
-                            typesToConcretes[i] = index;
-                        }
-
-                        double totalWeight = 0;
-                        boolean canInline = true;
-                        for (ResolvedJavaMethod concrete: concreteMethods) {
-                            if (!checkTargetConditions(invoke, concrete, optimisticOpts)) {
-                                canInline = false;
-                                break;
-                            }
-                            totalWeight += callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
-                        }
-
-                        if (canInline) {
-                            return new MultiTypeGuardInlineInfo(invoke, totalWeight, level, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability);
-                        } else {
-                            Debug.log("not inlining %s because it is a polymorphic method call and at least one invoked method cannot be inlined", methodName(targetMethod, invoke));
-                            return null;
-                        }
-                    } else {
-                        if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
-                            Debug.log("not inlining %s because GraalOptions.InlinePolymorphicCalls == false", methodName(targetMethod, invoke));
-                        } else {
-                            Debug.log("not inlining %s because GraalOptions.InlineMegamorphicCalls == false", methodName(targetMethod, invoke));
-                        }
-                        return null;
-                    }
-                }
-            }
-
-            Debug.log("not inlining %s because no types/probabilities were recorded", methodName(targetMethod, invoke));
-            return null;
-        } else {
-            Debug.log("not inlining %s because no type profile exists", methodName(targetMethod, invoke));
-            return null;
-        }
-    }
-
-    private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
-        // to avoid that floating reads on receiver fields float above the type check
-        return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType)));
-    }
-
-    private static boolean checkInvokeConditions(Invoke invoke) {
-        if (invoke.stateAfter() == null) {
-            Debug.log("not inlining %s because the invoke has no after state", methodName(invoke.methodCallTarget().targetMethod(), invoke));
-            return false;
-        }
-        if (invoke.predecessor() == null) {
-            Debug.log("not inlining %s because the invoke is dead code", methodName(invoke.methodCallTarget().targetMethod(), invoke));
-            return false;
-        }
-        if (!invoke.useForInlining()) {
-            Debug.log("not inlining %s because invoke is marked to be not used for inlining", methodName(invoke.methodCallTarget().targetMethod(), invoke));
-            return false;
-        }
-        return true;
-    }
-
-    private static boolean checkTargetConditions(Invoke invoke, JavaMethod method, OptimisticOptimizations optimisticOpts) {
-        if (method == null) {
-            Debug.log("not inlining because method is not resolved");
-            return false;
-        }
-        if (!(method instanceof ResolvedJavaMethod)) {
-            Debug.log("not inlining %s because it is unresolved", method.toString());
-            return false;
-        }
-        ResolvedJavaMethod resolvedMethod = (ResolvedJavaMethod) method;
-        if (Modifier.isNative(resolvedMethod.accessFlags())) {
-            Debug.log("not inlining %s because it is a native method", methodName(resolvedMethod, invoke));
-            return false;
-        }
-        if (Modifier.isAbstract(resolvedMethod.accessFlags())) {
-            Debug.log("not inlining %s because it is an abstract method", methodName(resolvedMethod, invoke));
-            return false;
-        }
-        if (!resolvedMethod.holder().isInitialized()) {
-            Debug.log("not inlining %s because of non-initialized class", methodName(resolvedMethod, invoke));
-            return false;
-        }
-        if (!resolvedMethod.canBeInlined()) {
-            Debug.log("not inlining %s because it is marked non-inlinable", methodName(resolvedMethod, invoke));
-            return false;
-        }
-        if (computeRecursiveInliningLevel(invoke.stateAfter(), (ResolvedJavaMethod) method) > GraalOptions.MaximumRecursiveInlining) {
-            Debug.log("not inlining %s because it exceeds the maximum recursive inlining depth", methodName(resolvedMethod, invoke));
-            return false;
-        }
-        OptimisticOptimizations calleeOpts = new OptimisticOptimizations(resolvedMethod);
-        if (calleeOpts.lessOptimisticThan(optimisticOpts)) {
-            Debug.log("not inlining %s because callee uses less optimistic optimizations than caller", methodName(resolvedMethod, invoke));
-            return false;
-        }
-
-        return true;
-    }
-
-    private static int computeRecursiveInliningLevel(FrameState state, ResolvedJavaMethod method) {
-        assert state != null;
-
-        int count = 0;
-        FrameState curState = state;
-        while (curState != null) {
-            if (curState.method() == method) {
-                count++;
-            }
-            curState = curState.outerFrameState();
-        }
-        return count;
-    }
-
-    /**
-     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
-     *
-     * @param invoke the invoke that will be replaced
-     * @param inlineGraph the graph that the invoke will be replaced with
-     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
-     */
-    public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
-        InliningIdentifier identifier = new InliningIdentifier(inlineGraph.method(), invoke);
-        NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
-        StructuredGraph graph = (StructuredGraph) invoke.node().graph();
-
-        FrameState stateAfter = invoke.stateAfter();
-        assert stateAfter.isAlive();
-
-        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
-        ArrayList<Node> nodes = new ArrayList<>();
-        ReturnNode returnNode = null;
-        UnwindNode unwindNode = null;
-        StartNode entryPointNode = inlineGraph.start();
-        FixedNode firstCFGNode = entryPointNode.next();
-        for (Node node : inlineGraph.getNodes()) {
-            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
-                // Do nothing.
-            } else if (node instanceof LocalNode) {
-                replacements.put(node, parameters.get(((LocalNode) node).index()));
-            } else {
-                nodes.add(node);
-                if (node instanceof ReturnNode) {
-                    assert returnNode == null;
-                    returnNode = (ReturnNode) node;
-                } else if (node instanceof UnwindNode) {
-                    assert unwindNode == null;
-                    unwindNode = (UnwindNode) node;
-                }
-            }
-        }
-        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode
-
-        assert invoke.node().successors().first() != null : invoke;
-        assert invoke.node().predecessor() != null;
-
-        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
-        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
-        if (receiverNullCheck) {
-            receiverNullCheck(invoke);
-        }
-        invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate);
-
-        FrameState stateAtExceptionEdge = null;
-        if (invoke instanceof InvokeWithExceptionNode) {
-            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
-            if (unwindNode != null) {
-                assert unwindNode.predecessor() != null;
-                assert invokeWithException.exceptionEdge().successors().count() == 1;
-                ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next();
-                stateAtExceptionEdge = obj.stateAfter();
-                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                obj.replaceAtUsages(unwindDuplicate.exception());
-                unwindDuplicate.clearInputs();
-                Node n = obj.next();
-                obj.setNext(null);
-                unwindDuplicate.replaceAndDelete(n);
-            } else {
-                invokeWithException.killExceptionEdge();
-            }
-        } else {
-            if (unwindNode != null) {
-                UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler, invoke.leafGraphId());
-                unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode));
-                // move the deopt upwards if there is a monitor exit that tries to use the "after exception" frame state
-                // (because there is no "after exception" frame state!)
-                if (deoptimizeNode.predecessor() instanceof MonitorExitNode) {
-                    MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor();
-                    if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) {
-                        FrameState monitorFrameState = monitorExit.stateAfter();
-                        graph.removeFixed(monitorExit);
-                        monitorFrameState.safeDelete();
-                    }
-                }
-            }
-        }
-
-        FrameState outerFrameState = null;
-        double invokeProbability = invoke.node().probability();
-        for (Node node : duplicates.values()) {
-            if (GraalOptions.ProbabilityAnalysis) {
-                if (node instanceof FixedNode) {
-                    FixedNode fixed = (FixedNode) node;
-                    double newProbability = fixed.probability() * invokeProbability;
-                    if (GraalOptions.LimitInlinedProbability) {
-                        newProbability = Math.min(newProbability, invokeProbability);
-                    }
-                    fixed.setProbability(newProbability);
-                }
-            }
-            if (node instanceof FrameState) {
-                FrameState frameState = (FrameState) node;
-                assert frameState.bci != FrameState.BEFORE_BCI;
-                if (frameState.bci == FrameState.AFTER_BCI) {
-                    frameState.replaceAndDelete(stateAfter);
-                } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) {
-                    if (frameState.isAlive()) {
-                        assert stateAtExceptionEdge != null;
-                        frameState.replaceAndDelete(stateAtExceptionEdge);
-                    } else {
-                        assert stateAtExceptionEdge == null;
-                    }
-                } else {
-                    // only handle the outermost frame states
-                    if (frameState.outerFrameState() == null) {
-                        assert frameState.method() == inlineGraph.method();
-                        if (outerFrameState == null) {
-                            outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind());
-                            outerFrameState.setDuringCall(true);
-                        }
-                        frameState.setOuterFrameState(outerFrameState);
-                        frameState.setInliningIdentifier(identifier);
-                    }
-                }
-            }
-        }
-
-        Node returnValue = null;
-        if (returnNode != null) {
-            if (returnNode.result() instanceof LocalNode) {
-                returnValue = replacements.get(returnNode.result());
-            } else {
-                returnValue = duplicates.get(returnNode.result());
-            }
-            invoke.node().replaceAtUsages(returnValue);
-            Node returnDuplicate = duplicates.get(returnNode);
-            returnDuplicate.clearInputs();
-            Node n = invoke.next();
-            invoke.setNext(null);
-            returnDuplicate.replaceAndDelete(n);
-        }
-
-        invoke.node().clearInputs();
-        invoke.node().replaceAtUsages(null);
-        GraphUtil.killCFG(invoke.node());
-
-        if (stateAfter.usages().isEmpty()) {
-            stateAfter.safeDelete();
-        }
-    }
-
-    public static void receiverNullCheck(Invoke invoke) {
-        MethodCallTargetNode callTarget = invoke.methodCallTarget();
-        StructuredGraph graph = (StructuredGraph) invoke.graph();
-        NodeInputList<ValueNode> parameters = callTarget.arguments();
-        ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
-        if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) {
-            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, true, invoke.leafGraphId())));
-        }
-    }
-}
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Sun Oct 07 14:27:50 2012 +0200
@@ -37,7 +37,6 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
 
 /**
  * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the <a
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -29,7 +29,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.snippets.CheckCastTest.*;
 
 /**
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InvokeTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InvokeTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -27,7 +27,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * Tests the implementation of the snippets for lowering the INVOKE* instructions.
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java	Sun Oct 07 14:27:50 2012 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
 import com.oracle.graal.snippets.Snippet.InliningPolicy;
 
 /**
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Sun Oct 07 14:27:50 2012 +0200
@@ -36,8 +36,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
-import com.oracle.graal.phases.util.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.snippets.Snippet.InliningPolicy;
 
 /**
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -34,7 +34,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.snippets.Snippet.Fold;
 
 public class SnippetIntrinsificationPhase extends Phase {
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Sun Oct 07 14:27:50 2012 +0200
@@ -38,7 +38,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.snippets.Snippet.ConstantParameter;
 import com.oracle.graal.snippets.Snippet.Parameter;
 import com.oracle.graal.snippets.Snippet.Varargs;
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetVerificationPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetVerificationPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -33,7 +33,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.snippets.Word.*;
 
 /**
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -32,7 +32,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.snippets.Word.Opcode;
 import com.oracle.graal.snippets.Word.Operation;
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -39,7 +39,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.nodes.*;
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/experimental/SplitPartialEscapeAnalysisPhase.java	Sun Oct 07 14:15:44 2012 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/experimental/SplitPartialEscapeAnalysisPhase.java	Sun Oct 07 14:27:50 2012 +0200
@@ -39,7 +39,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.phases.*;
+import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
--- a/mx/projects	Sun Oct 07 14:15:44 2012 +0200
+++ b/mx/projects	Sun Oct 07 14:27:50 2012 +0200
@@ -151,17 +151,24 @@
 project@com.oracle.graal.phases@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.phases@javaCompliance=1.7
 
+# graal.phases.common
+project@com.oracle.graal.phases.common@subDir=graal
+project@com.oracle.graal.phases.common@sourceDirs=src
+project@com.oracle.graal.phases.common@dependencies=com.oracle.graal.phases
+project@com.oracle.graal.phases.common@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.phases.common@javaCompliance=1.7
+
 # graal.virtual
 project@com.oracle.graal.virtual@subDir=graal
 project@com.oracle.graal.virtual@sourceDirs=src
-project@com.oracle.graal.virtual@dependencies=com.oracle.graal.phases
+project@com.oracle.graal.virtual@dependencies=com.oracle.graal.phases.common
 project@com.oracle.graal.virtual@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.virtual@javaCompliance=1.7
 
 # graal.loop
 project@com.oracle.graal.loop@subDir=graal
 project@com.oracle.graal.loop@sourceDirs=src
-project@com.oracle.graal.loop@dependencies=com.oracle.graal.phases
+project@com.oracle.graal.loop@dependencies=com.oracle.graal.phases.common
 project@com.oracle.graal.loop@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.loop@javaCompliance=1.7
 
@@ -202,7 +209,7 @@
 # graal.java
 project@com.oracle.graal.java@subDir=graal
 project@com.oracle.graal.java@sourceDirs=src
-project@com.oracle.graal.java@dependencies=com.oracle.graal.phases,com.oracle.graal.bytecode
+project@com.oracle.graal.java@dependencies=com.oracle.graal.phases.common,com.oracle.graal.bytecode
 project@com.oracle.graal.java@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.java@javaCompliance=1.7
 
--- a/src/share/vm/runtime/arguments.cpp	Sun Oct 07 14:15:44 2012 +0200
+++ b/src/share/vm/runtime/arguments.cpp	Sun Oct 07 14:27:50 2012 +0200
@@ -2164,6 +2164,7 @@
         "com.oracle.graal.compiler",
         "com.oracle.graal.loop",
         "com.oracle.graal.phases",
+        "com.oracle.graal.phases.common",
         "com.oracle.graal.virtual",
         "com.oracle.graal.nodes",
         "com.oracle.graal.printer",