changeset 3089:05b8a7787aaf

merge
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 27 Jun 2011 17:15:12 +0200
parents be5deef7c7a0 (diff) 33da84ebbe50 (current diff)
children 536528f48708
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Instruction.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MemoryAccess.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MemoryRead.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MemoryWrite.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/WriteNode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java
diffstat 16 files changed, 1008 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Mon Jun 27 17:15:12 2011 +0200
@@ -54,6 +54,10 @@
     public static int     MaximumDesiredSize                 = 8000;
     public static int     MaximumShortLoopSize               = 5;
 
+    // escape analysis settings
+    public static int     ForcedInlineEscapeWeight           = 0;
+    public static int     MaximumEscapeAnalysisArrayLength   = 32;
+
     // debugging settings
     public static boolean VerifyPointerMaps                  = ____;
     public static int     MethodEndBreakpointGuards          = 0;
@@ -101,6 +105,7 @@
     public static boolean TraceAssembler                     = ____;
     public static boolean TraceInlining                      = ____;
     public static boolean TraceDeadCodeElimination           = ____;
+    public static boolean TraceEscapeAnalysis                = ____;
     public static boolean TraceMemoryMaps                    = ____;
     public static int     TraceBytecodeParserLevel           = 0;
     public static boolean QuietBailout                       = ____;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Mon Jun 27 17:15:12 2011 +0200
@@ -402,7 +402,7 @@
     @Override
     public void visitNewObjectArray(NewObjectArray x) {
         XirArgument length = toXirArgument(x.length());
-        XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementClass(), x.exactType());
+        XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementType(), x.exactType());
         emitXir(snippet, x, stateFor(x), null, true);
     }
 
@@ -1607,7 +1607,9 @@
 
     private void walkStateValue(Value value) {
         if (value != null) {
-            if (value instanceof Phi && !((Phi) value).isDead()) {
+            if (value instanceof VirtualObject) {
+                walkVirtualObject((VirtualObject) value);
+            } else if (value instanceof Phi && !((Phi) value).isDead()) {
                 // phi's are special
                 operandForPhi((Phi) value);
             } else if (value.operand().isIllegal()) {
@@ -1618,6 +1620,13 @@
         }
     }
 
+    private void walkVirtualObject(VirtualObject value) {
+        walkStateValue(value.input());
+        if (value.object() != null) {
+            walkVirtualObject(value.object());
+        }
+    }
+
     protected LIRDebugInfo stateFor(Value x) {
         assert lastState != null : "must have state before instruction for " + x;
         return stateFor(x, lastState);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java	Mon Jun 27 17:15:12 2011 +0200
@@ -90,7 +90,7 @@
         //printGraph("After DeadCodeElimination", compilation.graph);
 
         if (GraalOptions.Inline) {
-            new InliningPhase(compilation, this, GraalOptions.TraceInlining).apply(compilation.graph);
+            new InliningPhase(compilation, this, null, GraalOptions.TraceInlining).apply(compilation.graph);
         }
 
         Graph graph = compilation.graph;
@@ -99,8 +99,11 @@
             new CanonicalizerPhase().apply(graph);
             new DeadCodeEliminationPhase().apply(graph);
         }
-//
-//        new EscapeAnalysisPhase().apply(graph);
+
+        new EscapeAnalysisPhase(compilation, this).apply(graph);
+        new DeadCodeEliminationPhase().apply(graph);
+        new CanonicalizerPhase().apply(graph);
+        new DeadCodeEliminationPhase().apply(graph);
 
         if (GraalOptions.OptLoops) {
             new LoopPhase().apply(graph);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java	Mon Jun 27 17:15:12 2011 +0200
@@ -84,7 +84,6 @@
     public final RiMethod target;
     public final RiType returnType;
     public final int bci; // XXX needed because we can not compute the bci from the sateBefore bci of this Invoke was optimized from INVOKEINTERFACE to INVOKESPECIAL
-    public final RiTypeProfile profile;
 
     /**
      * Constructs a new Invoke instruction.
@@ -95,13 +94,12 @@
      * @param isStatic {@code true} if this call is static (no receiver object)
      * @param target the target method being called
      */
-    public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, RiTypeProfile profile, Graph graph) {
+    public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, Graph graph) {
         super(result, args.length, SUCCESSOR_COUNT, graph);
         this.opcode = opcode;
         this.target = target;
         this.returnType = returnType;
         this.bci = bci;
-        this.profile = profile;
 
         this.argumentCount = args.length;
         for (int i = 0; i < args.length; i++) {
@@ -148,10 +146,6 @@
         return target;
     }
 
-    public RiTypeProfile profile() {
-        return profile;
-    }
-
     /**
      * Checks whether this invocation has a receiver object.
      * @return {@code true} if this invocation has a receiver object; {@code false} otherwise, if this is a
@@ -201,7 +195,7 @@
 
     @Override
     public Node copy(Graph into) {
-        Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, profile, into);
+        Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, into);
         return x;
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Mon Jun 27 17:15:12 2011 +0200
@@ -22,8 +22,15 @@
  */
 package com.oracle.max.graal.compiler.ir;
 
+import java.util.*;
+
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp;
+import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
 
 /**
  * The {@code NewArray} class is the base of all instructions that allocate arrays.
@@ -67,4 +74,158 @@
         super(CiKind.Object, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph);
         setLength(length);
     }
+
+    /**
+     * The list of instructions which produce input for this instruction.
+     */
+    public Value dimension(int index) {
+        assert index == 0;
+        return length();
+    }
+
+    /**
+     * The rank of the array allocated by this instruction, i.e. how many array dimensions.
+     */
+    public int dimensionCount() {
+        return 1;
+    }
+
+    public abstract CiKind elementKind();
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == EscapeOp.class) {
+            return (T) ESCAPE;
+        }
+        return super.lookup(clazz);
+    }
+
+    private static class NewArrayEscapeOp implements EscapeOp {
+
+        @Override
+        public boolean canAnalyze(Node node) {
+            NewArray x = (NewArray) node;
+            CiConstant length = x.dimension(0).asConstant();
+            return length != null && length.asInt() >= 0 && length.asInt() < GraalOptions.MaximumEscapeAnalysisArrayLength;
+        }
+
+        @Override
+        public boolean escape(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof FrameState) {
+                FrameState x = (FrameState) usage;
+                assert x.inputs().contains(node);
+                return true;
+            } else if (usage instanceof LoadIndexed) {
+                LoadIndexed x = (LoadIndexed) usage;
+                assert x.array() == node;
+                CiConstant index = x.index().asConstant();
+                CiConstant length = ((NewArray) node).dimension(0).asConstant();
+                if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) {
+                    return true;
+                }
+                return false;
+            } else if (usage instanceof StoreField) {
+                StoreField x = (StoreField) usage;
+                assert x.value() == node;
+                return true;
+            } else if (usage instanceof StoreIndexed) {
+                StoreIndexed x = (StoreIndexed) usage;
+                CiConstant index = x.index().asConstant();
+                CiConstant length = ((NewArray) node).dimension(0).asConstant();
+                if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) {
+                    return true;
+                }
+                return x.value() == node;
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof ArrayLength) {
+                ArrayLength x = (ArrayLength) usage;
+                assert x.array() == node;
+                return false;
+            } else if (usage instanceof VirtualObject) {
+                VirtualObject x = (VirtualObject) usage;
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        @Override
+        public void beforeUpdate(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replace(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.type() == ((NewArray) node).exactType();
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replace(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                x.replace(x.next());
+            } else if (usage instanceof ArrayLength) {
+                ArrayLength x = (ArrayLength) usage;
+                x.replace(((NewArray) node).dimension(0));
+            }
+        }
+
+        @Override
+        public void collectField(Node node, Node usage, Map<Object, EscapeField> fields) {
+            if (usage instanceof AccessIndexed) {
+                AccessIndexed x = (AccessIndexed) usage;
+                CiConstant index = x.index().asConstant();
+                CiConstant length = ((NewArray) node).dimension(0).asConstant();
+                assert index != null && length != null && index.asInt() >= 0 && index.asInt() < length.asInt();
+
+                Integer representation = index.asInt();
+                if (!fields.containsKey(representation)) {
+                    fields.put(representation, new EscapeField("[" + representation + "]", representation, ((NewArray) node).elementKind()));
+                }
+            }
+        }
+
+        @Override
+        public void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState) {
+            if (current instanceof AccessIndexed) {
+                int index = ((AccessIndexed) current).index().asConstant().asInt();
+                EscapeField field = fields.get(index);
+                if (current instanceof LoadIndexed) {
+                    LoadIndexed x = (LoadIndexed) current;
+                    if (x.array() == node) {
+                        for (Node usage : new ArrayList<Node>(x.usages())) {
+                            assert fieldState.get(field) != null;
+                            usage.inputs().replace(x, fieldState.get(field));
+                        }
+                        assert x.usages().size() == 0;
+                        x.replace(x.next());
+                    }
+                } else if (current instanceof StoreIndexed) {
+                    StoreIndexed x = (StoreIndexed) current;
+                    if (x.array() == node) {
+                        fieldState.put(field, x.value());
+                        assert x.usages().size() == 0;
+                        x.replace(x.next());
+                    }
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Mon Jun 27 17:15:12 2011 +0200
@@ -22,7 +22,12 @@
  */
 package com.oracle.max.graal.compiler.ir;
 
+import java.util.*;
+
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp;
+import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -31,6 +36,7 @@
  * The {@code NewInstance} instruction represents the allocation of an instance class object.
  */
 public final class NewInstance extends FloatingNode {
+    private static final EscapeOp ESCAPE = new NewInstanceEscapeOp();
 
     private static final int INPUT_COUNT = 0;
     private static final int SUCCESSOR_COUNT = 0;
@@ -85,4 +91,124 @@
         NewInstance x = new NewInstance(instanceClass, cpi, constantPool, into);
         return x;
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == EscapeOp.class) {
+            return (T) ESCAPE;
+        }
+        return super.lookup(clazz);
+    }
+
+    private static class NewInstanceEscapeOp implements EscapeOp {
+
+        @Override
+        public boolean canAnalyze(Node node) {
+            return ((NewInstance) node).instanceClass().isResolved();
+        }
+
+        @Override
+        public boolean escape(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof FrameState) {
+                FrameState x = (FrameState) usage;
+                assert x.inputs().contains(node);
+                return true;
+            } else if (usage instanceof LoadField) {
+                LoadField x = (LoadField) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof StoreField) {
+                StoreField x = (StoreField) usage;
+                return x.value() == node;
+            } else if (usage instanceof StoreIndexed) {
+                StoreIndexed x = (StoreIndexed) usage;
+                assert x.value() == node;
+                return true;
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof VirtualObject) {
+                VirtualObject x = (VirtualObject) usage;
+                return false;
+            } else if (usage instanceof RegisterFinalizer) {
+                RegisterFinalizer x = (RegisterFinalizer) usage;
+                assert x.object() == node;
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        @Override
+        public void beforeUpdate(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replace(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.type() == ((NewInstance) node).instanceClass();
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replace(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                x.replace(x.next());
+            } else if (usage instanceof RegisterFinalizer) {
+                RegisterFinalizer x = (RegisterFinalizer) usage;
+                x.replace(x.next());
+            }
+        }
+
+        @Override
+        public void collectField(Node node, Node usage, Map<Object, EscapeField> fields) {
+             if (usage instanceof AccessField) {
+                 AccessField x = (AccessField) usage;
+                assert x.object() == node;
+                if (!fields.containsKey(x.field())) {
+                    fields.put(x.field(), new EscapeField(x.field().name(), x.field(), x.field.kind().stackKind()));
+                }
+            }
+        }
+
+        @Override
+        public void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState) {
+            if (current instanceof AccessField) {
+                EscapeField field = fields.get(((AccessField) current).field());
+                if (current instanceof LoadField) {
+                    LoadField x = (LoadField) current;
+                    if (x.object() == node) {
+                        for (Node usage : new ArrayList<Node>(x.usages())) {
+                            assert fieldState.get(field) != null;
+                            usage.inputs().replace(x, fieldState.get(field));
+                        }
+                        assert x.usages().size() == 0;
+                        x.replace(x.next());
+                    }
+                } else if (current instanceof StoreField) {
+                    StoreField x = (StoreField) current;
+                    if (x.object() == node) {
+                        fieldState.put(field, x.value());
+                        assert x.usages().size() == 0;
+                        x.replace(x.next());
+                    }
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java	Mon Jun 27 17:15:12 2011 +0200
@@ -50,6 +50,7 @@
     /**
      * The list of instructions which produce input for this instruction.
      */
+    @Override
     public Value dimension(int index) {
         assert index >= 0 && index < dimensionCount;
         return (Value) inputs().get(super.inputCount() + index);
@@ -63,6 +64,7 @@
     /**
      * The rank of the array allocated by this instruction, i.e. how many array dimensions.
      */
+    @Override
     public int dimensionCount() {
         return dimensionCount;
     }
@@ -105,6 +107,21 @@
     }
 
     @Override
+    public CiKind elementKind() {
+        return elementType.kind();
+    }
+
+    @Override
+    public RiType exactType() {
+        return elementType.arrayOf();
+    }
+
+    @Override
+    public RiType declaredType() {
+        return exactType();
+    }
+
+    @Override
     public void print(LogStream out) {
         out.print("new multi array [");
         for (int i = 0; i < dimensionCount; i++) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java	Mon Jun 27 17:15:12 2011 +0200
@@ -52,11 +52,16 @@
      * Gets the type of the elements of the array.
      * @return the element type of the array
      */
-    public RiType elementClass() {
+    public RiType elementType() {
         return elementClass;
     }
 
     @Override
+    public CiKind elementKind() {
+        return elementClass.kind();
+    }
+
+    @Override
     public RiType exactType() {
         return elementClass.arrayOf();
     }
@@ -73,7 +78,7 @@
 
     @Override
     public void print(LogStream out) {
-        out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementClass()));
+        out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementType()));
     }
 
     @Override
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java	Mon Jun 27 17:15:12 2011 +0200
@@ -42,6 +42,7 @@
         this.elementType = elementType;
     }
 
+    @Override
     public CiKind elementKind() {
         return elementType.kind();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java	Mon Jun 27 17:15:12 2011 +0200
@@ -0,0 +1,125 @@
+/*
+ * 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.max.graal.compiler.ir;
+
+import java.util.*;
+
+import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField;
+import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
+
+
+public class VirtualObject extends FloatingNode {
+
+    private static final int INPUT_COUNT = 2;
+    private static final int INPUT_OBJECT = 0;
+    private static final int INPUT_INPUT = 1;
+
+    private static final int SUCCESSOR_COUNT = 0;
+
+    @Override
+    protected int inputCount() {
+        return super.inputCount() + INPUT_COUNT;
+    }
+
+    @Override
+    protected int successorCount() {
+        return super.successorCount() + SUCCESSOR_COUNT;
+    }
+
+    /**
+     * The instruction that specifies the old state of the virtual object.
+     */
+     public VirtualObject object() {
+        return (VirtualObject) inputs().get(super.inputCount() + INPUT_OBJECT);
+    }
+
+    public VirtualObject setObject(VirtualObject n) {
+        return (VirtualObject) inputs().set(super.inputCount() + INPUT_OBJECT, n);
+    }
+
+    /**
+     * The instruction that contains the new state of the specified field.
+     */
+     public Value input() {
+        return (Value) inputs().get(super.inputCount() + INPUT_INPUT);
+    }
+
+    public Value setInput(Value n) {
+        return (Value) inputs().set(super.inputCount() + INPUT_INPUT, n);
+    }
+
+    private EscapeField field;
+    private RiType type;
+
+    /**
+     * Constructs a new ArrayLength instruction.
+     * @param array the instruction producing the array
+     * @param newFrameState the state after executing this instruction
+     */
+    public VirtualObject(VirtualObject object, EscapeField field, RiType type, Graph graph) {
+        super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        this.field = field;
+        this.type = type;
+        setObject(object);
+    }
+
+    public EscapeField field() {
+        return field;
+    }
+
+    public RiType type() {
+        return type;
+    }
+
+    @Override
+    public void accept(ValueVisitor v) {
+        // nothing to do...
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties() {
+        Map<Object, Object> properties = super.getDebugProperties();
+        properties.put("type", type);
+        properties.put("field", field);
+        return properties;
+    }
+
+    @Override
+    public String shortName() {
+        return "VirtualObject " + field.name();
+    }
+
+    @Override
+    public void print(LogStream out) {
+        out.print(object()).print(".").print(field.name()).print("=").print(input());
+    }
+
+    @Override
+    public Node copy(Graph into) {
+        VirtualObject x = new VirtualObject(null, field, type, into);
+        return x;
+    }
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java	Mon Jun 27 17:15:12 2011 +0200
@@ -29,6 +29,7 @@
 import com.oracle.max.graal.compiler.gen.*;
 import com.oracle.max.graal.compiler.ir.*;
 import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
 
 
 public class DeadCodeEliminationPhase extends Phase {
@@ -53,20 +54,29 @@
             }
         }
         // remove if nodes with constant-value comparison
-//        for (If ifNode : graph.getNodes(If.class)) {
-//            Compare compare = ifNode.compare();
-//            if (compare.x().isConstant() && compare.y().isConstant()) {
-//                CiConstant constX = compare.x().asConstant();
-//                CiConstant constY = compare.y().asConstant();
-//                Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime);
-//                if (result != null) {
-//                    Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor();
-//                    ifNode.replace(actualSuccessor);
-//                } else {
-//                    TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind);
-//                }
-//            }
-//        }
+        for (If ifNode : graph.getNodes(If.class)) {
+            BooleanNode bool = ifNode.compare();
+            if (bool instanceof Compare) {
+                Compare compare = (Compare) bool;
+                if (compare.x().isConstant() && compare.y().isConstant()) {
+                    CiConstant constX = compare.x().asConstant();
+                    CiConstant constY = compare.y().asConstant();
+                    Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime);
+                    if (result != null) {
+                        Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor();
+                        ifNode.replace(actualSuccessor);
+                    } else {
+                        TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind);
+                    }
+                }
+            }
+        }
+        // remove unnecessary FixedGuards
+        for (FixedGuard guard : graph.getNodes(FixedGuard.class)) {
+            if (guard.node() instanceof IsNonNull && ((IsNonNull) guard.node()).object() instanceof NewInstance) {
+                guard.replace(guard.next());
+            }
+        }
 
         flood.add(graph.start());
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Mon Jun 27 17:15:12 2011 +0200
@@ -0,0 +1,385 @@
+/*
+ * 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.max.graal.compiler.phases;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.gen.*;
+import com.oracle.max.graal.compiler.graph.*;
+import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.schedule.*;
+import com.oracle.max.graal.compiler.value.*;
+import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
+
+
+public class EscapeAnalysisPhase extends Phase {
+
+
+    public static class BlockExitState {
+        public final Map<EscapeField, Node> fieldState;
+
+        public BlockExitState() {
+            this.fieldState = new HashMap<EscapeField, Node>();
+        }
+    }
+
+    public class EscapementFixup {
+
+        private List<Block> blocks;
+        private final Map<Object, EscapeField> fields = new HashMap<Object, EscapeField>();
+        private final Map<Block, BlockExitState> exitStates = new HashMap<Block, BlockExitState>();
+
+        private final EscapeOp op;
+        private Graph graph;
+        private final Node node;
+
+        public EscapementFixup(EscapeOp op, Graph graph, Node node) {
+            this.op = op;
+            this.graph = graph;
+            this.node = node;
+        }
+
+        public void apply() {
+            process();
+            removeAllocation();
+        }
+
+        public void removeAllocation() {
+            final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true);
+            identifyBlocksPhase.apply(graph);
+            blocks = identifyBlocksPhase.getBlocks();
+
+            final HashMap<Phi, EscapeField> phis = new HashMap<Phi, EscapeField>();
+            final Block startBlock = identifyBlocksPhase.getNodeToBlock().get(node);
+            assert startBlock != null;
+            final RiType type = ((Value) node).exactType();
+
+            Block.iteratePostOrder(blocks, new BlockClosure() {
+
+                public void apply(Block block) {
+                    if (GraalOptions.TraceEscapeAnalysis) {
+                        TTY.println("Block %d", block.blockID());
+                    }
+//                    for (Node n : block.getInstructions()) {
+//                        TTY.println("  %d %s", n.id(), n.shortName());
+//                    }
+//                    for (Block b : block.getSuccessors()) {
+//                        TTY.print(" %d", b.blockID());
+//                    }
+//                    TTY.println();
+
+                    BlockExitState state = new BlockExitState();
+                    if (block == startBlock) {
+                        for (EscapeField field : fields.values()) {
+                            state.fieldState.put(field, Constant.defaultForKind(field.kind(), graph));
+                        }
+                    } else {
+                        List<Block> predecessors = block.getPredecessors();
+                        Set<EscapeField> mergedFields = new HashSet<EscapeField>();
+                        for (int i = 0; i < predecessors.size(); i++) {
+                            BlockExitState exitState = exitStates.get(predecessors.get(i));
+                            if (exitState == null) {
+                                mergedFields.addAll(fields.values());
+                                break;
+                            } else {
+                                for (EscapeField field : fields.values()) {
+                                    if (state.fieldState.get(field) == null) {
+                                        state.fieldState.put(field, exitState.fieldState.get(field));
+                                    } else if (state.fieldState.get(field) != exitState.fieldState.get(field)) {
+                                        mergedFields.add(field);
+                                    }
+                                }
+                            }
+                        }
+                        if (!mergedFields.isEmpty()) {
+                            assert block.firstNode() instanceof Merge : "unexpected: " + block.firstNode().shortName() + " " + block.firstNode().id();
+                            for (EscapeField field : mergedFields) {
+                                Phi phi = new Phi(field.kind().stackKind(), (Merge) block.firstNode(), graph);
+                                state.fieldState.put(field, phi);
+                                phis.put(phi, field);
+                            }
+                        }
+                    }
+
+                    Node current;
+                    if (block.firstNode() instanceof StartNode) {
+                        current = ((StartNode) block.firstNode()).start();
+                    } else {
+                        current = block.firstNode();
+                    }
+                    while (current != block.lastNode()) {
+                        Node next = ((Instruction) current).next();
+                        op.updateState(node, current, fields, state.fieldState);
+                        if (!current.isDeleted() && current instanceof Instruction) {
+                            FrameState stateAfter = ((Instruction) current).stateAfter();
+                            if (stateAfter != null) {
+                                updateFrameState(stateAfter, state, type, null);
+                            }
+                        }
+                        current = next;
+                    }
+
+                    if (GraalOptions.TraceEscapeAnalysis) {
+                        TTY.print(" block end state: ");
+                        for (Entry<EscapeField, Node> entry : state.fieldState.entrySet()) {
+                            TTY.print("%s->%s ", entry.getKey().name(), entry.getValue());
+                        }
+                        TTY.println();
+                    }
+                    exitStates.put(block, state);
+                }
+            }, startBlock);
+
+            for (Entry<Phi, EscapeField> entry : phis.entrySet()) {
+                Phi phi = entry.getKey();
+                EscapeField field = entry.getValue();
+                Block block = identifyBlocksPhase.getNodeToBlock().get(entry.getKey().merge());
+
+                List<Block> predecessors = block.getPredecessors();
+                assert predecessors.size() > 0;
+                Node simple = exitStates.get(predecessors.get(0)).fieldState.get(field);
+                for (int i = 1; i < predecessors.size(); i++) {
+                    BlockExitState exitState = exitStates.get(predecessors.get(i));
+                    if (exitState.fieldState.get(field) != simple) {
+                        simple = null;
+                    }
+                }
+                if (simple != null) {
+                    for (Node usage : new ArrayList<Node>(phi.usages())) {
+                        usage.inputs().replace(phi, simple);
+                    }
+                    phi.delete();
+                } else {
+                    for (int i = 0; i < predecessors.size(); i++) {
+                        BlockExitState exitState = exitStates.get(predecessors.get(i));
+                        assert exitState != null;
+                        Node value = exitState.fieldState.get(field);
+                        if (GraalOptions.TraceEscapeAnalysis) {
+                            TTY.println("fixing phi %d with %s", phi.id(), value);
+                        }
+                        if (value == null) {
+                            phi.addInput(Constant.defaultForKind(field.kind(), graph));
+                        } else {
+                            phi.addInput(value);
+                        }
+                    }
+                }
+            }
+            // the rest of the usages should be dead frame states...
+            for (Node usage : new ArrayList<Node>(node.usages())) {
+                assert usage instanceof FrameState || usage instanceof VirtualObject;
+                usage.inputs().replace(node, Node.Null);
+            }
+
+            if (node instanceof Instruction) {
+                node.replace(((Instruction) node).next());
+            } else {
+                node.delete();
+            }
+        }
+
+        private VirtualObject updateFrameState(FrameState frameState, BlockExitState currentState, RiType type, VirtualObject current) {
+            for (int i = 0; i < frameState.inputs().size(); i++) {
+                if (frameState.inputs().get(i) == node) {
+                    if (current == null) {
+                        for (EscapeField field : fields.values()) {
+                            current = new VirtualObject(current, field, type, graph);
+                            current.setInput((Value) currentState.fieldState.get(field));
+                        }
+                    }
+                    frameState.inputs().set(i, current);
+                } else if (frameState.inputs().get(i) instanceof VirtualObject) {
+                    VirtualObject obj = (VirtualObject) frameState.inputs().get(i);
+                    do {
+                        current = updateVirtualObject(obj, currentState, type, current);
+                        obj = obj.object();
+                    } while (obj != null);
+                }
+            }
+            if (frameState.outerFrameState() != null) {
+                current = updateFrameState(frameState.outerFrameState(), currentState, type, current);
+            }
+            return current;
+        }
+
+        private VirtualObject updateVirtualObject(VirtualObject obj, BlockExitState currentState, RiType type, VirtualObject current) {
+            if (obj.input() == node) {
+                if (current == null) {
+                    for (EscapeField field : fields.values()) {
+                        current = new VirtualObject(current, field, type, graph);
+                        current.setInput((Value) currentState.fieldState.get(field));
+                    }
+                }
+                obj.setInput(current);
+            } else if (obj.input() instanceof VirtualObject) {
+                VirtualObject obj2 = (VirtualObject) obj.input();
+                do {
+                    current = updateVirtualObject(obj2, currentState, type, current);
+                    obj2 = obj2.object();
+                } while (obj2 != null);
+            }
+            return current;
+        }
+
+        private void process() {
+            for (Node usage : new ArrayList<Node>(node.usages())) {
+                op.beforeUpdate(node, usage);
+                if (!usage.isDeleted()) {
+                    op.collectField(node, usage, fields);
+                }
+            }
+        }
+    }
+
+    private final GraalCompilation compilation;
+    private final IR ir;
+
+    public EscapeAnalysisPhase(GraalCompilation compilation, IR ir) {
+        this.compilation = compilation;
+        this.ir = ir;
+    }
+
+    @Override
+    protected void run(Graph graph) {
+//        if (!compilation.method.holder().name().contains("jnt")) {
+//            return;
+//        }
+//        if (true) return;
+        for (Node node : graph.getNodes()) {
+            EscapeOp op = node.lookup(EscapeOp.class);
+            if (op != null && op.canAnalyze(node)) {
+                Set<Node> exits = new HashSet<Node>();
+                Set<Invoke> invokes = new HashSet<Invoke>();
+                int iterations = 0;
+
+                int weight;
+                int minimumWeight = GraalOptions.ForcedInlineEscapeWeight;
+                do {
+                    weight = analyze(op, node, exits, invokes);
+                    if (exits.size() != 0) {
+                        if (GraalOptions.TraceEscapeAnalysis) {
+                            TTY.println("####### escaping object: %d %s in %s", node.id(), node.shortName(), compilation.method);
+                            TTY.print("%d: new value: %d %s, weight %d, escapes at ", iterations, node.id(), node.shortName(), weight);
+                            for (Node n : exits) {
+                                TTY.print("%d %s, ", n.id(), n.shortName());
+                            }
+                            for (Node n : invokes) {
+                                TTY.print("%d %s, ", n.id(), n.shortName());
+                            }
+                            TTY.println();
+                        }
+                        break;
+                    }
+                    if (invokes.size() == 0) {
+                        if (GraalOptions.TraceEscapeAnalysis) {
+                            TTY.println("!!!!!!!! non-escaping object: %d %s in %s", node.id(), node.shortName(), compilation.method);
+                        }
+                        new EscapementFixup(op, graph, node).apply();
+                        new PhiSimplifier(graph);
+                        break;
+                    }
+                    if (weight < minimumWeight) {
+                        if (GraalOptions.TraceEscapeAnalysis) {
+                            TTY.println("####### possibly escaping object: %d in %s (insufficient weight for inlining)", node.id(), compilation.method);
+                        }
+                        break;
+                    }
+                    new InliningPhase(compilation, ir, invokes, GraalOptions.TraceInlining).apply(graph);
+                    exits.clear();
+                    invokes.clear();
+                } while (iterations++ < 3);
+            }
+        }
+    }
+
+    private int analyze(EscapeOp op, Node node, Collection<Node> exits, Collection<Invoke> invokes) {
+        int weight = 0;
+        for (Node usage : node.usages()) {
+            boolean escapes = op.escape(node, usage);
+            if (escapes) {
+                if (usage instanceof FrameState) {
+                    // nothing to do...
+                } else if (usage instanceof Invoke) {
+                    invokes.add((Invoke) usage);
+                } else {
+                    exits.add(usage);
+                    if (!GraalOptions.TraceEscapeAnalysis) {
+                        break;
+                    }
+                }
+            } else {
+                weight++;
+            }
+        }
+        return weight;
+    }
+
+    public static class EscapeField {
+
+        private String name;
+        private Object representation;
+        private CiKind kind;
+
+        public EscapeField(String name, Object representation, CiKind kind) {
+            this.name = name;
+            this.representation = representation;
+            this.kind = kind;
+        }
+
+        public String name() {
+            return name;
+        }
+
+        public Object representation() {
+            return representation;
+        }
+
+        public CiKind kind() {
+            return kind;
+        }
+
+        @Override
+        public String toString() {
+            return name();
+        }
+    }
+
+    public static interface EscapeOp extends Op {
+
+        boolean canAnalyze(Node node);
+
+        boolean escape(Node node, Node usage);
+
+        void beforeUpdate(Node node, Node usage);
+
+        void collectField(Node node, Node usage, Map<Object, EscapeField> fields);
+
+        void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState);
+
+    }
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java	Mon Jun 27 17:15:12 2011 +0200
@@ -963,7 +963,7 @@
             append(deoptimize);
             frameState.pushReturn(resultType, Constant.defaultForKind(resultType, graph));
         } else {
-            Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), method.typeProfile(bci()), graph);
+            Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph);
             Value result = appendWithBCI(invoke);
             invoke.setExceptionEdge(handleException(null, bci()));
             frameState.pushReturn(resultType, result);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Mon Jun 27 17:15:12 2011 +0200
@@ -32,25 +32,29 @@
 import com.oracle.max.graal.compiler.ir.Deoptimize.DeoptAction;
 import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
+import com.sun.cri.bytecode.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
 
 
 public class InliningPhase extends Phase {
 
+    public static HashMap<RiMethod, Integer> methodCount = new HashMap<RiMethod, Integer>();
+
     private final GraalCompilation compilation;
     private final IR ir;
 
     private final Queue<Invoke> invokes = new ArrayDeque<Invoke>();
     private final Queue<RiMethod> methods = new ArrayDeque<RiMethod>();
 
-    private final Map<Invoke, RiMethod> parentMethod = new HashMap<Invoke, RiMethod>();
     private int inliningSize;
     private final boolean trace;
+    private final Collection<Invoke> hints;
 
-    public InliningPhase(GraalCompilation compilation, IR ir, boolean trace) {
+    public InliningPhase(GraalCompilation compilation, IR ir, Collection<Invoke> hints, boolean trace) {
         this.compilation = compilation;
         this.ir = ir;
+        this.hints = hints;
         this.trace = trace;
     }
 
@@ -60,59 +64,33 @@
         inliningSize += method.codeSize();
     }
 
-    public static HashMap<RiMethod, Integer> methodCount = new HashMap<RiMethod, Integer>();
+    private Queue<Invoke> newInvokes = new ArrayDeque<Invoke>();
+    private Graph graph;
+
     @Override
     protected void run(Graph graph) {
+        this.graph = graph;
+
         float ratio = GraalOptions.MaximumInlineRatio;
         inliningSize = compilation.method.codeSize();
-        for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) {
+
+        if (hints != null) {
+            newInvokes.addAll(hints);
+        } else {
             for (Invoke invoke : graph.getNodes(Invoke.class)) {
-                RiMethod parent = parentMethod.get(invoke);
-                if (parent == null) {
-                    parent = compilation.method;
-                }
-                RiTypeProfile profile = parent.typeProfile(invoke.bci);
-                if (!checkInvokeConditions(invoke)) {
-                    continue;
-                }
-                if (invoke.target.canBeStaticallyBound()) {
-                    if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) {
-                        addToQueue(invoke, invoke.target);
+                newInvokes.add(invoke);
+            }
+        }
+
+        for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) {
+            Queue<Invoke> queue = newInvokes;
+            newInvokes = new ArrayDeque<Invoke>();
+            for (Invoke invoke : queue) {
+                if (!invoke.isDeleted()) {
+                    inlineInvoke(invoke, iterations, ratio);
+                    if (inliningSize > GraalOptions.MaximumInstructionCount) {
+                        break;
                     }
-                } else {
-                    RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
-                    if (concrete != null) {
-                        if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
-                            if (trace) {
-                                String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false);
-                                String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false);
-                                TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName);
-                            }
-                            compilation.assumptions.recordConcreteMethod(invoke.target, concrete);
-                            addToQueue(invoke, concrete);
-                        }
-                    } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) {
-                        if (GraalOptions.InlineWithTypeCheck) {
-                            // type check and inlining...
-                            concrete = profile.types[0].resolveMethodImpl(invoke.target);
-                            if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
-                                IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph);
-                                FixedGuard guard = new FixedGuard(graph);
-                                guard.setNode(isType);
-                                assert invoke.predecessors().size() == 1;
-                                invoke.predecessors().get(0).successors().replace(invoke, guard);
-                                guard.setNext(invoke);
-
-                                if (trace) {
-                                    TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]);
-                                }
-                                addToQueue(invoke, concrete);
-                            }
-                        }
-                    }
-                }
-                if (inliningSize > GraalOptions.MaximumInstructionCount) {
-                    break;
                 }
             }
 
@@ -157,16 +135,65 @@
         }
     }
 
+    private void inlineInvoke(Invoke invoke, int iterations, float ratio) {
+        RiMethod parent = invoke.stateAfter().method();
+        RiTypeProfile profile = parent.typeProfile(invoke.bci);
+        if (!checkInvokeConditions(invoke)) {
+            return;
+        }
+        if (invoke.opcode() == Bytecodes.INVOKESPECIAL || invoke.target.canBeStaticallyBound()) {
+            if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) {
+                addToQueue(invoke, invoke.target);
+            }
+        } else {
+            RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
+            if (concrete != null) {
+                if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
+                    if (trace) {
+                        String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false);
+                        String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false);
+                        TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName);
+                    }
+                    compilation.assumptions.recordConcreteMethod(invoke.target, concrete);
+                    addToQueue(invoke, concrete);
+                }
+            } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) {
+                if (GraalOptions.InlineWithTypeCheck) {
+                    // type check and inlining...
+                    concrete = profile.types[0].resolveMethodImpl(invoke.target);
+                    if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
+                        IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph);
+                        FixedGuard guard = new FixedGuard(graph);
+                        guard.setNode(isType);
+                        assert invoke.predecessors().size() == 1;
+                        invoke.predecessors().get(0).successors().replace(invoke, guard);
+                        guard.setNext(invoke);
+
+                        if (trace) {
+                            TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]);
+                        }
+                        addToQueue(invoke, concrete);
+                    }
+                } else {
+                    if (trace) {
+                        TTY.println("not inlining %s because GraalOptions.InlineWithTypeCheck is false", methodName(invoke.target, invoke));
+                    }
+                }
+            } else {
+            if (trace) {
+                TTY.println("not inlining %s because no monomorphic receiver could be found", methodName(invoke.target, invoke));
+            }
+        }
+        }
+    }
+
     private String methodName(RiMethod method) {
         return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
     }
 
     private String methodName(RiMethod method, Invoke invoke) {
         if (invoke != null) {
-            RiMethod parent = parentMethod.get(invoke);
-            if (parent == null) {
-                parent = compilation.method;
-            }
+            RiMethod parent = invoke.stateAfter().method();
             return parent.name() + "@" + invoke.bci + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
         } else {
             return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
@@ -241,7 +268,11 @@
     }
 
     private boolean checkStaticSizeConditions(RiMethod method, Invoke invoke) {
-        if (method.codeSize() > GraalOptions.MaximumInlineSize) {
+        int maximumSize = GraalOptions.MaximumInlineSize;
+        if (hints != null && hints.contains(invoke)) {
+            maximumSize = GraalOptions.MaximumFreqInlineSize;
+        }
+        if (method.codeSize() > maximumSize) {
             if (trace) {
                 TTY.println("not inlining %s because of code size (size: %d, max size: %d)", methodName(method, invoke), method.codeSize(), GraalOptions.MaximumInlineSize);
             }
@@ -254,10 +285,7 @@
         int maximumSize = GraalOptions.MaximumTrivialSize;
         float ratio = 0;
         if (profile != null && profile.count > 0) {
-            RiMethod parent = parentMethod.get(invoke);
-            if (parent == null) {
-                parent = compilation.method;
-            }
+            RiMethod parent = invoke.stateAfter().method();
             ratio = profile.count / (float) parent.invocationCount();
             if (ratio >= GraalOptions.FreqInlineRatio) {
                 maximumSize = GraalOptions.MaximumFreqInlineSize;
@@ -265,6 +293,9 @@
                 maximumSize = GraalOptions.MaximumInlineSize;
             }
         }
+        if (hints != null && hints.contains(invoke)) {
+            maximumSize = GraalOptions.MaximumFreqInlineSize;
+        }
         if (method.codeSize() > maximumSize) {
             if (trace) {
                 TTY.println("not inlining %s because of code size (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile);
@@ -359,7 +390,7 @@
 
         for (Node node : duplicates.values()) {
             if (node instanceof Invoke) {
-                parentMethod.put((Invoke) node, method);
+                newInvokes.add((Invoke) node);
             }
         }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java	Mon Jun 27 17:15:12 2011 +0200
@@ -24,6 +24,7 @@
 
 import java.util.*;
 
+import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.ir.*;
 import com.oracle.max.graal.graph.*;
 
@@ -178,4 +179,46 @@
     public void setInstructions(List<Node> instructions) {
         this.instructions = instructions;
     }
+
+    public static void iteratePostOrder(List<Block> blocks, BlockClosure closure) {
+        ArrayList<Block> startBlocks = new ArrayList<Block>();
+        for (Block block : blocks) {
+            if (block.getPredecessors().size() == 0) {
+                startBlocks.add(block);
+            }
+        }
+        iteratePostOrder(blocks, closure, startBlocks.toArray(new Block[startBlocks.size()]));
+    }
+
+    public static void iteratePostOrder(List<Block> blocks, BlockClosure closure, Block... startBlocks) {
+        BitMap visited = new BitMap(blocks.size());
+        LinkedList<Block> workList = new LinkedList<Block>();
+        for (Block block : startBlocks) {
+            workList.add(block);
+            visited.set(block.blockID());
+        }
+
+        while (!workList.isEmpty()) {
+            Block b = workList.remove();
+
+            closure.apply(b);
+
+            for (Block succ : b.getSuccessors()) {
+                if (!visited.get(succ.blockID())) {
+                    boolean delay = false;
+                    for (Block pred : succ.getPredecessors()) {
+                        if (!visited.get(pred.blockID()) && !(pred.lastNode instanceof LoopEnd)) {
+                            delay = true;
+                            break;
+                        }
+                    }
+
+                    if (!delay) {
+                        visited.set(succ.blockID());
+                        workList.add(succ);
+                    }
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Fri Jun 24 15:01:20 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Mon Jun 27 17:15:12 2011 +0200
@@ -121,6 +121,10 @@
         return rethrowException;
     }
 
+    public RiMethod method() {
+        return method;
+    }
+
     /**
      * Gets a copy of this frame state.
      */