changeset 4507:9d640941c9c7

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Tue, 07 Feb 2012 21:09:31 +0100
parents ab7c258e1cef 58ecb156a3e8
children 7e8c901c0009
files
diffstat 68 files changed, 2127 insertions(+), 556 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sun Feb 05 05:40:36 2012 +0100
+++ b/.hgignore	Tue Feb 07 21:09:31 2012 +0100
@@ -36,6 +36,7 @@
 /nbproject/private/
 ^graal/hotspot/java$
 ^scratch/
+^test-output/
 scratch/
 bin/
 ^local/
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Tue Feb 07 21:09:31 2012 +0100
@@ -311,6 +311,7 @@
     }
 
     public CiConstant readUnsafeConstant(Object value, long displacement) {
+        assert value != null;
         Unsafe u = Unsafe.getUnsafe();
         switch(this) {
             case Boolean:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java	Tue Feb 07 21:09:31 2012 +0100
@@ -0,0 +1,64 @@
+/*
+ * 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.max.cri.ri;
+
+
+/**
+ * Represents profiling information for one specific method.
+ * Every accessor method returns the information that is available at the time of its invocation.
+ * If a method is invoked multiple times, it may return a significantly different results for every invocation.
+ */
+public interface RiProfilingInfo {
+    /**
+     * Returns an estimate of how often the branch at the given byte code was taken.
+     * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if this information is not available.
+     */
+    double getBranchTakenProbability(int bci);
+
+    /**
+     * Returns an estimate of how often the switch cases are taken at the given BCI.
+     * The default case is stored as the last entry.
+     * @return A double value that contains the estimated probabilities, with 0.0 meaning never and 1.0 meaning always,
+     * or -1 if this information is not available.
+     */
+    double[] getSwitchProbabilities(int bci);
+
+    /**
+     * Returns the TypeProfile for the given BCI.
+     * @return Returns an RiTypeProfile object, or null if not available.
+     */
+    RiTypeProfile getTypeProfile(int bci);
+
+    /**
+     * Returns true if the instruction at least once an exception was thrown at the given BCI.
+     * @return true if an exception was encountered during profiling, false otherwise.
+     */
+    boolean getExceptionSeen(int bci);
+
+    /**
+     * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts to each other,
+     * as the returned value highly depends on the time of invocation.
+     * @return the estimated execution count or -1 if not available.
+     */
+    int getExecutionCount(int bci);
+}
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java	Tue Feb 07 21:09:31 2012 +0100
@@ -159,29 +159,10 @@
     int invocationCount();
 
     /**
-     * Returns an estimate of hot often an exception was seen at the given bytecode.
-     * @return The estimate in percent (0-100), with 0 meaning never and 100 meaning always, or -1 if this information isn't available.
+     * Returns an object that provides access to the method's profiling information.
+     * @return The profiling information recorded for this method.
      */
-    int exceptionProbability(int bci);
-
-    /**
-     * Returns the type profile of the instruction at the given byte code index.
-     * @return The RiTypeProfile information, or null if it isn't available.
-     */
-    RiTypeProfile typeProfile(int bci);
-
-    /**
-     * Returns an estimate of how often the branch at the given byte code was taken.
-     * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if this information isn't available.
-     */
-    double branchProbability(int bci);
-
-    /**
-     * Returns an estimate of how often the branches of the switch at the given byte code were taken.
-     * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or NULL if this information isn't available.
-     * The default case is specified at the last index.
-     */
-    double[] switchProbability(int bci);
+    RiProfilingInfo profilingInfo();
 
     /**
      * Returns a map that the compiler can use to store objects that should survive the current compilation.
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java	Tue Feb 07 21:09:31 2012 +0100
@@ -25,37 +25,47 @@
 import java.io.*;
 
 /**
- * This profile object represents the type profile of one call site, cast or instanceof instruction. The precision of
- * the supplied values may vary, but a runtime that provides this information should be aware that it will be used to
- * guide performance-critical decisions like speculative inlining, etc.
+ * This profile object represents the type profile at a specific BCI. The precision of the supplied values may vary,
+ * but a runtime that provides this information should be aware that it will be used to guide performance-critical
+ * decisions like speculative inlining, etc.
  */
-public class RiTypeProfile implements Serializable {
-
+public final class RiTypeProfile implements Serializable {
     /**
-     * 
+     *
      */
     private static final long serialVersionUID = -6877016333706838441L;
 
-    /**
-     * How often the instruction was executed, which may be used to judge the maturity of this profile.
-     */
-    public int count;
+    private final RiResolvedType[] types;
+    private final double notRecordedProbability;
+    private final double[] probabilities;
+
+    public RiTypeProfile(RiResolvedType[] types, double notRecordedProbability, double[] probabilites) {
+        this.types = types;
+        this.notRecordedProbability = notRecordedProbability;
+        this.probabilities = probabilites;
+    }
 
     /**
-     * An estimation of how many different receiver types were encountered. This may or may not be the same as
-     * probabilities.length/types.length, as the runtime may store probabilities for a limited number of receivers.
+     * The estimated probabilities of the different receivers. This array needs to have the same length as the array returned by
+     * {@link RiTypeProfile#types}.
      */
-    public int morphism;
+    public double[] getProbabilities() {
+        return probabilities;
+    }
+
+    /**
+     * Returns the estimated probability of all types that could not be recorded due to profiling limitations.
+     * @return double value >= 0.0 and <= 1.0
+     */
+    public double getNotRecordedProbability() {
+        return notRecordedProbability;
+    }
 
     /**
      * A list of receivers for which the runtime has recorded probability information. This array needs to have the same
      * length as {@link RiTypeProfile#probabilities}.
      */
-    public RiResolvedType[] types;
-
-    /**
-     * The estimated probabilities of the different receivers. This array needs to have the same length as
-     * {@link RiTypeProfile#types}.
-     */
-    public float[] probabilities;
+    public RiResolvedType[] getTypes() {
+        return types;
+    }
 }
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Tue Feb 07 21:09:31 2012 +0100
@@ -102,12 +102,12 @@
      * an object is identical to a given hub constant. In pseudo code:
      * <pre>
      *     if (object.getHub() != hub) {
-     *         uncommonTrap();
+     *       jump(falseSuccessor)
      *     }
      * </pre>
      * This snippet should only be used when the object is guaranteed not to be null.
      */
-    XirSnippet genTypeCheck(XirSite site, XirArgument object, XirArgument hub, RiType type);
+    XirSnippet genTypeBranch(XirSite site, XirArgument thisHub, XirArgument otherHub, RiType type);
 
     /**
      * Initializes the XIR generator for the given XIR assembler.
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java	Tue Feb 07 21:09:31 2012 +0100
@@ -81,7 +81,7 @@
         if (osrBCI != -1) {
             throw new CiBailout("No OSR supported");
         }
-        return Debug.scope(createScopeName(method), method, new Callable<CiTargetMethod>() {
+        return Debug.scope(createScopeName(method), new Callable<CiTargetMethod>() {
             public CiTargetMethod call() {
                 final CiAssumptions assumptions = GraalOptions.OptAssumptions ? new CiAssumptions() : null;
                 final LIR lir = Debug.scope("FrontEnd", graph, new Callable<LIR>() {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Tue Feb 07 21:09:31 2012 +0100
@@ -42,9 +42,12 @@
     public static boolean Inline                             = true;
     public static boolean Intrinsify                         = true;
     public static boolean CacheGraphs                        = ____;
-    public static boolean InlineWithTypeCheck                = ____;
+    public static boolean InlineMonomorphicCalls             = true;
+    public static boolean InlinePolymorphicCalls             = true;
+    public static int     InliningPolicy                     = 0;
     public static int     MaximumInlineSize                  = 35;
     public static int     MaximumFreqInlineSize              = 300;
+    public static float   NestedInliningSizeRatio            = 0.9f;
     public static int     FreqInlineRatio                    = 20;
     public static int     MaximumTrivialSize                 = 6;
     public static int     MaximumInlineLevel                 = 30;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Tue Feb 07 21:09:31 2012 +0100
@@ -701,9 +701,7 @@
 
     @Override
     public void emitGuardCheck(BooleanNode comp) {
-        if (comp instanceof IsTypeNode) {
-            emitTypeGuard((IsTypeNode) comp);
-        } else if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) {
+        if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) {
             emitNullCheckGuard((NullCheckNode) comp);
         } else if (comp instanceof ConstantNode && comp.asConstant().asBoolean()) {
             // True constant, nothing to emit.
@@ -717,15 +715,6 @@
 
     protected abstract void emitNullCheckGuard(NullCheckNode node);
 
-    private void emitTypeGuard(IsTypeNode node) {
-        load(operand(node.object()));
-        LIRDebugInfo info = state();
-        XirArgument clazz = toXirArgument(node.type().getEncoding(Representation.ObjectHub));
-        XirSnippet typeCheck = xir.genTypeCheck(site(node), toXirArgument(node.object()), clazz, node.type());
-        emitXir(typeCheck, node, info, false);
-    }
-
-
     public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
         if (node instanceof NullCheckNode) {
             emitNullCheckBranch((NullCheckNode) node, trueSuccessor, falseSuccessor, info);
@@ -735,6 +724,8 @@
             emitInstanceOfBranch((InstanceOfNode) node, trueSuccessor, falseSuccessor, info);
         } else if (node instanceof ConstantNode) {
             emitConstantBranch(((ConstantNode) node).asConstant().asBoolean(), trueSuccessor, falseSuccessor, info);
+        } else if (node instanceof IsTypeNode) {
+            emitTypeBranch((IsTypeNode) node, trueSuccessor, falseSuccessor, info);
         } else {
             throw Util.unimplemented(node.toString());
         }
@@ -761,7 +752,6 @@
         emitXir(snippet, x, info, null, false, x.negated() ? falseSuccessor : trueSuccessor, x.negated() ? trueSuccessor : falseSuccessor);
     }
 
-
     public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) {
         LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock;
         if (block != null) {
@@ -769,6 +759,16 @@
         }
     }
 
+    public void emitTypeBranch(IsTypeNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+        XirArgument thisClass = toXirArgument(x.objectClass());
+        XirArgument otherClass = toXirArgument(x.type().getEncoding(Representation.ObjectHub));
+        XirSnippet snippet = xir.genTypeBranch(site(x), thisClass, otherClass, x.type());
+        emitXir(snippet, x, info, null, false, trueSuccessor, falseSuccessor);
+        if (trueSuccessor != null) {
+            emitJump(trueSuccessor, null);
+        }
+    }
+
     @Override
     public void emitConditional(ConditionalNode conditional) {
         CiValue tVal = operand(conditional.trueValue());
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java	Tue Feb 07 21:09:31 2012 +0100
@@ -219,7 +219,7 @@
                         pred.replaceFirstSuccessor(replacedSux, next);
                         FrameState stateAfter = merge.stateAfter();
                         merge.setStateAfter(null);
-                        if (stateAfter.usages().isEmpty()) {
+                        if (stateAfter != null && stateAfter.usages().isEmpty()) {
                             stateAfter.safeDelete();
                         }
                         merge.safeDelete();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Tue Feb 07 21:09:31 2012 +0100
@@ -316,7 +316,7 @@
                 assert ((NullCheckNode) usage).object() == node;
                 return null;
             } else if (usage instanceof IsTypeNode) {
-                assert ((IsTypeNode) usage).object() == node;
+                assert ((IsTypeNode) usage).objectClass() == node;
                 return null;
             } else if (usage instanceof AccessMonitorNode) {
                 assert ((AccessMonitorNode) usage).object() == node;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Tue Feb 07 21:09:31 2012 +0100
@@ -53,6 +53,7 @@
     private CiAssumptions assumptions;
 
     private final PhasePlan plan;
+    private final InliningPolicy inliningPolicy;
 
     // Metrics
     private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
@@ -64,6 +65,7 @@
         this.hints = hints;
         this.assumptions = assumptions;
         this.plan = plan;
+        this.inliningPolicy = createInliningPolicy();
     }
 
     @SuppressWarnings("unchecked")
@@ -80,39 +82,36 @@
 
         while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) {
             InlineInfo info = inlineCandidates.remove();
-            double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, graph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp;
-            if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) {
-                Debug.log("not inlining (cut off by weight): %e", info.weight);
-                return;
-            }
-            Iterable<Node> newNodes = null;
-            if (info.invoke.node().isAlive()) {
-                try {
-                    info.inline(graph, runtime, this);
-                    Debug.log("inlining %f: %s", info.weight, info);
-                    Debug.dump(graph, "after inlining %s", info);
-                    // get the new nodes here, the canonicalizer phase will reset the mark
-                    newNodes = graph.getNewNodes();
-                    if (GraalOptions.OptCanonicalizer) {
-                        new CanonicalizerPhase(target, runtime, true, assumptions).apply(graph);
+            if (inliningPolicy.isWorthInlining(graph, info)) {
+                Iterable<Node> newNodes = null;
+                if (info.invoke.node().isAlive()) {
+                    try {
+                        info.inline(graph, runtime, this);
+                        Debug.log("inlining %f: %s", info.weight, info);
+                        Debug.dump(graph, "after inlining %s", info);
+                        // get the new nodes here, the canonicalizer phase will reset the mark
+                        newNodes = graph.getNewNodes();
+                        if (GraalOptions.OptCanonicalizer) {
+                            new CanonicalizerPhase(target, runtime, true, assumptions).apply(graph);
+                        }
+                        if (GraalOptions.Intrinsify) {
+                            new IntrinsificationPhase(runtime).apply(graph);
+                        }
+                        metricInliningPerformed.increment();
+                    } catch (CiBailout 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 (GraalOptions.Intrinsify) {
-                        new IntrinsificationPhase(runtime).apply(graph);
-                    }
-                    metricInliningPerformed.increment();
-                } catch (CiBailout 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, info.level + 1, graph);
+                if (newNodes != null && info.level <= GraalOptions.MaximumInlineLevel) {
+                    scanInvokes(newNodes, info.level + 1, graph);
+                }
             }
         }
     }
@@ -160,61 +159,10 @@
 
     @Override
     public double inliningWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke) {
-        double ratio;
-        if (hints != null && hints.contains(invoke)) {
-            ratio = 1000000;
-        } else {
-            if (GraalOptions.ProbabilityAnalysis) {
-                ratio = invoke.node().probability();
-            } else {
-                RiTypeProfile profile = caller.typeProfile(invoke.bci());
-                if (profile != null && profile.count > 0) {
-                    RiResolvedMethod parent = invoke.stateAfter().method();
-                    ratio = profile.count / (float) parent.invocationCount();
-                } else {
-                    ratio = 1;
-                }
-            }
-        }
-
-        final double normalSize;
-        // TODO(ls) get rid of this magic, it's here to emulate the old behavior for the time being
-        if (ratio < 0.01) {
-            ratio = 0.01;
-        }
-        if (ratio < 0.5) {
-            normalSize = 10 * ratio / 0.5;
-        } else if (ratio < 2) {
-            normalSize = 10 + (35 - 10) * (ratio - 0.5) / 1.5;
-        } else if (ratio < 20) {
-            normalSize = 35;
-        } else if (ratio < 40) {
-            normalSize = 35 + (350 - 35) * (ratio - 20) / 20;
-        } else {
-            normalSize = 350;
-        }
-
-        int count;
-        if (GraalOptions.ParseBeforeInlining) {
-            if (!parsedMethods.containsKey(method)) {
-                StructuredGraph newGraph = new StructuredGraph(method);
-                if (plan != null) {
-                    plan.runPhases(PhasePosition.AFTER_PARSING, newGraph);
-                }
-                new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph);
-                count = graphComplexity(newGraph);
-                parsedMethods.put(method, count);
-            } else {
-                count = parsedMethods.get(method);
-            }
-        } else {
-            count = method.codeSize();
-        }
-
-        return count / normalSize;
+        boolean preferred = hints != null && hints.contains(invoke);
+        return inliningPolicy.computeWeight(caller, method, invoke, preferred);
     }
 
-
     public static int graphComplexity(StructuredGraph graph) {
         int result = 0;
         for (Node node : graph.getNodes()) {
@@ -239,4 +187,105 @@
         assumptions.recordConcreteMethod(method, context, impl);
     }
 
+    private InliningPolicy createInliningPolicy() {
+        if (GraalOptions.InliningPolicy == 0) {
+            return new WeightBasedInliningPolicy();
+        } else if (GraalOptions.InliningPolicy == 1) {
+            return new SizeBasedInliningPolicy();
+        } else {
+            Util.shouldNotReachHere();
+            return null;
+        }
+    }
+
+    private interface InliningPolicy {
+        double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke);
+        boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info);
+    }
+
+    private class WeightBasedInliningPolicy implements InliningPolicy {
+        @Override
+        public double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke) {
+            double ratio;
+            if (preferredInvoke) {
+                ratio = 1000000;
+            } else {
+                if (GraalOptions.ProbabilityAnalysis) {
+                    ratio = invoke.node().probability();
+                } else {
+                    RiProfilingInfo profilingInfo = method.profilingInfo();
+                    int executionCount = profilingInfo.getExecutionCount(invoke.bci());
+                    if (executionCount > 0) {
+                        RiResolvedMethod parent = invoke.stateAfter().method();
+                        ratio = executionCount / (float) parent.invocationCount();
+                    } else {
+                        ratio = 1;
+                    }
+                }
+            }
+
+            final double normalSize;
+            // TODO(ls) get rid of this magic, it's here to emulate the old behavior for the time being
+            if (ratio < 0.01) {
+                ratio = 0.01;
+            }
+            if (ratio < 0.5) {
+                normalSize = 10 * ratio / 0.5;
+            } else if (ratio < 2) {
+                normalSize = 10 + (35 - 10) * (ratio - 0.5) / 1.5;
+            } else if (ratio < 20) {
+                normalSize = 35;
+            } else if (ratio < 40) {
+                normalSize = 35 + (350 - 35) * (ratio - 20) / 20;
+            } else {
+                normalSize = 350;
+            }
+
+            int count;
+            if (GraalOptions.ParseBeforeInlining) {
+                if (!parsedMethods.containsKey(method)) {
+                    StructuredGraph newGraph = new StructuredGraph(method);
+                    if (plan != null) {
+                        plan.runPhases(PhasePosition.AFTER_PARSING, newGraph);
+                    }
+                    new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph);
+                    count = graphComplexity(newGraph);
+                    parsedMethods.put(method, count);
+                } else {
+                    count = parsedMethods.get(method);
+                }
+            } else {
+                count = method.codeSize();
+            }
+
+            return count / normalSize;
+        }
+
+        @Override
+        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
+            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 (cut off by weight): %e", info.weight);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    private class SizeBasedInliningPolicy implements InliningPolicy {
+        @Override
+        public double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke) {
+            if (preferredInvoke) {
+                return method.codeSize() / 2;
+            } else {
+                return method.codeSize();
+            }
+        }
+
+        @Override
+        public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
+            double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize);
+            return info.weight <= maxSize;
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java	Tue Feb 07 21:09:31 2012 +0100
@@ -34,7 +34,9 @@
 import com.oracle.max.graal.graph.*;
 import com.oracle.max.graal.nodes.*;
 import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction;
+import com.oracle.max.graal.nodes.PhiNode.PhiType;
 import com.oracle.max.graal.nodes.calc.*;
+import com.oracle.max.graal.nodes.extended.*;
 import com.oracle.max.graal.nodes.java.*;
 import com.oracle.max.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.max.graal.nodes.util.*;
@@ -85,6 +87,15 @@
             return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0;
         }
 
+        protected static StructuredGraph getGraph(final RiResolvedMethod concrete, final InliningCallback callback) {
+            return Debug.scope("Inlining", concrete, new Callable<StructuredGraph>() {
+                @Override
+                public StructuredGraph call() throws Exception {
+                    return callback.buildGraph(concrete);
+                }
+            });
+        }
+
         public abstract boolean canDeopt();
 
         /**
@@ -94,10 +105,8 @@
          * @param graph
          * @param runtime
          * @param callback
-         * @return The node that represents the return value, or null for void methods and methods that have no
-         *         non-exceptional exit.
          */
-        public abstract Node inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback);
+        public abstract void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback);
     }
 
     /**
@@ -113,14 +122,9 @@
         }
 
         @Override
-        public Node inline(StructuredGraph compilerGraph, GraalRuntime runtime, final InliningCallback callback) {
-            StructuredGraph graph = Debug.scope("Inlining", concrete, new Callable<StructuredGraph>() {
-                @Override
-                public StructuredGraph call() throws Exception {
-                    return callback.buildGraph(concrete);
-                }
-            });
-            return InliningUtil.inline(invoke, graph, true);
+        public void inline(StructuredGraph compilerGraph, GraalRuntime runtime, final InliningCallback callback) {
+            StructuredGraph graph = getGraph(concrete, callback);
+            InliningUtil.inline(invoke, graph, true);
         }
 
         @Override
@@ -138,26 +142,32 @@
      * 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 ExactInlineInfo {
+    private static class TypeGuardInlineInfo extends InlineInfo {
+        public final RiResolvedMethod concrete;
+        public final RiResolvedType type;
 
-        public final RiResolvedType type;
-        public final double probability;
-
-        public TypeGuardInlineInfo(Invoke invoke, double weight, int level, RiResolvedMethod concrete, RiResolvedType type, double probability) {
-            super(invoke, weight, level, concrete);
+        public TypeGuardInlineInfo(Invoke invoke, double weight, int level, RiResolvedMethod concrete, RiResolvedType type) {
+            super(invoke, weight, level);
+            this.concrete = concrete;
             this.type = type;
-            this.probability = probability;
         }
 
         @Override
-        public Node inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) {
-            IsTypeNode isType = graph.unique(new IsTypeNode(invoke.callTarget().receiver(), type));
-            FixedGuardNode guard = graph.add(new FixedGuardNode(isType));
+        public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) {
+            // receiver null check must be before the type check
+            InliningUtil.receiverNullCheck(invoke);
+            ReadHubNode objectClass = graph.add(new ReadHubNode(invoke.callTarget().receiver()));
+            IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClass, type));
+            FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode));
             assert invoke.predecessor() != null;
+
+            graph.addBeforeFixed(invoke.node(), objectClass);
             graph.addBeforeFixed(invoke.node(), guard);
 
-            Debug.log("inlining with type check, type probability: %5.3f", probability);
-            return super.inline(graph, runtime, callback);
+            Debug.log("inlining 1 method using 1 type check");
+
+            StructuredGraph calleeGraph = getGraph(concrete, callback);
+            InliningUtil.inline(invoke, calleeGraph, false);
         }
 
         @Override
@@ -172,6 +182,240 @@
     }
 
     /**
+     * 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<RiResolvedMethod> concretes;
+        public final RiResolvedType[] types;
+        public final int[] typesToConcretes;
+        public final double[] branchProbabilities;
+        public final double notRecordedTypeProbability;
+
+        public MultiTypeGuardInlineInfo(Invoke invoke, double weight, int level, List<RiResolvedMethod> concretes, RiResolvedType[] types,
+                        int[] typesToConcretes, double[] branchProbabilities, double notRecordedTypeProbability) {
+            super(invoke, weight, level);
+            assert concretes.size() > 0 && concretes.size() <= types.length : "must have at least one method but no more than types methods";
+            assert types.length == typesToConcretes.length && types.length == branchProbabilities.length : "array length must match";
+
+            this.concretes = concretes;
+            this.types = types;
+            this.typesToConcretes = typesToConcretes;
+            this.branchProbabilities = branchProbabilities;
+            this.notRecordedTypeProbability = notRecordedTypeProbability;
+        }
+
+        @Override
+        public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) {
+            int numberOfMethods = concretes.size();
+            boolean hasReturnValue = invoke.node().kind() != CiKind.Void;
+
+            // receiver null check must be the first node
+            InliningUtil.receiverNullCheck(invoke);
+            if (numberOfMethods > 1 || shouldFallbackToInvoke()) {
+                inlineMultipleMethods(graph, callback, numberOfMethods, hasReturnValue);
+            } else {
+                inlineSingleMethod(graph, callback);
+            }
+
+            Debug.log("inlining %d methods with %d type checks and falling back to %s if violated", numberOfMethods, types.length, shouldFallbackToInvoke() ? "invocation" : "deoptimization");
+        }
+
+        private boolean shouldFallbackToInvoke() {
+            return notRecordedTypeProbability > 0;
+        }
+
+        private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, int numberOfMethods, boolean hasReturnValue) {
+            FixedNode continuation = invoke.next();
+
+            // setup merge and phi nodes for results and exceptions
+            MergeNode returnMerge = graph.add(new MergeNode());
+            returnMerge.setProbability(invoke.probability());
+            returnMerge.setStateAfter(invoke.stateAfter());
+
+            PhiNode returnValuePhi = null;
+            if (hasReturnValue) {
+                returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge, PhiType.Value));
+            }
+
+            MergeNode exceptionMerge = null;
+            PhiNode exceptionObjectPhi = null;
+            if (invoke instanceof InvokeWithExceptionNode) {
+                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+
+                exceptionMerge = graph.add(new MergeNode());
+                exceptionMerge.setProbability(exceptionEdge.probability());
+                exceptionMerge.setStateAfter(exceptionEdge.stateAfter());
+
+                FixedNode exceptionSux = exceptionObject.next();
+                graph.addBeforeFixed(exceptionSux, exceptionMerge);
+                exceptionObjectPhi = graph.unique(new PhiNode(CiKind.Object, exceptionMerge, PhiType.Value));
+            }
+
+            // create one separate block for each invoked method
+            BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods];
+            for (int i = 0; i < numberOfMethods; i++) {
+                int predecessors = getPredecessorCount(i);
+                calleeEntryNodes[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, predecessors, true);
+            }
+
+            // create the successor for an unknown type
+            FixedNode unknownTypeNode;
+            if (shouldFallbackToInvoke()) {
+                unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, false);
+            } else {
+                unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile));
+            }
+
+            // 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 cascade of if nodes
+            ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.callTarget().receiver()));
+            graph.addBeforeFixed(invoke.node(), objectClassNode);
+            FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, calleeEntryNodes, unknownTypeNode);
+
+            assert invoke.next() == continuation;
+            invoke.setNext(null);
+            returnMerge.setNext(continuation);
+            invoke.node().replaceAtUsages(returnValuePhi);
+            invoke.node().replaceAndDelete(dispatchOnType);
+
+            // do the actual inlining for every invoke
+            for (int i = 0; i < calleeEntryNodes.length; i++) {
+                BeginNode node = calleeEntryNodes[i];
+                Invoke invokeForInlining = (Invoke) node.next();
+                StructuredGraph calleeGraph = getGraph(concretes.get(i), callback);
+                InliningUtil.inline(invokeForInlining, calleeGraph, false);
+            }
+        }
+
+        private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback) {
+            assert concretes.size() == 1 && types.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+
+            MergeNode calleeEntryNode = graph.add(new MergeNode());
+            calleeEntryNode.setProbability(invoke.probability());
+            ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.callTarget().receiver()));
+            graph.addBeforeFixed(invoke.node(), objectClassNode);
+
+            FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile));
+            FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, new BeginNode[] {calleeEntryNode}, unknownTypeNode);
+
+            FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor();
+            pred.setNext(dispatchOnType);
+            calleeEntryNode.setNext(invoke.node());
+
+            StructuredGraph calleeGraph = getGraph(concretes.get(0), callback);
+            InliningUtil.inline(invoke, calleeGraph, false);
+        }
+
+        private FixedNode createDispatchOnType(StructuredGraph graph, ReadHubNode objectClassNode, BeginNode[] calleeEntryNodes, FixedNode unknownTypeSux) {
+            assert types.length > 1;
+
+            // TODO (ch) set probabilities for all created fixed nodes...
+            int lastIndex = types.length - 1;
+            FixedNode nextNode = createTypeCheck(graph, objectClassNode, types[lastIndex], calleeEntryNodes[typesToConcretes[lastIndex]], unknownTypeSux, branchProbabilities[lastIndex]);
+            for (int i = lastIndex - 1; i >= 0; i--) {
+                nextNode = createTypeCheck(graph, objectClassNode, types[i], calleeEntryNodes[typesToConcretes[i]], nextNode, branchProbabilities[i]);
+            }
+
+            return nextNode;
+        }
+
+        private static FixedNode createTypeCheck(StructuredGraph graph, ReadHubNode objectClassNode, RiResolvedType type, BeginNode tsux, FixedNode nextNode, double tsuxProbability) {
+            IfNode result;
+            IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClassNode, type));
+            if (tsux instanceof MergeNode) {
+                EndNode endNode = graph.add(new EndNode());
+                result = graph.add(new IfNode(isTypeNode, endNode, nextNode, tsuxProbability));
+                ((MergeNode) tsux).addEnd(endNode);
+            } else {
+                result = graph.add(new IfNode(isTypeNode, tsux, nextNode, tsuxProbability));
+            }
+            return result;
+        }
+
+        private int getPredecessorCount(int concreteMethodIndex) {
+            if (concretes.size() == types.length) {
+                return 1;
+            } else {
+                int count = 0;
+                for (int i = 0; i < typesToConcretes.length; i++) {
+                    if (typesToConcretes[i] == concreteMethodIndex) {
+                        count++;
+                    }
+                }
+                return count;
+            }
+        }
+
+        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi,
+                        MergeNode exceptionMerge, PhiNode exceptionObjectPhi, int predecessors, boolean useForInlining) {
+            Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
+            // TODO (ch) set probabilities
+            BeginNode calleeEntryNode = graph.add(predecessors > 1 ? new MergeNode() : new BeginNode());
+            calleeEntryNode.setNext(duplicatedInvoke.node());
+
+            EndNode endNode = graph.add(new EndNode());
+            // TODO (ch) set probability
+            duplicatedInvoke.setNext(endNode);
+            returnMerge.addEnd(endNode);
+            if (returnValuePhi != null) {
+                returnValuePhi.addInput(duplicatedInvoke.node());
+            }
+            return calleeEntryNode;
+        }
+
+        private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
+            Invoke result = (Invoke) invoke.node().copyWithInputs();
+            result.setUseForInlining(useForInlining);
+            if (invoke instanceof InvokeWithExceptionNode) {
+                assert exceptionMerge != null && exceptionObjectPhi != null;
+
+                InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
+
+                BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs();
+                ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs();
+                newExceptionEdge.setNext(newExceptionObject);
+
+                EndNode endNode = graph.add(new EndNode());
+                newExceptionObject.setNext(endNode);
+                exceptionMerge.addEnd(endNode);
+                exceptionObjectPhi.addInput(newExceptionObject);
+
+                ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
+            }
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder(String.format("type-checked inlining of %d methods with %d type checks: ", concretes.size(), types.length));
+            for (int i = 0; i < concretes.size(); i++) {
+                builder.append(CiUtil.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.
      */
@@ -184,14 +428,15 @@
         }
 
         @Override
-        public Node inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) {
+        public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) {
             if (Debug.isLogEnabled()) {
                 String targetName = CiUtil.format("%H.%n(%p):%r", invoke.callTarget().targetMethod());
                 String concreteName = CiUtil.format("%H.%n(%p):%r", concrete);
                 Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName);
             }
             callback.recordConcreteMethodAssumption(invoke.callTarget().targetMethod(), context, concrete);
-            return super.inline(graph, runtime, callback);
+
+            super.inline(graph, runtime, callback);
         }
 
         @Override
@@ -248,35 +493,107 @@
             }
         }
         // TODO (tw) fix this
-        if (assumptions == null) {
+        if (assumptions != null) {
+            RiResolvedMethod concrete = holder.uniqueConcreteMethod(callTarget.targetMethod());
+            if (concrete != null) {
+                if (checkTargetConditions(concrete)) {
+                    double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
+                    return new AssumptionInlineInfo(invoke, weight, level, holder, concrete);
+                }
+                return null;
+            }
+        }
+
+        // type check based inlining
+        RiProfilingInfo profilingInfo = parent.profilingInfo();
+        RiTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
+        if (typeProfile != null) {
+            RiResolvedType[] types = typeProfile.getTypes();
+            double[] probabilities = typeProfile.getProbabilities();
+
+            if (types != null && probabilities != null && types.length > 0) {
+                assert types.length == probabilities.length : "length must match";
+                double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
+                if (types.length == 1 && notRecordedTypeProbability == 0) {
+                    if (GraalOptions.InlineMonomorphicCalls) {
+                        RiResolvedType type = types[0];
+                        RiResolvedMethod concrete = type.resolveMethodImpl(callTarget.targetMethod());
+                        if (concrete != null && checkTargetConditions(concrete)) {
+                            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(callTarget.targetMethod(), invoke));
+                        return null;
+                    } else {
+                        Debug.log("not inlining %s because GraalOptions.InlinePolymorphicCalls == false", methodName(callTarget.targetMethod(), invoke));
+                        return null;
+                    }
+                } else {
+                    if (GraalOptions.InlinePolymorphicCalls) {
+                        // TODO (ch) 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 (ch) sort types by probability
+
+                        // determine concrete methods and map type to specific method
+                        ArrayList<RiResolvedMethod> concreteMethods = new ArrayList<>();
+                        int[] typesToConcretes = new int[types.length];
+                        for (int i = 0; i < types.length; i++) {
+                            RiResolvedMethod concrete = types[i].resolveMethodImpl(callTarget.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 (RiResolvedMethod concrete: concreteMethods) {
+                            if (concrete == null || !checkTargetConditions(concrete)) {
+                                canInline = false;
+                                break;
+                            }
+                            totalWeight += callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
+                        }
+
+                        if (canInline) {
+                            convertTypeToBranchProbabilities(probabilities, notRecordedTypeProbability);
+                            return new MultiTypeGuardInlineInfo(invoke, totalWeight, level, concreteMethods, types, typesToConcretes, probabilities, notRecordedTypeProbability);
+                        } else {
+                            Debug.log("not inlining %s because it is a polymorphic method call and at least one invoked method cannot be inlined", methodName(callTarget.targetMethod(), invoke));
+                            return null;
+                        }
+                    } else {
+                        Debug.log("not inlining %s because GraalOptions.InlineMonomorphicCalls == false", methodName(callTarget.targetMethod(), invoke));
+                        return null;
+                    }
+                }
+            }
+
+            Debug.log("not inlining %s because no types/probabilities were recorded", methodName(callTarget.targetMethod(), invoke));
+            return null;
+        } else {
+            Debug.log("not inlining %s because no type profile exists", methodName(callTarget.targetMethod(), invoke));
             return null;
         }
-        RiResolvedMethod concrete = holder.uniqueConcreteMethod(callTarget.targetMethod());
-        if (concrete != null) {
-            if (checkTargetConditions(concrete)) {
-                double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
-                return new AssumptionInlineInfo(invoke, weight, level, holder, concrete);
-            }
-            return null;
+    }
+
+    private static void convertTypeToBranchProbabilities(double[] typeProbabilities, double notRecordedTypeProbability) {
+        // avoid branches with 0.0/1.0 probability
+        double total = Math.max(1E-10, notRecordedTypeProbability);
+
+        for (int i = typeProbabilities.length - 1; i >= 0; i--) {
+            total += typeProbabilities[i];
+            typeProbabilities[i] = typeProbabilities[i] / total;
         }
-        RiTypeProfile profile = parent.typeProfile(invoke.bci());
-        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(callTarget.targetMethod());
-                if (concrete != null && checkTargetConditions(concrete)) {
-                    double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke);
-                    return new TypeGuardInlineInfo(invoke, weight, level, concrete, profile.types[0], profile.probabilities[0]);
-                }
-                return null;
-            } else {
-                Debug.log("not inlining %s because GraalOptions.InlineWithTypeCheck == false", methodName(callTarget.targetMethod(), invoke));
-                return null;
-            }
-        } else {
-            Debug.log("not inlining %s because no monomorphic receiver could be found", methodName(callTarget.targetMethod(), invoke));
-            return null;
-        }
+        assert total > 0.99 && total < 1.01;
     }
 
     private static boolean checkInvokeConditions(Invoke invoke) {
@@ -288,6 +605,10 @@
             Debug.log("not inlining %s because the invoke is dead code", methodName(invoke.callTarget().targetMethod(), invoke));
             return false;
         }
+        if (!invoke.useForInlining()) {
+            Debug.log("not inlining %s because invoke is marked to be not used for inlining", methodName(invoke.callTarget().targetMethod(), invoke));
+            return false;
+        }
         return true;
     }
 
@@ -323,7 +644,7 @@
      * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
      * @return The node that represents the return value, or null for void methods and methods that have no non-exceptional exit.
      */
-    public static Node inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+    public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
         NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
         StructuredGraph graph = (StructuredGraph) invoke.node().graph();
 
@@ -332,7 +653,6 @@
 
         IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
         ArrayList<Node> nodes = new ArrayList<>();
-        ArrayList<Node> frameStates = new ArrayList<>();
         ReturnNode returnNode = null;
         UnwindNode unwindNode = null;
         BeginNode entryPointNode = inlineGraph.start();
@@ -348,8 +668,6 @@
                     returnNode = (ReturnNode) node;
                 } else if (node instanceof UnwindNode) {
                     unwindNode = (UnwindNode) node;
-                } else if (node instanceof FrameState) {
-                    frameStates.add(node);
                 }
             }
         }
@@ -358,11 +676,9 @@
         assert invoke.node().predecessor() != null;
 
         Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
-
         FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
-        MethodCallTargetNode callTarget = invoke.callTarget();
-        if (!callTarget.isStatic() && receiverNullCheck && parameters.get(0).kind() == CiKind.Object && !parameters.get(0).stamp().nonNull()) {
-            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(parameters.get(0), false)))));
+        if (receiverNullCheck) {
+            receiverNullCheck(invoke);
         }
         invoke.node().replaceAtPredecessors(firstCFGNodeDuplicate);
 
@@ -375,9 +691,7 @@
                 ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next();
                 stateAtExceptionEdge = obj.stateAfter();
                 UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                for (Node usage : obj.usages().snapshot()) {
-                    usage.replaceFirstInput(obj, unwindDuplicate.exception());
-                }
+                obj.replaceAtUsages(unwindDuplicate.exception());
                 unwindDuplicate.clearInputs();
                 Node n = obj.next();
                 obj.setNext(null);
@@ -404,6 +718,7 @@
         }
 
         FrameState stateBefore = null;
+        FrameState outerFrameState = null;
         double invokeProbability = invoke.node().probability();
         for (Node node : duplicates.values()) {
             if (GraalOptions.ProbabilityAnalysis) {
@@ -428,6 +743,11 @@
                     } else {
                         assert stateAtExceptionEdge == null;
                     }
+                } else {
+                    if (outerFrameState == null) {
+                        outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind());
+                    }
+                    frameState.setOuterFrameState(outerFrameState);
                 }
             }
         }
@@ -439,13 +759,7 @@
             } else {
                 returnValue = duplicates.get(returnNode.result());
             }
-            for (Node usage : invoke.node().usages().snapshot()) {
-                if (returnNode.result() instanceof LocalNode) {
-                    usage.replaceFirstInput(invoke.node(), returnValue);
-                } else {
-                    usage.replaceFirstInput(invoke.node(), returnValue);
-                }
-            }
+            invoke.node().replaceAtUsages(returnValue);
             Node returnDuplicate = duplicates.get(returnNode);
             returnDuplicate.clearInputs();
             Node n = invoke.next();
@@ -465,20 +779,18 @@
         invoke.node().replaceAtUsages(null);
         GraphUtil.killCFG(invoke.node());
 
-        // adjust all frame states that were copied
-        if (frameStates.size() > 0) {
-            FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind());
-            for (Node node : frameStates) {
-                FrameState frameState = (FrameState) duplicates.get(node);
-                if (!frameState.isDeleted()) {
-                    frameState.setOuterFrameState(outerFrameState);
-                }
-            }
-        }
-
         if (stateAfter.usages().isEmpty()) {
             stateAfter.safeDelete();
         }
-        return returnValue;
+    }
+
+    public static void receiverNullCheck(Invoke invoke) {
+        MethodCallTargetNode callTarget = invoke.callTarget();
+        StructuredGraph graph = (StructuredGraph) invoke.graph();
+        NodeInputList<ValueNode> parameters = callTarget.arguments();
+        ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
+        if (!callTarget.isStatic() && firstParam.kind() == CiKind.Object && !firstParam.stamp().nonNull()) {
+            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(firstParam, false)))));
+        }
     }
 }
--- a/graal/com.oracle.max.graal.debug/src/com/oracle/max/graal/debug/Debug.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.debug/src/com/oracle/max/graal/debug/Debug.java	Tue Feb 07 21:09:31 2012 +0100
@@ -26,8 +26,8 @@
 import java.util.*;
 import java.util.concurrent.*;
 
+public class Debug {
 
-public class Debug {
     private static boolean ENABLED = false;
 
     public static void enable() {
@@ -73,7 +73,7 @@
 
     public static void scope(String name, Object context, Runnable runnable) {
         if (ENABLED) {
-            DebugScope.getInstance().scope(name, runnable, null, false, new Object[]{context});
+            DebugScope.getInstance().scope(name, runnable, null, false, new Object[] {context});
         } else {
             runnable.run();
         }
@@ -89,7 +89,7 @@
 
     public static <T> T scope(String name, Object context, Callable<T> callable) {
         if (ENABLED) {
-            return DebugScope.getInstance().scope(name, null, callable, false, new Object[]{context});
+            return DebugScope.getInstance().scope(name, null, callable, false, new Object[] {context});
         } else {
             return DebugScope.call(callable);
         }
@@ -130,6 +130,18 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
+    public static <T> T contextLookup(Class<T> clazz) {
+        if (ENABLED) {
+            for (Object o : context()) {
+                if (clazz.isInstance(o)) {
+                    return ((T) o);
+                }
+            }
+        }
+        return null;
+    }
+
     public static DebugMetric metric(String name) {
         if (ENABLED) {
             return new MetricImpl(name);
@@ -168,8 +180,8 @@
             }
 
             @Override
-            public RuntimeException interceptException(RuntimeException e) {
-                return e;
+            public RuntimeException interceptException(Throwable e) {
+                return null;
             }
 
             @Override
@@ -180,8 +192,12 @@
     }
 
     private static final DebugMetric VOID_METRIC = new DebugMetric() {
-        public void increment() { }
-        public void add(int value) { }
+
+        public void increment() {
+        }
+
+        public void add(int value) {
+        }
     };
 
     public static DebugTimer timer(String name) {
@@ -193,6 +209,9 @@
     }
 
     private static final DebugTimer VOID_TIMER = new DebugTimer() {
-        public TimerCloseable start() { return TimerImpl.VOID_CLOSEABLE; }
+
+        public TimerCloseable start() {
+            return TimerImpl.VOID_CLOSEABLE;
+        }
     };
 }
--- a/graal/com.oracle.max.graal.debug/src/com/oracle/max/graal/debug/DebugConfig.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.debug/src/com/oracle/max/graal/debug/DebugConfig.java	Tue Feb 07 21:09:31 2012 +0100
@@ -30,6 +30,6 @@
     boolean isMeterEnabled();
     boolean isDumpEnabled();
     boolean isTimeEnabled();
-    RuntimeException interceptException(RuntimeException e);
+    RuntimeException interceptException(Throwable e);
     Collection<? extends DebugDumpHandler> dumpHandlers();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.debug/src/com/oracle/max/graal/debug/DebugDumpScope.java	Tue Feb 07 21:09:31 2012 +0100
@@ -0,0 +1,36 @@
+/*
+ * 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.max.graal.debug;
+
+public final class DebugDumpScope {
+
+    private final String name;
+
+    public DebugDumpScope(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}
--- a/graal/com.oracle.max.graal.debug/src/com/oracle/max/graal/debug/internal/DebugScope.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.debug/src/com/oracle/max/graal/debug/internal/DebugScope.java	Tue Feb 07 21:09:31 2012 +0100
@@ -32,7 +32,7 @@
 
     private static ThreadLocal<DebugScope> instanceTL = new ThreadLocal<>();
     private static ThreadLocal<DebugConfig> configTL = new ThreadLocal<>();
-    private static ThreadLocal<RuntimeException> lastExceptionThrownTL = new ThreadLocal<>();
+    private static ThreadLocal<Throwable> lastExceptionThrownTL = new ThreadLocal<>();
     private static DebugTimer scopeTime = Debug.timer("ScopeTime");
     private static DebugMetric scopeCount = Debug.metric("ScopeCount");
 
@@ -142,13 +142,18 @@
             if (callable != null) {
                 return call(callable);
             }
-        } catch (RuntimeException e) {
+        } catch (Throwable e) {
             if (e == lastExceptionThrownTL.get()) {
                 throw e;
             } else {
                 RuntimeException newException = interceptException(e);
-                lastExceptionThrownTL.set(newException);
-                throw newException;
+                if (newException == null) {
+                    lastExceptionThrownTL.set(e);
+                    throw e;
+                } else {
+                    lastExceptionThrownTL.set(newException);
+                    throw newException;
+                }
             }
         }
         return null;
@@ -173,7 +178,7 @@
         context = null;
     }
 
-    private RuntimeException interceptException(final RuntimeException e) {
+    private RuntimeException interceptException(final Throwable e) {
         final DebugConfig config = getConfig();
         if (config != null) {
             return scope("InterceptException", null, new Callable<RuntimeException>() {
@@ -183,12 +188,12 @@
                     try {
                         return config.interceptException(e);
                     } catch (Throwable t) {
-                        return e;
+                        return new RuntimeException("Exception while intercepting exception", e);
                     }
                 }
             }, false, new Object[] {e});
         }
-        return e;
+        return null;
     }
 
     private DebugValueMap getValueMap() {
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java	Tue Feb 07 21:09:31 2012 +0100
@@ -120,9 +120,9 @@
     }
 
     @Override
-    public RuntimeException interceptException(RuntimeException e) {
+    public RuntimeException interceptException(Throwable e) {
         if (e instanceof CiBailout) {
-            return e;
+            return null;
         }
         Debug.setConfig(Debug.fixedConfig(true, true, false, false, dumpHandlers));
         // sync "Exception occured in scope: " with mx/sanitycheck.py::Test.__init__
@@ -135,7 +135,7 @@
                 Debug.dump(o, "Exception graph");
             }
         }
-        return e;
+        return null;
     }
 
     @Override
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotVMConfig.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotVMConfig.java	Tue Feb 07 21:09:31 2012 +0100
@@ -30,7 +30,7 @@
 public final class HotSpotVMConfig extends CompilerObject {
 
     /**
-     * 
+     *
      */
     private static final long serialVersionUID = -4744897993263044184L;
 
@@ -70,8 +70,20 @@
     public int runtimeCallStackSize;
     public int klassModifierFlagsOffset;
     public int klassOopOffset;
+    public int graalMirrorKlassOffset;
     public int nmethodEntryOffset;
 
+    // methodData information
+    public int methodDataOopDataOffset;
+    public int dataLayoutHeaderSize;
+    public int dataLayoutTagOffset;
+    public int dataLayoutFlagsOffset;
+    public int dataLayoutBCIOffset;
+    public int dataLayoutCellsOffset;
+    public int dataLayoutCellSize;
+    public int bciProfileWidth;
+    public int typeProfileWidth;
+
     // runtime stubs
     public long debugStub;
     public long instanceofStub;
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java	Tue Feb 07 21:09:31 2012 +0100
@@ -49,13 +49,9 @@
 
     int RiMethod_invocationCount(HotSpotMethodResolved method);
 
-    int RiMethod_exceptionProbability(HotSpotMethodResolved method, int bci);
+    HotSpotMethodData RiMethod_methodData(HotSpotMethodResolved method);
 
-    RiTypeProfile RiMethod_typeProfile(HotSpotMethodResolved method, int bci);
-
-    double RiMethod_branchProbability(HotSpotMethodResolved method, int bci);
-
-    double[] RiMethod_switchProbability(HotSpotMethodResolved method, int bci);
+    boolean HotSpotMethodData_isMature(HotSpotMethodData methodData);
 
     RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass);
 
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java	Tue Feb 07 21:09:31 2012 +0100
@@ -60,18 +60,6 @@
     public native int RiMethod_invocationCount(HotSpotMethodResolved method);
 
     @Override
-    public native int RiMethod_exceptionProbability(HotSpotMethodResolved method, int bci);
-
-    @Override
-    public native RiTypeProfile RiMethod_typeProfile(HotSpotMethodResolved method, int bci);
-
-    @Override
-    public native double RiMethod_branchProbability(HotSpotMethodResolved method, int bci);
-
-    @Override
-    public native double[] RiMethod_switchProbability(HotSpotMethodResolved method, int bci);
-
-    @Override
     public native RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass);
 
     @Override
@@ -123,6 +111,12 @@
     public native boolean RiType_isInitialized(HotSpotTypeResolved klass);
 
     @Override
+    public native HotSpotMethodData RiMethod_methodData(HotSpotMethodResolved method);
+
+    @Override
+    public native boolean HotSpotMethodData_isMature(HotSpotMethodData methodData);
+
+    @Override
     public native RiType getType(Class<?> javaClass);
 
     @Override
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Feb 07 21:09:31 2012 +0100
@@ -239,19 +239,13 @@
                     // to add something to its own queue.
                     return;
                 }
-            } else {
-                if (GraalOptions.Debug) {
-                    Debug.enable();
-                    HotSpotDebugConfig hotspotDebugConfig = new HotSpotDebugConfig(GraalOptions.Log, GraalOptions.Meter, GraalOptions.Time, GraalOptions.Dump, GraalOptions.MethodFilter);
-                    Debug.setConfig(hotspotDebugConfig);
-                }
             }
 
             Runnable runnable = new Runnable() {
 
                 public void run() {
                     try {
-                        PhasePlan plan = getDefaultPhasePlan();
+                        final PhasePlan plan = getDefaultPhasePlan();
                         GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(compiler.getRuntime());
                         plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
                         long startTime = 0;
@@ -265,7 +259,12 @@
                         CiTargetMethod result = null;
                         TTY.Filter filter = new TTY.Filter(GraalOptions.PrintFilter, method);
                         try {
-                            result = compiler.getCompiler().compileMethod(method, -1, plan);
+                            result = Debug.scope("Compiling", method, new Callable<CiTargetMethod>() {
+                                @Override
+                                public CiTargetMethod call() throws Exception {
+                                    return compiler.getCompiler().compileMethod(method, -1, plan);
+                                }
+                            });
                         } finally {
                             filter.remove();
                             if (printCompilation) {
@@ -276,6 +275,7 @@
                         }
                         compiler.getRuntime().installMethod(method, result);
                     } catch (CiBailout bailout) {
+                        Debug.metric("Bailouts").increment();
                         if (GraalOptions.ExitVMOnBailout) {
                             bailout.printStackTrace(TTY.cachedOut);
                             System.exit(-1);
@@ -391,7 +391,9 @@
 
     private PhasePlan getDefaultPhasePlan() {
         PhasePlan phasePlan = new PhasePlan();
-        phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy);
+        if (GraalOptions.Intrinsify) {
+            phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy);
+        }
         return phasePlan;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java	Tue Feb 07 21:09:31 2012 +0100
@@ -0,0 +1,590 @@
+/*
+ * 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.max.graal.hotspot.ri;
+
+import java.util.*;
+
+import sun.misc.*;
+
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.graal.hotspot.*;
+import com.oracle.max.graal.hotspot.Compiler;
+
+
+public final class HotSpotMethodData extends CompilerObject {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -8873133496591225071L;
+
+    static {
+        config = CompilerImpl.getInstance().getConfig();
+    }
+
+    // TODO (ch) use same logic as in NodeClass?
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final HotSpotMethodDataAccessor NO_DATA_ACCESSOR = new NoMethodData();
+    private static final HotSpotVMConfig config;
+    // sorted by tag
+    private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = {
+        null, new BitData(), new CounterData(), new JumpData(),
+        new TypeCheckData(), new VirtualCallData(), new RetData(),
+        new BranchData(), new MultiBranchData(), new ArgInfoData()
+    };
+
+    private Object hotspotMirror;
+    private int normalDataSize;
+    private int extraDataSize;
+    private boolean mature;
+
+    private HotSpotMethodData(Compiler compiler) {
+        super(compiler);
+        throw new IllegalStateException("this constructor is never actually called, because the objects are allocated from within the VM");
+    }
+
+    public boolean hasNormalData() {
+        return normalDataSize > 0;
+    }
+
+    public boolean hasExtraData() {
+        return extraDataSize > 0;
+    }
+
+    public int getExtraDataBeginOffset() {
+        return normalDataSize;
+    }
+
+    public boolean isMature() {
+        // TODO (ch) maturity of profiling information is an issue in general. Not all optimizations require mature data as long as the code
+        // does deoptimize/recompile on violations (might decrease startup and increase peak performance).
+        // Maturity is currently used on several levels:
+        // 1) whole method data
+        // 2) individual branch/switch profiling data
+        // 3) MatureInvocationCount for eliminating exception edges
+        if (!mature) {
+            mature = compiler.getVMEntries().HotSpotMethodData_isMature(this);
+        }
+        return mature;
+    }
+
+    public boolean isWithin(int position) {
+        return position >= 0 && position < normalDataSize + extraDataSize;
+    }
+
+    public HotSpotMethodDataAccessor getNormalData(int position) {
+        if (position >= normalDataSize) {
+            return null;
+        }
+
+        HotSpotMethodDataAccessor result = getData(position);
+        assert result != null : "NO_DATA tag is not allowed";
+        return result;
+    }
+
+    public HotSpotMethodDataAccessor getExtraData(int position) {
+        if (position >= extraDataSize) {
+            return null;
+        }
+        return getData(position);
+    }
+
+    public static HotSpotMethodDataAccessor getNoMethodData() {
+        return NO_DATA_ACCESSOR;
+    }
+
+    private HotSpotMethodDataAccessor getData(int position) {
+        assert position >= 0 : "out of bounds";
+        int tag = AbstractMethodData.readTag(this, position);
+        assert tag >= 0 && tag < PROFILE_DATA_ACCESSORS.length : "illegal tag";
+        return PROFILE_DATA_ACCESSORS[tag];
+    }
+
+    private int readUnsignedByte(int position, int offsetInBytes) {
+        long fullOffsetInBytes = computeFullOffset(position, offsetInBytes);
+        return unsafe.getByte(hotspotMirror, fullOffsetInBytes) & 0xFF;
+    }
+
+    private int readUnsignedShort(int position, int offsetInBytes) {
+        long fullOffsetInBytes = computeFullOffset(position, offsetInBytes);
+        return unsafe.getShort(hotspotMirror, fullOffsetInBytes) & 0xFFFF;
+    }
+
+    private long readUnsignedInt(int position, int offsetInBytes) {
+        long fullOffsetInBytes = computeFullOffset(position, offsetInBytes);
+        return unsafe.getInt(hotspotMirror, fullOffsetInBytes) & 0xFFFFFFFFL;
+    }
+
+    private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) {
+        long value = readUnsignedInt(position, offsetInBytes);
+        return truncateLongToInt(value);
+    }
+
+    private int readInt(int position, int offsetInBytes) {
+        long fullOffsetInBytes = computeFullOffset(position, offsetInBytes);
+        return unsafe.getInt(hotspotMirror, fullOffsetInBytes);
+    }
+
+    private Object readObject(int position, int offsetInBytes) {
+        long fullOffsetInBytes = computeFullOffset(position, offsetInBytes);
+        return unsafe.getObject(hotspotMirror, fullOffsetInBytes);
+    }
+
+    private static int truncateLongToInt(long value) {
+        return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value;
+    }
+
+    private static int computeFullOffset(int position, int offsetInBytes) {
+        return config.methodDataOopDataOffset + position + offsetInBytes;
+    }
+
+    private static int cellIndexToOffset(int cells) {
+        return config.dataLayoutHeaderSize + cellsToBytes(cells);
+    }
+
+    private static int cellsToBytes(int cells) {
+        return cells * config.dataLayoutCellSize;
+    }
+
+    private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor {
+        private static final int EXCEPTIONS_MASK = 0x80;
+
+        private final int tag;
+        private final int staticSize;
+
+        protected AbstractMethodData(int tag, int staticSize) {
+            this.tag = tag;
+            this.staticSize = staticSize;
+        }
+
+        public int getTag() {
+            return tag;
+        }
+
+        public static int readTag(HotSpotMethodData data, int position) {
+            return data.readUnsignedByte(position, config.dataLayoutTagOffset);
+        }
+
+        @Override
+        public int getBCI(HotSpotMethodData data, int position) {
+            return data.readUnsignedShort(position, config.dataLayoutBCIOffset);
+        }
+
+        @Override
+        public int getSize(HotSpotMethodData data, int position) {
+            return staticSize + getDynamicSize(data, position);
+        }
+
+        @Override
+        public boolean getExceptionSeen(HotSpotMethodData data, int position) {
+            return (getFlags(data, position) & EXCEPTIONS_MASK) != 0;
+        }
+
+        @Override
+        public RiTypeProfile getTypeProfile(HotSpotMethodData data, int position) {
+            return null;
+        }
+
+        @Override
+        public double getBranchTakenProbability(HotSpotMethodData data, int position) {
+            return -1;
+        }
+
+        @Override
+        public double[] getSwitchProbabilities(HotSpotMethodData data, int position) {
+            return null;
+        }
+
+        @Override
+        public int getExecutionCount(HotSpotMethodData data, int position) {
+            return -1;
+        }
+
+        protected int getFlags(HotSpotMethodData data, int position) {
+            return data.readUnsignedByte(position, config.dataLayoutFlagsOffset);
+        }
+
+        protected int getDynamicSize(@SuppressWarnings("unused") HotSpotMethodData data, @SuppressWarnings("unused") int position) {
+            return 0;
+        }
+    }
+
+    private static class NoMethodData extends AbstractMethodData {
+        private static final int NO_DATA_TAG = 0;
+        private static final int NO_DATA_SIZE = cellIndexToOffset(0);
+
+        protected NoMethodData() {
+            super(NO_DATA_TAG, NO_DATA_SIZE);
+        }
+
+        @Override
+        public int getBCI(HotSpotMethodData data, int position) {
+            return -1;
+        }
+
+
+        @Override
+        public boolean getExceptionSeen(HotSpotMethodData data, int position) {
+            return false;
+        }
+    }
+
+    private static class BitData extends AbstractMethodData {
+        private static final int BIT_DATA_TAG = 1;
+        private static final int BIT_DATA_SIZE = cellIndexToOffset(0);
+        private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01;
+
+        private BitData() {
+            super(BIT_DATA_TAG, BIT_DATA_SIZE);
+        }
+
+        protected BitData(int tag, int staticSize) {
+            super(tag, staticSize);
+        }
+
+        @SuppressWarnings("unused")
+        public boolean getNullSeen(HotSpotMethodData data, int position) {
+            return (getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0;
+        }
+    }
+
+    private static class CounterData extends BitData {
+        private static final int COUNTER_DATA_TAG = 2;
+        private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1);
+        private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0);
+
+        public CounterData() {
+            super(COUNTER_DATA_TAG, COUNTER_DATA_SIZE);
+        }
+
+        protected CounterData(int tag, int staticSize) {
+            super(tag, staticSize);
+        }
+
+        @Override
+        public int getExecutionCount(HotSpotMethodData data, int position) {
+            return getCounterValue(data, position);
+        }
+
+        protected int getCounterValue(HotSpotMethodData data, int position) {
+            return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET);
+        }
+    }
+
+    private static class JumpData extends AbstractMethodData {
+        private static final int JUMP_DATA_TAG = 3;
+        private static final int JUMP_DATA_SIZE = cellIndexToOffset(2);
+        protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0);
+        protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1);
+
+        public JumpData() {
+            super(JUMP_DATA_TAG, JUMP_DATA_SIZE);
+        }
+
+        protected JumpData(int tag, int staticSize) {
+            super(tag, staticSize);
+        }
+
+        @Override
+        public double getBranchTakenProbability(HotSpotMethodData data, int position) {
+            return 1;
+        }
+
+        @Override
+        public int getExecutionCount(HotSpotMethodData data, int position) {
+            return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET);
+        }
+
+        @SuppressWarnings("unused")
+        public int getTakenDisplacement(HotSpotMethodData data, int position) {
+            return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET);
+        }
+    }
+
+    private abstract static class AbstractTypeData extends CounterData {
+        private static final int RECEIVER_TYPE_DATA_ROW_SIZE = cellsToBytes(2);
+        private static final int RECEIVER_TYPE_DATA_SIZE = cellIndexToOffset(1) + RECEIVER_TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
+        private static final int RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET = cellIndexToOffset(1);
+        private static final int RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET = cellIndexToOffset(2);
+
+        protected AbstractTypeData(int tag) {
+            super(tag, RECEIVER_TYPE_DATA_SIZE);
+        }
+
+        @Override
+        public RiTypeProfile getTypeProfile(HotSpotMethodData data, int position) {
+            int typeProfileWidth = config.typeProfileWidth;
+
+            RiResolvedType[] sparseTypes = new RiResolvedType[typeProfileWidth];
+            double[] counts = new double[typeProfileWidth];
+            long totalCount = 0;
+            int entries = 0;
+
+            for (int i = 0; i < typeProfileWidth; i++) {
+                Object receiverKlassOop = data.readObject(position, getReceiverOffset(i));
+                if (receiverKlassOop != null) {
+                    Object graalMirror = unsafe.getObject(receiverKlassOop, (long) config.graalMirrorKlassOffset);
+                    if (graalMirror == null) {
+                        Class<?> javaClass = (Class<?>) unsafe.getObject(receiverKlassOop, (long) config.classMirrorOffset);
+                        graalMirror = CompilerImpl.getInstance().getVMEntries().getType(javaClass);
+                        assert graalMirror != null : "must not return null";
+                    }
+                    sparseTypes[entries] = (RiResolvedType) graalMirror;
+
+                    long count = data.readUnsignedInt(position, getCountOffset(i));
+                    totalCount += count;
+                    counts[entries] = count;
+
+                    entries++;
+                }
+            }
+
+            totalCount += getTypesNotRecordedExecutionCount(data, position);
+            return createRiTypeProfile(sparseTypes, counts, totalCount, entries);
+        }
+
+        protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position);
+
+        private static RiTypeProfile createRiTypeProfile(RiResolvedType[] sparseTypes, double[] counts, long totalCount, int entries) {
+            RiResolvedType[] types;
+            double[] probabilities;
+
+            if (entries <= 0) {
+                return null;
+            } else if (entries < sparseTypes.length) {
+                types = Arrays.copyOf(sparseTypes, entries);
+                probabilities = new double[entries];
+            } else {
+                types = sparseTypes;
+                probabilities = counts;
+            }
+
+            double totalProbability = 0.0;
+            for (int i = 0; i < entries; i++) {
+                double p = counts[i] / totalCount;
+                probabilities[i] = p;
+                totalProbability += p;
+            }
+
+            double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
+            return new RiTypeProfile(types, notRecordedTypeProbability, probabilities);
+        }
+
+        private static int getReceiverOffset(int row) {
+            return RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET + row * RECEIVER_TYPE_DATA_ROW_SIZE;
+        }
+
+        protected static int getCountOffset(int row) {
+            return RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET + row * RECEIVER_TYPE_DATA_ROW_SIZE;
+        }
+    }
+
+    private static class TypeCheckData extends AbstractTypeData {
+        private static final int RECEIVER_TYPE_DATA_TAG = 4;
+
+        public TypeCheckData() {
+            super(RECEIVER_TYPE_DATA_TAG);
+        }
+
+        @Override
+        public int getExecutionCount(HotSpotMethodData data, int position) {
+            return -1;
+        }
+
+        @Override
+        protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
+            // TODO (ch) if types do not fit, profiling is skipped for typechecks
+            return 0;
+        }
+    }
+
+    private static class VirtualCallData extends AbstractTypeData {
+        private static final int VIRTUAL_CALL_DATA_TAG = 5;
+
+        public VirtualCallData() {
+            super(VIRTUAL_CALL_DATA_TAG);
+        }
+
+        @Override
+        public int getExecutionCount(HotSpotMethodData data, int position) {
+            int typeProfileWidth = config.typeProfileWidth;
+
+            long total = 0;
+            for (int i = 0; i < typeProfileWidth; i++) {
+                total += data.readUnsignedInt(position, getCountOffset(i));
+            }
+
+            total += getCounterValue(data, position);
+            return truncateLongToInt(total);
+        }
+
+        @Override
+        protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
+            return getCounterValue(data, position);
+        }
+    }
+
+    private static class RetData extends CounterData {
+        private static final int RET_DATA_TAG = 6;
+        private static final int RET_DATA_ROW_SIZE = cellsToBytes(3);
+        private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth;
+
+        public RetData() {
+            super(RET_DATA_TAG, RET_DATA_SIZE);
+        }
+    }
+
+    private static class BranchData extends JumpData {
+        private static final int BRANCH_DATA_TAG = 7;
+        private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3);
+        private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2);
+        private static final int BRANCH_DATA_MATURE_COUNT = 40;
+
+        public BranchData() {
+            super(BRANCH_DATA_TAG, BRANCH_DATA_SIZE);
+        }
+
+        @Override
+        public double getBranchTakenProbability(HotSpotMethodData data, int position) {
+            long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET);
+            long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET);
+            long total = takenCount + notTakenCount;
+
+            if (total < BRANCH_DATA_MATURE_COUNT) {
+                return -1;
+            } else {
+                return takenCount / (double) total;
+            }
+        }
+
+        @Override
+        public int getExecutionCount(HotSpotMethodData data, int position) {
+            long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET);
+            return truncateLongToInt(count);
+        }
+    }
+
+    private static class ArrayData extends AbstractMethodData {
+        private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0);
+        protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1);
+
+        public ArrayData(int tag, int staticSize) {
+            super(tag, staticSize);
+        }
+
+        @Override
+        protected int getDynamicSize(HotSpotMethodData data, int position) {
+            return cellsToBytes(getLength(data, position));
+        }
+
+        protected static int getLength(HotSpotMethodData data, int position) {
+            return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET);
+        }
+    }
+
+    private static class MultiBranchData extends ArrayData {
+        private static final int MULTI_BRANCH_DATA_TAG = 8;
+        private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1);
+        private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2;
+        private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS);
+        private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0);
+        private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1);
+
+        public MultiBranchData() {
+            super(MULTI_BRANCH_DATA_TAG, MULTI_BRANCH_DATA_SIZE);
+        }
+
+        @Override
+        public double[] getSwitchProbabilities(HotSpotMethodData data, int position) {
+            int arrayLength = getLength(data, position);
+            assert arrayLength > 0 : "switch must have at least the default case";
+            assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows";
+
+            int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS;
+            long totalCount = 0;
+            double[] result = new double[length];
+
+            // default case is first in HotSpot but last for the compiler
+            long count = readCount(data, position, 0);
+            totalCount += count;
+            result[length - 1] = count;
+
+            for (int i = 1; i < length; i++) {
+                count = readCount(data, position, i);
+                totalCount += count;
+                result[i - 1] = count;
+            }
+
+            if (totalCount < 10 * (length + 2)) {
+                return null;
+            } else {
+                for (int i = 0; i < length; i++) {
+                    result[i] = result[i] / totalCount;
+                }
+                return result;
+            }
+        }
+
+        private static long readCount(HotSpotMethodData data, int position, int i) {
+            int offset;
+            long count;
+            offset = getCountOffset(i);
+            count = data.readUnsignedInt(position, offset);
+            return count;
+        }
+
+        @Override
+        public int getExecutionCount(HotSpotMethodData data, int position) {
+            int arrayLength = getLength(data, position);
+            assert arrayLength > 0 : "switch must have at least the default case";
+            assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows";
+
+            int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS;
+            long totalCount = 0;
+            for (int i = 0; i < length; i++) {
+                int offset = getCountOffset(i);
+                totalCount += data.readUnsignedInt(position, offset);
+            }
+
+            return truncateLongToInt(totalCount);
+        }
+
+        private static int getCountOffset(int index) {
+            return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
+        }
+
+        @SuppressWarnings("unused")
+        private static int getDisplacementOffset(int index) {
+            return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
+        }
+    }
+
+    private static class ArgInfoData extends ArrayData {
+        private static final int ARG_INFO_DATA_TAG = 9;
+        private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1);
+
+        public ArgInfoData() {
+            super(ARG_INFO_DATA_TAG, ARG_INFO_DATA_SIZE);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodDataAccessor.java	Tue Feb 07 21:09:31 2012 +0100
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.ri;
+
+import com.oracle.max.cri.ri.*;
+
+/**
+ * Interface for accessor objects that encapsulate the logic for accessing the different kinds of data in a HotSpot methodDataOop.
+ * This interface is similar to the interface {@link RiProfilingInfo}, but most methods require a MethodDataObject and the
+ * exact position within the methodData.
+ */
+public interface HotSpotMethodDataAccessor {
+    /**
+     * Returns the tag stored in the LayoutData header.
+     * @return An integer >= 0 or -1 if not supported.
+     */
+    int getTag();
+
+    /**
+     * Returns the BCI stored in the LayoutData header.
+     * @return An integer >= 0 and <= Short.MAX_VALUE, or -1 if not supported.
+     */
+    int getBCI(HotSpotMethodData data, int position);
+
+    /**
+     * Computes the size for the specific data at the given position.
+     * @return An integer > 0.
+     */
+    int getSize(HotSpotMethodData data, int position);
+
+    RiTypeProfile getTypeProfile(HotSpotMethodData data, int position);
+    double getBranchTakenProbability(HotSpotMethodData data, int position);
+    double[] getSwitchProbabilities(HotSpotMethodData data, int position);
+    boolean getExceptionSeen(HotSpotMethodData data, int position);
+    int getExecutionCount(HotSpotMethodData data, int position);
+}
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Tue Feb 07 21:09:31 2012 +0100
@@ -55,6 +55,7 @@
     private Boolean hasBalancedMonitors;
     private Map<Object, Object> compilerStorage;
     private RiResolvedType holder;
+    private HotSpotMethodData methodData;
     private byte[] code;
     private boolean canBeInlined;
     private CiGenericCallback callback;
@@ -187,24 +188,22 @@
         return null;
     }
 
+    @Override
     public int invocationCount() {
         return compiler.getVMEntries().RiMethod_invocationCount(this);
     }
 
-    public int exceptionProbability(int bci) {
-        return compiler.getVMEntries().RiMethod_exceptionProbability(this, bci);
-    }
+    @Override
+    public RiProfilingInfo profilingInfo() {
+        if (methodData == null) {
+            methodData = compiler.getVMEntries().RiMethod_methodData(this);
+        }
 
-    public RiTypeProfile typeProfile(int bci) {
-        return compiler.getVMEntries().RiMethod_typeProfile(this, bci);
-    }
-
-    public double branchProbability(int bci) {
-        return compiler.getVMEntries().RiMethod_branchProbability(this, bci);
-    }
-
-    public double[] switchProbability(int bci) {
-        return compiler.getVMEntries().RiMethod_switchProbability(this, bci);
+        if (methodData == null || !methodData.isMature()) {
+            return new HotSpotNoProfilingInfo(compiler);
+        } else {
+            return new HotSpotProfilingInfo(compiler, methodData);
+        }
     }
 
     @Override
@@ -224,25 +223,40 @@
         TTY.println("profile info for %s", this);
         TTY.println("canBeStaticallyBound: " + canBeStaticallyBound());
         TTY.println("invocationCount: " + invocationCount());
+        RiProfilingInfo profilingInfo = this.profilingInfo();
         for (int i = 0; i < codeSize(); i++) {
-            if (branchProbability(i) != -1) {
-                TTY.println("  branchProbability@%d: %f", i, branchProbability(i));
+            if (profilingInfo.getExecutionCount(i) != -1) {
+                TTY.println("  executionCount@%d: %d", i, profilingInfo.getExecutionCount(i));
             }
-            if (exceptionProbability(i) > 0) {
-                TTY.println("  exceptionProbability@%d: %d", i, exceptionProbability(i));
+
+            if (profilingInfo.getBranchTakenProbability(i) != -1) {
+                TTY.println("  branchProbability@%d: %f", i, profilingInfo.getBranchTakenProbability(i));
             }
-            RiTypeProfile profile = typeProfile(i);
-            if (profile != null && profile.count > 0) {
-                TTY.print("  profile@%d: count: %d, morphism: %d", i, profile.count, profile.morphism);
-                if (profile.types != null) {
-                    TTY.print(", types:");
-                    for (int i2 = 0; i2 < profile.types.length; i2++) {
-                        TTY.print(" %s (%f)", profile.types[i2], profile.probabilities[i2]);
-                    }
+
+            double[] switchProbabilities = profilingInfo.getSwitchProbabilities(i);
+            if (switchProbabilities != null) {
+                TTY.print("  switchProbabilities@%d:", i);
+                for (int j = 0; j < switchProbabilities.length; j++) {
+                    TTY.print(" %f", switchProbabilities[j]);
                 }
                 TTY.println();
-                if (exceptionProbability(i) > 0) {
-                    TTY.println("  exceptionProbability@%d: %d", i, exceptionProbability(i));
+            }
+
+            if (profilingInfo.getExceptionSeen(i)) {
+                TTY.println("  exceptionSeen@%d: true", i);
+            }
+
+            RiTypeProfile typeProfile = profilingInfo.getTypeProfile(i);
+            if (typeProfile != null) {
+                RiResolvedType[] types = typeProfile.getTypes();
+                double[] probabilities = typeProfile.getProbabilities();
+                if (types != null && probabilities != null) {
+                    assert types.length == probabilities.length : "length must match";
+                    TTY.print("  types@%d:", i);
+                    for (int j = 0; j < types.length; j++) {
+                        TTY.print(" %s (%f)", types[j], probabilities[j]);
+                    }
+                    TTY.println(" not recorded (%f)", typeProfile.getNotRecordedProbability());
                 }
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotNoProfilingInfo.java	Tue Feb 07 21:09:31 2012 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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.max.graal.hotspot.ri;
+
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.graal.hotspot.*;
+import com.oracle.max.graal.hotspot.Compiler;
+
+
+public final class HotSpotNoProfilingInfo extends CompilerObject implements RiProfilingInfo {
+    /**
+     *
+     */
+    private static final long serialVersionUID = 4357945025049704109L;
+    private static final HotSpotMethodDataAccessor noData = HotSpotMethodData.getNoMethodData();
+
+    public HotSpotNoProfilingInfo(Compiler compiler) {
+        super(compiler);
+    }
+
+    @Override
+    public RiTypeProfile getTypeProfile(int bci) {
+        return noData.getTypeProfile(null, -1);
+    }
+
+    @Override
+    public double getBranchTakenProbability(int bci) {
+        return noData.getBranchTakenProbability(null, -1);
+    }
+
+    @Override
+    public double[] getSwitchProbabilities(int bci) {
+        return noData.getSwitchProbabilities(null, -1);
+    }
+
+    @Override
+    public boolean getExceptionSeen(int bci) {
+        return noData.getExceptionSeen(null, -1);
+    }
+
+    @Override
+    public int getExecutionCount(int bci) {
+        return noData.getExecutionCount(null, -1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotProfilingInfo.java	Tue Feb 07 21:09:31 2012 +0100
@@ -0,0 +1,134 @@
+/*
+ * 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.max.graal.hotspot.ri;
+
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.graal.hotspot.*;
+import com.oracle.max.graal.hotspot.Compiler;
+
+
+public final class HotSpotProfilingInfo extends CompilerObject implements RiProfilingInfo {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -8307682725047864875L;
+
+    private int position;
+    private int hintPosition;
+    private int hintBCI;
+    private HotSpotMethodDataAccessor dataAccessor;
+    private HotSpotMethodData methodData;
+
+    public HotSpotProfilingInfo(Compiler compiler, HotSpotMethodData methodData) {
+        super(compiler);
+        this.methodData = methodData;
+        hintPosition = 0;
+        hintBCI = -1;
+    }
+
+    @Override
+    public RiTypeProfile getTypeProfile(int bci) {
+        findBCI(bci, false);
+        return dataAccessor.getTypeProfile(methodData, position);
+    }
+
+    @Override
+    public double getBranchTakenProbability(int bci) {
+        findBCI(bci, false);
+        return dataAccessor.getBranchTakenProbability(methodData, position);
+    }
+
+    @Override
+    public double[] getSwitchProbabilities(int bci) {
+        findBCI(bci, false);
+        return dataAccessor.getSwitchProbabilities(methodData, position);
+    }
+
+    @Override
+    public boolean getExceptionSeen(int bci) {
+        findBCI(bci, true);
+        return dataAccessor.getExceptionSeen(methodData, position);
+    }
+
+    @Override
+    public int getExecutionCount(int bci) {
+        findBCI(bci, false);
+        return dataAccessor.getExecutionCount(methodData, position);
+    }
+
+    private void findBCI(int targetBCI, boolean searchExtraData) {
+        assert targetBCI >= 0 : "invalid BCI";
+
+        if (methodData.hasNormalData()) {
+            int currentPosition = targetBCI < hintBCI ? 0 : hintPosition;
+            HotSpotMethodDataAccessor currentAccessor;
+            while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) {
+                int currentBCI = currentAccessor.getBCI(methodData, currentPosition);
+                if (currentBCI == targetBCI) {
+                    normalDataFound(currentAccessor, currentPosition, currentBCI);
+                    return;
+                } else if (currentBCI > targetBCI) {
+                    break;
+                }
+                currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition);
+            }
+        }
+
+        if (searchExtraData && methodData.hasExtraData()) {
+            int currentPosition = methodData.getExtraDataBeginOffset();
+            HotSpotMethodDataAccessor currentAccessor;
+            while ((currentAccessor = methodData.getExtraData(currentPosition)) != null) {
+                int currentBCI = currentAccessor.getBCI(methodData, currentPosition);
+                if (currentBCI == targetBCI) {
+                    extraDataFound(currentAccessor, currentPosition);
+                    return;
+                }
+                currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition);
+            }
+        }
+
+        // TODO (ch) getExceptionSeen() should return UNKNOWN if not enough extra data
+
+        noDataFound();
+    }
+
+    private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) {
+        setCurrentData(data, pos);
+        this.hintPosition = position;
+        this.hintBCI = bci;
+    }
+
+    private void extraDataFound(HotSpotMethodDataAccessor data, int pos) {
+        setCurrentData(data, pos);
+    }
+
+    private void noDataFound() {
+        setCurrentData(HotSpotMethodData.getNoMethodData(), -1);
+    }
+
+    private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) {
+        this.dataAccessor = dataAccessor;
+        this.position = position;
+    }
+}
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java	Tue Feb 07 21:09:31 2012 +0100
@@ -314,6 +314,12 @@
         } else if (n instanceof ArrayHeaderSizeNode) {
             ArrayHeaderSizeNode arrayHeaderSize = (ArrayHeaderSizeNode) n;
             graph.replaceFloating(arrayHeaderSize, ConstantNode.forLong(config.getArrayOffset(arrayHeaderSize.elementKind()), n.graph()));
+        } else if (n instanceof ReadHubNode) {
+            ReadHubNode objectClassNode = (ReadHubNode) n;
+            LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph);
+            ReadNode memoryRead = graph.add(new ReadNode(CiKind.Object, objectClassNode.object(), location));
+            memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false))));
+            graph.replaceFixed(objectClassNode, memoryRead);
         }
     }
 
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java	Tue Feb 07 21:09:31 2012 +0100
@@ -1174,32 +1174,21 @@
        @Override
        protected XirTemplate create(CiXirAssembler asm, long flags) {
            asm.restart();
-           XirParameter object = asm.createInputParameter("object", CiKind.Object);
+           XirParameter objHub = asm.createInputParameter("objectHub", CiKind.Object);
            XirOperand hub = asm.createConstantInputParameter("hub", CiKind.Object);
+           XirLabel falseSucc = asm.createInlineLabel(XirLabel.FalseSuccessor);
 
-           XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
            XirOperand checkHub = asm.createTemp("checkHub", CiKind.Object);
 
-           XirLabel slowPath = asm.createOutOfLineLabel("deopt");
-
            if (is(NULL_CHECK, flags)) {
                asm.mark(MARK_IMPLICIT_NULL);
            }
 
-           asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
            asm.mov(checkHub, hub);
            // if we get an exact match: continue
-           asm.jneq(slowPath, objHub, checkHub);
+           asm.jneq(falseSucc, objHub, checkHub);
 
-           // -- out of line -------------------------------------------------------
-           asm.bindOutOfLine(slowPath);
-           XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10);
-           asm.mov(scratch, wordConst(asm, 2));
-
-           asm.callRuntime(CiRuntimeCall.Deoptimize, null);
-           asm.shouldNotReachHere();
-
-           return asm.finishTemplate(object, "typeCheck");
+           return asm.finishTemplate(objHub, "typeCheck");
        }
     };
 
@@ -1411,9 +1400,9 @@
     }
 
     @Override
-    public XirSnippet genTypeCheck(XirSite site, XirArgument object, XirArgument hub, RiType type) {
+    public XirSnippet genTypeBranch(XirSite site, XirArgument thisHub, XirArgument otherHub, RiType type) {
         assert type instanceof RiResolvedType;
-        return new XirSnippet(typeCheckTemplates.get(site), object, hub);
+        return new XirSnippet(typeCheckTemplates.get(site), thisHub, otherHub);
     }
 
     @Override
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/snippets/ArrayCopySnippets.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/snippets/ArrayCopySnippets.java	Tue Feb 07 21:09:31 2012 +0100
@@ -21,7 +21,6 @@
  * questions.
  */
 package com.oracle.max.graal.hotspot.snippets;
-
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.cri.*;
 import com.oracle.max.graal.hotspot.*;
@@ -285,7 +284,6 @@
             DirectObjectStoreNode.store(dest, i + (destOffset + header), a);
         }
     }
-
     /**
      * Copies {@code length} bytes from {@code src} starting at {@code srcPos} to {@code dest} starting at {@code destPos}.
      * @param src source object
@@ -347,7 +345,6 @@
             DirectObjectStoreNode.store(dest, i + (destOffset + header), a);
         }
     }
-
     private static class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable {
         @Input private ValueNode object;
 
@@ -369,7 +366,6 @@
             gen.setResult(this, obj);
         }
     }
-
     private static class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
         @Input private ValueNode address;
         @Input private ValueNode value;
--- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java	Tue Feb 07 21:09:31 2012 +0100
@@ -236,6 +236,7 @@
         // mark the entrypoints of basic blocks and build lists of successors for
         // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret)
         byte[] code = method.code();
+        RiProfilingInfo profilingInfo = method.profilingInfo();
         Block current = null;
         int bci = 0;
         while (bci < code.length) {
@@ -282,7 +283,7 @@
                 case IFNULL:    // fall through
                 case IFNONNULL: {
                     current = null;
-                    double probability = useBranchPrediction ? method.branchProbability(bci) : -1;
+                    double probability = useBranchPrediction ? profilingInfo.getBranchTakenProbability(bci) : -1;
 
                     Block b1 = probability == 0.0 ? new DeoptBlock(bci + Bytes.beS2(code, bci + 1)) : makeBlock(bci + Bytes.beS2(code, bci + 1));
                     Block b2 = probability == 1.0 ? new DeoptBlock(bci + 3) : makeBlock(bci + 3);
@@ -351,7 +352,7 @@
                     break;
                 }
                 default: {
-                    if (canTrap(opcode, bci)) {
+                    if (canTrap(opcode, bci, profilingInfo)) {
                         canTrap.set(bci);
                     }
                 }
@@ -360,7 +361,7 @@
         }
     }
 
-    public boolean canTrap(int opcode, int bci) {
+    private static boolean canTrap(int opcode, int bci, RiProfilingInfo profilingInfo) {
         switch (opcode) {
             case INVOKESTATIC:
             case INVOKESPECIAL:
@@ -387,7 +388,7 @@
             case PUTFIELD:
             case GETFIELD: {
                 if (GraalOptions.AllowExplicitExceptionChecks) {
-                    return method.exceptionProbability(bci) > 0;
+                    return profilingInfo.getExceptionSeen(bci);
                 }
             }
         }
--- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Tue Feb 07 21:09:31 2012 +0100
@@ -72,6 +72,7 @@
     private RiConstantPool constantPool;
     private RiExceptionHandler[] exceptionHandlers;
     private RiResolvedMethod method;
+    private RiProfilingInfo profilingInfo;
 
     private BytecodeStream stream;           // the bytecode stream
     private final LogStream log;
@@ -116,6 +117,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         method = graph.method();
+        profilingInfo = method.profilingInfo();
         assert method.code() != null : "method must contain bytecodes: " + method;
         this.stream = new BytecodeStream(method.code());
         this.constantPool = method.getConstantPool();
@@ -321,7 +323,7 @@
         assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci";
 
         if (GraalOptions.UseExceptionProbability && method.invocationCount() > GraalOptions.MatureInvocationCount) {
-            if (bci != FrameState.BEFORE_BCI && exceptionObject == null && method.exceptionProbability(bci) == 0) {
+            if (bci != FrameState.BEFORE_BCI && exceptionObject == null && !profilingInfo.getExceptionSeen(bci)) {
                 return null;
             }
         }
@@ -602,7 +604,7 @@
 
     private void ifNode(ValueNode x, Condition cond, ValueNode y) {
         assert !x.isDeleted() && !y.isDeleted();
-        double probability = method.branchProbability(bci());
+        double probability = profilingInfo.getBranchTakenProbability(bci());
         if (probability < 0) {
             Debug.log("missing probability in %s at bci %d", method, bci());
             probability = 0.5;
@@ -696,16 +698,21 @@
             if (uniqueSubtype != null) {
                 return new RiResolvedType[] {uniqueSubtype};
             } else {
-                RiTypeProfile typeProfile = method.typeProfile(bci());
-                if (typeProfile != null && typeProfile.types != null && typeProfile.types.length > 0 && typeProfile.morphism <= maxHints) {
-                    RiResolvedType[] hints = new RiResolvedType[typeProfile.types.length];
-                    int hintCount = 0;
-                    for (RiResolvedType hint : typeProfile.types) {
-                        if (hint.isSubtypeOf(type)) {
-                            hints[hintCount++] = hint;
+                RiTypeProfile typeProfile = profilingInfo.getTypeProfile(bci());
+                if (typeProfile != null) {
+                    double notRecordedTypes = typeProfile.getNotRecordedProbability();
+                    RiResolvedType[] types = typeProfile.getTypes();
+
+                    if (notRecordedTypes == 0 && types != null && types.length > 0 && types.length <= maxHints) {
+                        RiResolvedType[] hints = new RiResolvedType[types.length];
+                        int hintCount = 0;
+                        for (RiResolvedType hint : types) {
+                            if (hint.isSubtypeOf(type)) {
+                                hints[hintCount++] = hint;
+                            }
                         }
+                        return Arrays.copyOf(hints, Math.min(maxHints, hintCount));
                     }
-                    return Arrays.copyOf(hints, Math.min(maxHints, hintCount));
                 }
                 return EMPTY_TYPE_ARRAY;
             }
@@ -1185,7 +1192,7 @@
     }
 
     private double[] switchProbability(int numberOfCases, int bci) {
-        double[] prob = method.switchProbability(bci);
+        double[] prob = profilingInfo.getSwitchProbabilities(bci);
         if (prob != null) {
             assert prob.length == numberOfCases;
         } else {
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -44,8 +44,8 @@
         return compare;
     }
 
-    public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double probability) {
-        super(StampFactory.illegal(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {probability, 1 - probability});
+    public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double takenProbability) {
+        super(StampFactory.illegal(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {takenProbability, 1 - takenProbability});
         this.compare = condition;
     }
 
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/Invoke.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/Invoke.java	Tue Feb 07 21:09:31 2012 +0100
@@ -46,4 +46,10 @@
     void intrinsify(Node node);
 
     Graph graph();
+
+    double probability();
+
+    boolean useForInlining();
+
+    void setUseForInlining(boolean value);
 }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -37,6 +37,7 @@
 
     @Input private final MethodCallTargetNode callTarget;
     private final int bci;
+    private boolean useForInlining;
 
     /**
      * Constructs a new Invoke instruction.
@@ -50,12 +51,22 @@
         super(callTarget.returnStamp());
         this.callTarget = callTarget;
         this.bci = bci;
+        this.useForInlining = true;
     }
 
     public MethodCallTargetNode callTarget() {
         return callTarget;
     }
 
+    public boolean useForInlining() {
+        return useForInlining;
+    }
+
+    @Override
+    public void setUseForInlining(boolean value) {
+        this.useForInlining = value;
+    }
+
     @Override
     public Map<Object, Object> getDebugProperties() {
         Map<Object, Object> debugProperties = super.getDebugProperties();
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeWithExceptionNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeWithExceptionNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -38,6 +38,7 @@
     @Input private final MethodCallTargetNode callTarget;
     @Input private FrameState stateAfter;
     private final int bci;
+    private boolean useForInlining;
 
     /**
      * @param kind
@@ -48,6 +49,7 @@
         super(callTarget.returnStamp(), new BeginNode[]{null, exceptionEdge}, new double[]{1.0, 0.0});
         this.bci = bci;
         this.callTarget = callTarget;
+        this.useForInlining = true;
     }
 
     public BeginNode exceptionEdge() {
@@ -71,6 +73,16 @@
     }
 
     @Override
+    public boolean useForInlining() {
+        return useForInlining;
+    }
+
+    @Override
+    public void setUseForInlining(boolean value) {
+        this.useForInlining = value;
+    }
+
+    @Override
     public String toString(Verbosity verbosity) {
         if (verbosity == Verbosity.Long) {
             return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/LookupSwitchNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/LookupSwitchNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -29,7 +29,7 @@
  * The {@code LookupSwitchNode} represents a lookup switch bytecode, which has a sorted
  * array of key values.
  */
-public final class LookupSwitchNode extends SwitchNode implements LIRLowerable {
+public final class LookupSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
 
     @Data private final int[] keys;
 
@@ -66,4 +66,32 @@
     public void generate(LIRGeneratorTool gen) {
         gen.emitLookupSwitch(this);
     }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (value() instanceof ConstantNode) {
+            ConstantNode constant = (ConstantNode) value();
+            int value = constant.value.asInt();
+
+            BeginNode remainingSux = (BeginNode) defaultSuccessor();
+            int remainingSuxIndex = blockSuccessorCount() - 1;
+            for (int i = 0; i < keys.length; i++) {
+                if (value == keys[i]) {
+                    remainingSux = blockSuccessor(i);
+                    remainingSuxIndex = i;
+                    break;
+                }
+            }
+
+            for (int i = 0; i < blockSuccessorCount(); i++) {
+                BeginNode sux = blockSuccessor(i);
+                if (sux != remainingSux) {
+                    tool.deleteBranch(sux);
+                }
+            }
+
+            tool.addToWorkList(remainingSux);
+            ((StructuredGraph) graph()).removeSplit(this, remainingSuxIndex);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ReadHubNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -0,0 +1,48 @@
+/*
+ * 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.nodes.extended;
+
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.graal.cri.*;
+import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.spi.*;
+import com.oracle.max.graal.nodes.type.*;
+
+// TODO (ch) this should be a FloatingNode but Lowering crashes in that case
+public final class ReadHubNode extends FixedWithNextNode implements Lowerable {
+    @Input private ValueNode object;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ReadHubNode(ValueNode object) {
+        super(StampFactory.forKind(CiKind.Object));
+        this.object = object;
+    }
+
+    @Override
+    public void lower(CiLoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+}
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/TableSwitchNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/TableSwitchNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -28,7 +28,7 @@
 /**
  * The {@code TableSwitchNode} represents a table switch.
  */
-public final class TableSwitchNode extends SwitchNode implements LIRLowerable {
+public final class TableSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
 
     @Data private final int lowKey;
 
@@ -67,4 +67,30 @@
     public void generate(LIRGeneratorTool gen) {
         gen.emitTableSwitch(this);
     }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (value() instanceof ConstantNode) {
+            ConstantNode constant = (ConstantNode) value();
+            int value = constant.value.asInt();
+
+            int remainingSuxIndex;
+            if (value >= lowKey() && value <= highKey()) {
+                remainingSuxIndex = value - lowKey();
+            } else {
+                remainingSuxIndex = blockSuccessorCount() - 1;
+            }
+
+            BeginNode remainingSux = blockSuccessor(remainingSuxIndex);
+            for (int i = 0; i < blockSuccessorCount(); i++) {
+                BeginNode sux = blockSuccessor(i);
+                if (sux != remainingSux) {
+                    tool.deleteBranch(sux);
+                }
+            }
+
+            tool.addToWorkList(remainingSux);
+            ((StructuredGraph) graph()).removeSplit(this, remainingSuxIndex);
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/ArrayLengthNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/ArrayLengthNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -58,7 +58,7 @@
             return length;
         }
         CiConstant constantValue = null;
-        if (array().isConstant()) {
+        if (array().isConstant() && !array().isNullConstant()) {
             constantValue = array().asConstant();
             if (constantValue != null && constantValue.isNonNull()) {
                 RiRuntime runtime = tool.runtime();
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -27,30 +27,30 @@
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.extended.*;
 import com.oracle.max.graal.nodes.spi.*;
 import com.oracle.max.graal.nodes.type.*;
 
 public final class IsTypeNode extends BooleanNode implements Canonicalizable, LIRLowerable {
 
-    @Input private ValueNode object;
+    @Input private ValueNode objectClass;
+    @Data private final RiResolvedType type;
 
-    public ValueNode object() {
-        return object;
+    public ValueNode objectClass() {
+        return objectClass;
     }
 
-    private final RiResolvedType type;
-
     /**
      * Constructs a new IsTypeNode.
      *
      * @param object the instruction producing the object to check against the given type
      * @param type the type for this check
      */
-    public IsTypeNode(ValueNode object, RiResolvedType type) {
+    public IsTypeNode(ValueNode objectClass, RiResolvedType type) {
         super(StampFactory.illegal());
-        assert object == null || object.kind() == CiKind.Object;
+        assert objectClass == null || objectClass.kind() == CiKind.Object;
         this.type = type;
-        this.object = object;
+        this.objectClass = objectClass;
     }
 
     public RiResolvedType type() {
@@ -71,8 +71,9 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (object().exactType() != null) {
-            return ConstantNode.forBoolean(object().exactType() == type(), graph());
+        RiResolvedType exactType = objectClass() instanceof ReadHubNode ? ((ReadHubNode) objectClass()).object().exactType() : null;
+        if (exactType != null) {
+            return ConstantNode.forBoolean(exactType == type(), graph());
         }
         // constants return the correct exactType, so they are handled by the code above
         return this;
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/LoadFieldNode.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/LoadFieldNode.java	Tue Feb 07 21:09:31 2012 +0100
@@ -69,7 +69,7 @@
         CiConstant constant = null;
         if (isStatic()) {
             constant = field().constantValue(null);
-        } else if (object().isConstant()) {
+        } else if (object().isConstant() && !object().isNullConstant()) {
             constant = field().constantValue(object().asConstant());
         }
         if (constant != null) {
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java	Tue Feb 07 21:09:31 2012 +0100
@@ -41,7 +41,7 @@
             assert ((NullCheckNode) usage).object() == node;
             return false;
         } else if (usage instanceof IsTypeNode) {
-            assert ((IsTypeNode) usage).object() == node;
+            assert ((IsTypeNode) usage).objectClass() == node;
             return false;
         } else if (usage instanceof FrameState) {
             assert usage.inputs().contains(node);
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/type/StampFactory.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/type/StampFactory.java	Tue Feb 07 21:09:31 2012 +0100
@@ -173,7 +173,7 @@
             RiResolvedType exactType = first.exactType();
             while (iterator.hasNext()) {
                 Stamp current = iterator.next().stamp();
-                assert current.kind() == first.kind() : values + " first=" + first + " current=" + current;
+                assert current.kind() == first.kind() : values + " first=" + first + " current=" + current + " first kind=" + first.kind() + " current kind=" + current.kind();
                 nonNull &= current.nonNull();
                 declaredType = orTypes(declaredType, current.declaredType());
                 exactType = orTypes(exactType, current.exactType());
--- a/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinterDumpHandler.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinterDumpHandler.java	Tue Feb 07 21:09:31 2012 +0100
@@ -25,6 +25,7 @@
 import java.io.*;
 import java.net.*;
 import java.util.*;
+
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.criutils.*;
@@ -40,7 +41,7 @@
     private static final String DEFAULT_FILE_NAME = "output.igv.xml";
 
     private IdealGraphPrinter printer;
-    private List<RiResolvedMethod> previousInlineContext = new ArrayList<>();
+    private List<String> previousInlineContext = new ArrayList<>();
     private String fileName;
     private String host;
     private int port;
@@ -61,8 +62,6 @@
         this.port = port;
     }
 
-
-
     private void ensureInitialized() {
         if (!initialized) {
             initialized = true;
@@ -85,7 +84,7 @@
     }
 
     private void initializeNetworkPrinter() {
-        try  {
+        try {
             Socket socket = new Socket(host, port);
             BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000);
             printer = new IdealGraphPrinter(stream);
@@ -103,26 +102,29 @@
 
             if (printer.isValid()) {
                 // Get all current RiResolvedMethod instances in the context.
-                List<RiResolvedMethod> inlineContext = Debug.contextSnapshot(RiResolvedMethod.class);
+                List<String> inlineContext = getInlineContext();
+                Debug.contextSnapshot(RiResolvedMethod.class);
 
                 // Reverse list such that inner method comes after outer method.
                 Collections.reverse(inlineContext);
 
                 // Check for method scopes that must be closed since the previous dump.
                 for (int i = 0; i < previousInlineContext.size(); ++i) {
-                    if (i >= inlineContext.size() || inlineContext.get(i) != previousInlineContext.get(i)) {
+                    if (i >= inlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) {
                         for (int j = previousInlineContext.size() - 1; j >= i; --j) {
-                            closeMethodScope();
+                            closeScope();
                         }
+                        break;
                     }
                 }
 
                 // Check for method scopes that must be opened since the previous dump.
                 for (int i = 0; i < inlineContext.size(); ++i) {
-                    if (i >= previousInlineContext.size() || inlineContext.get(i) != previousInlineContext.get(i)) {
+                    if (i >= previousInlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) {
                         for (int j = i; j < inlineContext.size(); ++j) {
-                            openMethodScope(inlineContext.get(j));
+                            openScope(inlineContext.get(j));
                         }
+                        break;
                     }
                 }
 
@@ -145,13 +147,25 @@
         }
     }
 
-    private void openMethodScope(RiResolvedMethod method) {
-        printer.beginGroup(CiUtil.format("%H::%n", method), CiUtil.format("%h::%n", method), method, -1);
-
+    private static List<String> getInlineContext() {
+        List<String> result = new ArrayList<>();
+        for (Object o : Debug.context()) {
+            if (o instanceof RiResolvedMethod) {
+                RiResolvedMethod method = (RiResolvedMethod) o;
+                result.add(CiUtil.format("%H::%n", method));
+            } else if (o instanceof DebugDumpScope) {
+                DebugDumpScope debugDumpScope = (DebugDumpScope) o;
+                result.add(debugDumpScope.getName());
+            }
+        }
+        return result;
     }
 
-    private void closeMethodScope() {
+    private void openScope(String name) {
+        printer.beginGroup(name, name, Debug.contextLookup(RiResolvedMethod.class), -1);
+    }
+
+    private void closeScope() {
         printer.endGroup();
-
     }
 }
--- a/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/DegeneratedLoopsTest.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/DegeneratedLoopsTest.java	Tue Feb 07 21:09:31 2012 +0100
@@ -52,9 +52,6 @@
     }
 
     private static class UnresolvedException extends RuntimeException {
-        /**
-         *
-         */
         private static final long serialVersionUID = 5215434338750728440L;
 
         static {
--- a/make/windows/makefiles/projectcreator.make	Sun Feb 05 05:40:36 2012 +0100
+++ b/make/windows/makefiles/projectcreator.make	Tue Feb 07 21:09:31 2012 +0100
@@ -89,7 +89,7 @@
         -define ALIGN_STACK_FRAMES \
         -define VM_LITTLE_ENDIAN \
         -prelink  "" "Generating vm.def..." "cd %o	set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME)	$(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LINK_VER)" \
-        -postbuild "" "Building hotspot.exe..." "cd %o	HOTSPOTMKSHOME=$(HOTSPOTMKSHOME)	nmake -f $(HOTSPOTWORKSPACE)\make\windows\projectfiles\common\Makefile LOCAL_MAKE=$(HOTSPOTBUILDSPACE)\%f\local.make JAVA_HOME=$(HOTSPOTJDKDIST) launcher" \
+        -postbuild "" "Building hotspot.exe..." "cd %o	set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME)	nmake -f $(HOTSPOTWORKSPACE)\make\windows\projectfiles\common\Makefile LOCAL_MAKE=$(HOTSPOTBUILDSPACE)\%f\local.make JAVA_HOME=$(HOTSPOTJDKDIST) launcher" \
         -ignoreFile jsig.c \
         -ignoreFile jvmtiEnvRecommended.cpp \
         -ignoreFile jvmtiEnvStub.cpp \
--- a/mx/commands.py	Sun Feb 05 05:40:36 2012 +0100
+++ b/mx/commands.py	Tue Feb 07 21:09:31 2012 +0100
@@ -218,6 +218,57 @@
     
     if len(failed) != 0:
         mx.abort('DaCapo failures: ' + str(failed))
+    
+
+def scaladacapo(args):
+    """run one or all Scala DaCapo benchmarks
+    
+    Scala DaCapo options are distinguished from VM options by a '@' prefix.
+    For example, '@--iterations @5' will pass '--iterations 5' to the
+    DaCapo harness."""
+
+    numTests = {}
+    
+    if len(args) > 0:
+        level = getattr(sanitycheck.SanityCheckLevel, args[0], None)
+        if level is not None:
+            del args[0]
+            for (bench, ns) in sanitycheck.dacapoScalaSanityWarmup.items():
+                if ns[level] > 0:
+                    numTests[bench] = ns[level]
+        else:
+            while len(args) != 0 and args[0][0] not in ['-', '@']:
+                n = 1
+                if args[0].isdigit():
+                    n = int(args[0])
+                    assert len(args) > 1 and args[1][0] not in ['-', '@'] and not args[1].isdigit()
+                    bm = args[1]
+                    del args[0]
+                else:
+                    bm = args[0]
+                
+                del args[0]
+                if bm not in sanitycheck.dacapoScalaSanityWarmup.keys():
+                    mx.abort('unknown benchmark: ' + bm + '\nselect one of: ' + str(sanitycheck.dacapoScalaSanityWarmup.keys()))
+                numTests[bm] = n
+    
+    if len(numTests) is 0:    
+        for bench in sanitycheck.dacapoScalaSanityWarmup.keys():
+            numTests[bench] = 1
+    
+    # Extract DaCapo options
+    dacapoArgs = [(arg[1:]) for arg in args if arg.startswith('@')]
+    
+    # The remainder are VM options 
+    vmOpts = [arg for arg in args if not arg.startswith('@')]
+    
+    failed = []
+    for (test, n) in numTests.items():
+        if not sanitycheck.getScalaDacapo(test, n, dacapoArgs).test('graal', opts=vmOpts):
+            failed.append(test)
+    
+    if len(failed) != 0:
+        mx.abort('Scala DaCapo failures: ' + str(failed))
  
 def _jdk(build='product', create=False):
     """
@@ -498,7 +549,7 @@
         build(['--no-native'])
         tasks.append(t.stop())
     
-        for vmbuild in ['product', 'fastdebug']:
+        for vmbuild in ['fastdebug', 'product']:
             global _vmbuild
             _vmbuild = vmbuild
             
@@ -571,6 +622,15 @@
             if dacapo not in sanitycheck.dacapoSanityWarmup.keys():
                 mx.abort('Unknown dacapo : ' + dacapo)
             benchmarks += [sanitycheck.getDacapo(dacapo, sanitycheck.dacapoSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark])]
+    
+    if ('scaladacapo' in args or 'all' in args):
+        benchmarks += sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Benchmark)
+    else:
+        dacapos = [a[7:] for a in args if a.startswith('scaladacapo:')]
+        for dacapo in dacapos:
+            if dacapo not in sanitycheck.dacapoScalaSanityWarmup.keys():
+                mx.abort('Unknown dacapo : ' + dacapo)
+            benchmarks += [sanitycheck.getScalaDacapo(dacapo, sanitycheck.dacapoScalaSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark])]
         
     #Bootstrap
     if ('bootstrap' in args or 'all' in args):
@@ -597,14 +657,29 @@
     vmArgs = [a for a in args if a[0] != '@']
     sanitycheck.getSPECjvm2008(benchArgs).bench('graal', opts=vmArgs)
     
+def hsdis(args):
+    """Installs the hsdis library
+
+    This is needed to support HotSpot's assembly dumping features.
+    By default it installs the Intel syntax version, use the 'att' argument to install AT&T syntax."""
+    flavor = 'intel'
+    if 'att' in args:
+        flavor = 'att'
+    build = _vmbuild if _vmSourcesAvailable else 'product'
+    lib = mx.lib_suffix('hsdis-amd64')
+    path = join(_jdk(build), 'jre', 'lib', 'amd64', lib)
+    mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib])
+    
 def mx_init():
     _vmbuild = 'product'
     commands = {
         'build': [build, '[-options]'],
         'clean': [clean, ''],
         'copyrightcheck': [copyrightcheck, ''],
+        'hsdis': [hsdis, '[att]'],
         'dacapo': [dacapo, '[[n] benchmark] [VM options|@DaCapo options]'],
-        'specjvm2008': [specjvm2008, ''],
+        'scaladacapo': [scaladacapo, '[[n] benchmark] [VM options|@Scala DaCapo options]'],
+        'specjvm2008': [specjvm2008, '[VM options|@specjvm2008 options]'],
         'example': [example, '[-v] example names...'],
         'gate' : [gate, ''],
         'bench' : [bench, '[-vm vm] [-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'],
--- a/mx/projects	Sun Feb 05 05:40:36 2012 +0100
+++ b/mx/projects	Tue Feb 07 21:09:31 2012 +0100
@@ -41,6 +41,9 @@
 library@DACAPO@path=lib/dacapo-9.12-bach.jar
 library@DACAPO@urls=http://dfn.dl.sourceforge.net/project/dacapobench/9.12-bach/dacapo-9.12-bach.jar
 
+library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0.jar
+library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20110908.085753-2.jar
+
 # graal.hotspot
 project@com.oracle.max.graal.hotspot@subDir=graal
 project@com.oracle.max.graal.hotspot@sourceDirs=src
--- a/mx/sanitycheck.py	Sun Feb 05 05:40:36 2012 +0100
+++ b/mx/sanitycheck.py	Tue Feb 07 21:09:31 2012 +0100
@@ -39,13 +39,28 @@
     'luindex':    [0, 0,  5, 10, 10],
     'lusearch':   [0, 4,  5,  5,  8],
     'pmd':        [0, 0,  5, 10, 13],
-    'sunflow':    [0, 0,  5, 10, 15],
+    'sunflow':    [0, 2,  5, 10, 15],
     'tomcat':     [0, 0,  5, 10, 15],
     'tradebeans': [0, 0,  5, 10, 13],
     'tradesoap':  [2, 4,  5, 10, 15],
     'xalan':      [0, 0,  5, 10, 18],
 }
 
+dacapoScalaSanityWarmup = {
+    'actors':     [0, 0, 2,  8, 10],
+    'apparat':    [0, 0, 1,  2,  3],
+    'factorie':   [0, 0, 2,  5,  5],
+    'kiama':      [0, 0, 3, 13, 15],
+    'scalac':     [0, 0, 5, 15, 20],
+    'scaladoc':   [0, 0, 5, 15, 15],
+    'scalap':     [0, 0, 5, 15, 20],
+    'scalariform':[0, 0, 6, 15, 20],
+    'scalatest':  [0, 0, 2, 10, 12],
+    'scalaxb':    [0, 0, 5, 15, 25],
+    'specs':      [0, 0, 3, 13, 18],
+    'tmt':        [0, 0, 3, 10, 12]
+}
+
 dacapoGateBuildLevels = {
     'avrora':     ['product', 'fastdebug', 'debug'],
     'batik':      ['product', 'fastdebug', 'debug'],
@@ -63,6 +78,21 @@
     'xalan':      ['product', 'fastdebug', 'debug'],
 }
 
+dacapoScalaGateBuildLevels = {
+    'actors':     ['product', 'fastdebug', 'debug'],
+    'apparat':    ['product', 'fastdebug', 'debug'],
+    'factorie':   ['product', 'fastdebug', 'debug'],
+    'kiama':      ['product', 'fastdebug', 'debug'],
+    'scalac':     ['product', 'fastdebug', 'debug'],
+    'scaladoc':   ['product', 'fastdebug', 'debug'],
+    'scalap':     ['product', 'fastdebug', 'debug'],
+    'scalariform':['product', 'fastdebug', 'debug'],
+    'scalatest':  ['product', 'fastdebug', 'debug'],
+    'scalaxb':    ['product', 'fastdebug', 'debug'],
+    'specs':      ['product', 'fastdebug', 'debug'],
+    'tmt':        ['product', 'fastdebug', 'debug'],
+}
+
 class SanityCheckLevel:
     Fast, Gate, Normal, Extensive, Benchmark = range(5)
     
@@ -118,6 +148,36 @@
     
     return Test("DaCapo-" + name, "DaCapo", ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:MaxPermSize=256m'])
 
+def getScalaDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=[]):
+    checks = []
+    
+    for (bench, ns) in dacapoScalaSanityWarmup.items():
+        if ns[level] > 0:
+            if gateBuildLevel is None or gateBuildLevel in dacapoScalaGateBuildLevels[bench]:
+                checks.append(getScalaDacapo(bench, ns[level], dacapoArgs))
+    
+    return checks
+
+def getScalaDacapo(name, n, dacapoArgs=[]):
+    dacapo = mx.get_env('DACAPO_SCALA_CP')
+    if dacapo is None:
+        l = mx.library('DACAPO_SCALA', False)
+        if l is not None:
+            dacapo = l.get_path(True)
+        else:
+            mx.abort('Scala DaCapo 0.1.0 jar file must be specified with DACAPO_SCALA_CP environment variable or as DACAPO_SCALA library')
+    
+    if not isfile(dacapo) or not dacapo.endswith('.jar'):
+        mx.abort('Specified Scala DaCapo jar file does not exist or is not a jar file: ' + dacapo)
+    
+    dacapoSuccess = re.compile(r"^===== DaCapo 0\.1\.0(-SNAPSHOT)? ([a-zA-Z0-9_]+) PASSED in ([0-9]+) msec =====$")
+    dacapoFail = re.compile(r"^===== DaCapo 0\.1\.0(-SNAPSHOT)? ([a-zA-Z0-9_]+) FAILED (warmup|) =====$")
+    dacapoTime = re.compile(r"===== DaCapo 0\.1\.0(-SNAPSHOT)? (?P<benchmark>[a-zA-Z0-9_]+) PASSED in (?P<time>[0-9]+) msec =====")
+    
+    dacapoMatcher = Matcher(dacapoTime, {'const:name' : 'benchmark', 'const:score' : 'time'})
+    
+    return Test("Scala-DaCapo-" + name, "Scala-DaCapo", ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:MaxPermSize=256m'])
+
 def getBootstraps():
     time = re.compile(r"Bootstrapping Graal\.+ in (?P<time>[0-9]+) ms")
     scoreMatcher = Matcher(time, {'const:name' : 'const:BootstrapTime', 'const:score' : 'time'})
--- a/mxtool/mx.py	Sun Feb 05 05:40:36 2012 +0100
+++ b/mxtool/mx.py	Tue Feb 07 21:09:31 2012 +0100
@@ -648,6 +648,17 @@
         return name + '.exe'
     return name
 
+def lib_suffix(name):
+    """
+    Gets the platform specific suffix for a library
+    """
+    os = get_os();
+    if os == 'windows':
+        return name + '.dll'
+    if os == 'linux':
+        return name + '.so'
+    return name
+
 """
 A JavaConfig object encapsulates info on how Java commands are run.
 """
--- a/src/cpu/x86/vm/c1_globals_x86.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/cpu/x86/vm/c1_globals_x86.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -47,7 +47,7 @@
 define_pd_global(intx, FreqInlineSize,               325  );
 define_pd_global(intx, NewSizeThreadIncrease,        4*K  );
 define_pd_global(intx, InitialCodeCacheSize,         4*M);      // changed for GRAAL
-define_pd_global(intx, ReservedCodeCacheSize,        50*M );    // changed for GRAAL
+define_pd_global(intx, ReservedCodeCacheSize,        48*M );    // changed for GRAAL
 define_pd_global(bool, ProfileInterpreter,           true );    // changed for GRAAL
 define_pd_global(intx, CodeCacheExpansionSize,       64*K );    // changed for GRAAL
 define_pd_global(uintx,CodeCacheMinBlockLength,      4);        // changed for GRAAL
@@ -57,7 +57,7 @@
 define_pd_global(uint64_t,MaxRAM,                    1ULL*G);
 define_pd_global(bool, CICompileOSR,                 true );
 #endif // !TIERED
-define_pd_global(bool, UseTypeProfile,               true );    // changed for GRAAL
+define_pd_global(intx, TypeProfileWidth,             8    );    // changed for GRAAL
 define_pd_global(bool, RoundFPResults,               true );
 
 define_pd_global(bool, LIRFillDelaySlots,            false);
--- a/src/cpu/x86/vm/c2_globals_x86.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/cpu/x86/vm/c2_globals_x86.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -39,6 +39,7 @@
 define_pd_global(bool, PreferInterpreterNativeStubs, false);
 define_pd_global(bool, ProfileTraps,                 true);
 define_pd_global(bool, UseOnStackReplacement,        true);
+define_pd_global(intx, TypeProfileWidth,             2   );
 #ifdef CC_INTERP
 define_pd_global(bool, ProfileInterpreter,           false);
 #else
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Tue Feb 07 21:09:31 2012 +0100
@@ -128,8 +128,8 @@
 
         @Override
         protected Group start() throws SAXException {
-            Group group = new Group(this.getParentObject());
-            
+            final Group group = new Group(this.getParentObject());
+
             String differenceProperty = this.readAttribute(DIFFERENCE_PROPERTY);
             Parser.this.differenceEncoding.put(group, (differenceProperty != null && (differenceProperty.equals("1") || differenceProperty.equals("true"))));
 
@@ -138,12 +138,6 @@
                 monitor.setState(group.getName());
             }
 
-            return group;
-        }
-
-        @Override
-        protected void end(String text) throws SAXException {
-            final Group group = getObject();
             final Folder parent = getParentObject();
             if (groupCallback == null || parent instanceof Group) {
                 SwingUtilities.invokeLater(new Runnable(){
@@ -153,6 +147,12 @@
                     }
                 });
             }
+
+            return group;
+        }
+
+        @Override
+        protected void end(String text) throws SAXException {
         }
     };
     // <method>
@@ -270,7 +270,7 @@
                 graph.addBlockEdge(left, right);
             }
             blockConnections.clear();
-            
+
             SwingUtilities.invokeLater(new Runnable(){
 
                 @Override
--- a/src/share/tools/ProjectCreator/BuildConfig.java	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/tools/ProjectCreator/BuildConfig.java	Tue Feb 07 21:09:31 2012 +0100
@@ -68,8 +68,14 @@
         if (value != null) {
             outDir = value;
         }
+        if (outDir.endsWith("debug")) {
+            outDir = outDir.substring(0, outDir.lastIndexOf("debug") - 1);
+        } else if(outDir.endsWith("fastdebug")) {
+            outDir = outDir.substring(0, outDir.lastIndexOf("fastdebug") - 1);
+        }
+        
         if (!build.equals("product")) {
-            outDir += Util.sep + "fastdebug";
+            outDir += Util.sep + build;
         }
         outDir += Util.sep + "jre" + Util.sep + "bin";
         if (flavour.equals("compiler1")) {
--- a/src/share/vm/classfile/systemDictionary.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -193,6 +193,7 @@
   template(HotSpotField_klass,                    com_oracle_max_graal_hotspot_HotSpotField,                        Opt) \
   template(HotSpotCompiledMethod_klass,           com_oracle_max_graal_hotspot_HotSpotCompiledMethod,               Opt) \
   template(HotSpotMethodResolved_klass,           com_oracle_max_graal_hotspot_ri_HotSpotMethodResolved,            Opt) \
+  template(HotSpotMethodData_klass,               com_oracle_max_graal_hotspot_ri_HotSpotMethodData,                Opt) \
   template(HotSpotTargetMethod_klass,             com_oracle_max_graal_hotspot_HotSpotTargetMethod,                 Opt) \
   template(HotSpotExceptionHandler_klass,         com_oracle_max_graal_hotspot_HotSpotExceptionHandler,             Opt) \
   template(HotSpotProxy_klass,                    com_oracle_max_graal_hotspot_HotSpotProxy,                        Opt) \
@@ -223,7 +224,6 @@
   template(RiType_klass,                          com_oracle_max_cri_ri_RiType,                                     Opt) \
   template(RiResolvedField_klass,                 com_oracle_max_cri_ri_RiResolvedField,                            Opt) \
   template(RiExceptionHandler_klass,              com_oracle_max_cri_ri_RiExceptionHandler,                         Opt) \
-  template(RiTypeProfile_klass,                   com_oracle_max_cri_ri_RiTypeProfile,                              Opt) \
 
   /*end*/
 
--- a/src/share/vm/classfile/vmSymbols.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -272,6 +272,7 @@
   template(com_oracle_max_graal_hotspot_bridge_VMToCompiler,          "com/oracle/max/graal/hotspot/bridge/VMToCompiler")                 \
   template(com_oracle_max_graal_hotspot_ri_HotSpotMethodResolved,     "com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl")        \
   template(com_oracle_max_graal_hotspot_HotSpotTargetMethod,          "com/oracle/max/graal/hotspot/HotSpotTargetMethod")                 \
+  template(com_oracle_max_graal_hotspot_ri_HotSpotMethodData,         "com/oracle/max/graal/hotspot/ri/HotSpotMethodData")                \
   template(com_oracle_max_graal_hotspot_HotSpotField,                 "com/oracle/max/graal/hotspot/ri/HotSpotField")                     \
   template(com_oracle_max_graal_hotspot_HotSpotCompiledMethod,        "com/oracle/max/graal/hotspot/ri/HotSpotCompiledMethod")            \
   template(com_oracle_max_graal_hotspot_HotSpotOptions,               "com/oracle/max/graal/hotspot/HotSpotOptions")                      \
@@ -284,7 +285,6 @@
   template(com_oracle_max_cri_ri_RiMethod,                            "com/oracle/max/cri/ri/RiMethod")                                   \
   template(com_oracle_max_cri_ri_RiResolvedField,                     "com/oracle/max/cri/ri/RiResolvedField")                            \
   template(com_oracle_max_cri_ri_RiType,                              "com/oracle/max/cri/ri/RiType")                                     \
-  template(com_oracle_max_cri_ri_RiTypeProfile,                       "com/oracle/max/cri/ri/RiTypeProfile")                              \
   template(com_oracle_max_cri_ri_RiConstantPool,                      "com/oracle/max/cri/ri/RiConstantPool")                             \
   template(com_oracle_max_cri_ri_RiExceptionHandler,                  "com/oracle/max/cri/ri/RiExceptionHandler")                         \
   template(com_oracle_max_cri_ci_CiAssumptions,                       "com/oracle/max/cri/ci/CiAssumptions")                              \
--- a/src/share/vm/graal/graalCompiler.cpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Tue Feb 07 21:09:31 2012 +0100
@@ -29,6 +29,7 @@
 #include "graal/graalVmIds.hpp"
 #include "graal/graalEnv.hpp"
 #include "c1/c1_Runtime1.hpp"
+#include "compiler/compilerOracle.hpp"
 #include "runtime/arguments.hpp"
 
 GraalCompiler* GraalCompiler::_instance = NULL;
@@ -270,10 +271,30 @@
   HotSpotMethodResolved::set_accessFlags(obj, method->access_flags().as_int());
   HotSpotMethodResolved::set_maxLocals(obj, method->max_locals());
   HotSpotMethodResolved::set_maxStackSize(obj, method->max_stack());
-  HotSpotMethodResolved::set_canBeInlined(obj, true);
+  HotSpotMethodResolved::set_canBeInlined(obj, !CompilerOracle::should_not_inline(method));
   
   method->set_graal_mirror(obj());
-  return obj();
+  return obj;
+}
+
+Handle GraalCompiler::createHotSpotMethodData(methodDataHandle method_data, TRAPS) {
+  if(method_data->graal_mirror() != NULL) {
+    assert(method_data->graal_mirror()->is_a(HotSpotMethodData::klass()), "unexpected class");
+    return method_data->graal_mirror();
+  }
+
+  instanceKlass::cast(HotSpotMethodData::klass())->initialize(CHECK_NULL);
+  Handle obj = instanceKlass::cast(HotSpotMethodData::klass())->allocate_instance(CHECK_NULL);
+  assert(obj.not_null(), "must succeed in allocating instance");
+  
+  HotSpotMethodData::set_compiler(obj, VMToCompiler::compilerInstance()());
+  HotSpotMethodData::set_hotspotMirror(obj, method_data());
+  HotSpotMethodData::set_normalDataSize(obj, method_data()->data_size());
+  HotSpotMethodData::set_extraDataSize(obj, method_data()->extra_data_size());
+  HotSpotMethodData::set_mature(obj, method_data()->is_mature());
+
+  method_data->set_graal_mirror(obj());
+  return obj;
 }
 
 BasicType GraalCompiler::kindToBasicType(jchar ch) {
--- a/src/share/vm/graal/graalCompiler.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/graal/graalCompiler.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -67,6 +67,7 @@
 
   static Handle createHotSpotTypeResolved(KlassHandle klass, Handle name, TRAPS);
   static Handle createHotSpotMethodResolved(methodHandle method, TRAPS);
+  static Handle createHotSpotMethodData(methodDataHandle method_data, TRAPS);
 
   void exit();
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue Feb 07 21:09:31 2012 +0100
@@ -44,6 +44,10 @@
   return (methodOop)HotSpotMethodResolved::javaMirror(hotspot_method);
 }
 
+methodDataOop getMethodDataFromHotSpotMethodData(jobject hotspot_method_data) {
+  return (methodDataOop)HotSpotMethodData::hotspotMirror(JNIHandles::resolve(hotspot_method_data));
+}
+
 // public byte[] RiMethod_code(HotSpotResolvedMethod method);
 JNIEXPORT jbyteArray JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1code(JNIEnv *env, jobject, jobject hotspot_method) {
   TRACE_graal_3("CompilerToVM::RiMethod_code");
@@ -182,26 +186,25 @@
   return getMethodFromHotSpotMethod(hotspot_method)->invocation_count();
 }
 
-// public native int RiMethod_exceptionProbability(long vmId, int bci);
-JNIEXPORT jint JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2exceptionProbability(JNIEnv *, jobject, jobject hotspot_method, jint bci) {
-  TRACE_graal_3("CompilerToVM::RiMethod_exceptionProbability");
+// public native HotSpotMethodData RiMethod_methodData(HotSpotMethodResolved method);
+JNIEXPORT jobject JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1methodData(JNIEnv *, jobject, jobject hotspot_method) {
+  TRACE_graal_3("CompilerToVM::RiMethod_methodData");
   VM_ENTRY_MARK;
-  ResourceMark rm;
-  methodHandle method = getMethodFromHotSpotMethod(hotspot_method);
-  methodDataHandle method_data = method->method_data();
-  if (method_data == NULL || !method_data->is_mature()) {
-    return -1;
+
+  methodDataHandle method_data = getMethodFromHotSpotMethod(hotspot_method)->method_data();
+  if(method_data.is_null()) {
+    return NULL;
+  } else {
+    Handle graalMethodData = GraalCompiler::createHotSpotMethodData(method_data, CHECK_NULL);
+    return JNIHandles::make_local(THREAD, graalMethodData());
   }
-  ProfileData* data = method_data->bci_to_data(bci);
-  if (data == NULL) {
-    return 0;
-  }
-  uint trap = Deoptimization::trap_state_is_recompiled(data->trap_state())? 1: 0;
-  if (trap > 0) {
-    return 100;
-  } else {
-    return trap;
-  }
+}
+
+JNIEXPORT jboolean JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_HotSpotMethodData_1isMature(JNIEnv *, jobject, jobject hotspot_method_data) {
+  TRACE_graal_3("CompilerToVM::HotSpotMethodData_isMature");
+  VM_ENTRY_MARK;
+  methodDataHandle method_data = getMethodDataFromHotSpotMethodData(hotspot_method_data);
+  return method_data->is_mature();
 }
 
 // ------------------------------------------------------------------
@@ -230,137 +233,6 @@
   return count;
 }
 
-// public native RiTypeProfile RiMethod_typeProfile(long vmId, int bci);
-JNIEXPORT jobject JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2typeProfile(JNIEnv *, jobject, jobject hotspot_method, jint bci) {
-  TRACE_graal_3("CompilerToVM::RiMethod_typeProfile");
-  VM_ENTRY_MARK;
-  Handle obj;
-  
-  methodHandle method = getMethodFromHotSpotMethod(hotspot_method);
-  methodDataHandle method_data = method->method_data();
-  if (method_data == NULL || !method_data->is_mature()) {
-    return NULL;
-  }
-  ResourceMark rm;
-  ProfileData* data = method_data->bci_to_data(bci);
-  if (data != NULL && data->is_ReceiverTypeData()) {
-    ReceiverTypeData* recv = data->as_ReceiverTypeData();
-    GrowableArray<KlassHandle> receivers;
-    GrowableArray<int> counts;
-    // determine morphism
-    uint total_count = 0;
-    for (uint i = 0; i < recv->row_limit(); i++) {
-      klassOop receiver = recv->receiver(i);
-      if (receiver == NULL)  continue;
-      uint count = recv->receiver_count(i);
-      total_count += count;
-      receivers.append(receiver);
-      counts.append(count);
-    }
-
-    instanceKlass::cast(RiTypeProfile::klass())->initialize(CHECK_NULL);
-    obj = instanceKlass::cast(RiTypeProfile::klass())->allocate_instance(CHECK_NULL);
-    assert(obj() != NULL, "must succeed in allocating instance");
-
-    int count = MAX2(total_count, recv->count());
-    RiTypeProfile::set_count(obj, scale_count(method_data(), count));
-    RiTypeProfile::set_morphism(obj, receivers.length());
-
-    if (receivers.length() > 0) {
-      typeArrayHandle probabilities = oopFactory::new_typeArray(T_FLOAT, receivers.length(), CHECK_NULL);
-      objArrayHandle types = oopFactory::new_objArray(SystemDictionary::RiType_klass(), receivers.length(), CHECK_NULL);
-      for (int i = 0; i < receivers.length(); i++) {
-        KlassHandle receiver = receivers.at(i);
-
-        float prob = counts.at(i) / (float) total_count;
-        Handle type = GraalCompiler::get_RiType(receiver, CHECK_NULL);
-
-        probabilities->float_at_put(i, prob);
-        types->obj_at_put(i, type());
-
-      }
-
-      RiTypeProfile::set_probabilities(obj, probabilities());
-      RiTypeProfile::set_types(obj, types());
-    } else {
-      RiTypeProfile::set_probabilities(obj, NULL);
-      RiTypeProfile::set_types(obj, NULL);
-    }
-  }
-  return JNIHandles::make_local(obj());
-}
-
-JNIEXPORT jdouble JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2branchProbability(JNIEnv *, jobject, jobject hotspot_method, jint bci) {
-  TRACE_graal_3("CompilerToVM::RiMethod_typeProfile");
-  ResourceMark rm;
-  methodHandle method = getMethodFromHotSpotMethod(hotspot_method);
-  methodDataHandle method_data = method->method_data();
-
-  if (method_data == NULL || !method_data->is_mature()) return -1;
-  method_data->bci_to_data(bci);
-  
-  ProfileData* data = method_data->bci_to_data(bci);
-  if (data == NULL || !data->is_JumpData())  return -1;
-
-  // get taken and not taken values
-  int     taken = data->as_JumpData()->taken();
-  int not_taken = 0;
-  if (data->is_BranchData()) {
-    not_taken = data->as_BranchData()->not_taken();
-  }
-
-  // Give up if too few (or too many, in which case the sum will overflow) counts to be meaningful.
-  // We also check that individual counters are positive first, otherwise the sum can become positive.
-  if (taken < 0 || not_taken < 0 || taken + not_taken < 40) return -1;
-
-  // Pin probability to sane limits
-  if (taken == 0)
-    return 0;
-  else if (not_taken == 0)
-    return 1;
-  else {                         // Compute probability of true path
-    return (jdouble)(taken) / (taken + not_taken);
-  }
-}
-
-JNIEXPORT jobject JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2switchProbability(JNIEnv *, jobject, jobject hotspot_method, jint bci) {
-  TRACE_graal_3("CompilerToVM::RiMethod_typeProfile");
-  VM_ENTRY_MARK;
-  ResourceMark rm;
-  methodHandle method = getMethodFromHotSpotMethod(hotspot_method);
-  methodDataHandle method_data = method->method_data();
-
-  if (method_data == NULL || !method_data->is_mature()) return NULL;
-
-  ProfileData* data = method_data->bci_to_data(bci);
-  if (data == NULL || !data->is_MultiBranchData())  return NULL;
-
-  MultiBranchData* branch_data = data->as_MultiBranchData();
-
-  long sum = 0;
-  int cases = branch_data->number_of_cases();
-  GrowableArray<uint>* counts = new GrowableArray<uint>(cases + 1);
-
-  for (int i = 0; i < cases; i++) {
-    uint value = branch_data->count_at(i);
-    sum += value;
-    counts->append(value);
-  }
-  uint value = branch_data->default_count();
-  sum += value;
-  counts->append(value);
-
-  // Give up if too few (or too many, in which case the sum will overflow) counts to be meaningful.
-  // We also check that individual counters are positive first, otherwise the sum can become positive.
-  if (sum < 10 * (cases + 3)) return NULL;
-
-  typeArrayOop probability = oopFactory::new_typeArray(T_DOUBLE, cases + 1, CHECK_NULL);
-  for (int i = 0; i < cases + 1; i++) {
-    probability->double_at_put(i, counts->at(i) / (double) sum);
-  }
-  return JNIHandles::make_local(probability);
-}
-
 // public native boolean RiMethod_hasCompiledCode(HotSpotMethodResolved method);
 JNIEXPORT jboolean JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1hasCompiledCode(JNIEnv *, jobject, jobject hotspot_method) {
   TRACE_graal_3("CompilerToVM::RiMethod_hasCompiledCode");
@@ -875,6 +747,16 @@
   set_int(env, config, "threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset()));
   set_int(env, config, "threadMultiNewArrayStorage", in_bytes(JavaThread::graal_multinewarray_storage_offset()));
   set_int(env, config, "classMirrorOffset", klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes());
+  
+  set_int(env, config, "methodDataOopDataOffset", in_bytes(methodDataOopDesc::data_offset()));
+  set_int(env, config, "dataLayoutHeaderSize", DataLayout::header_size_in_bytes());
+  set_int(env, config, "dataLayoutTagOffset", in_bytes(DataLayout::tag_offset()));
+  set_int(env, config, "dataLayoutFlagsOffset", in_bytes(DataLayout::flags_offset()));
+  set_int(env, config, "dataLayoutBCIOffset", in_bytes(DataLayout::bci_offset()));
+  set_int(env, config, "dataLayoutCellsOffset", in_bytes(DataLayout::cell_offset(0)));
+  set_int(env, config, "dataLayoutCellSize", DataLayout::cell_size);
+  set_int(env, config, "bciProfileWidth", BciProfileWidth);
+  set_int(env, config, "typeProfileWidth", TypeProfileWidth);
 
   set_long(env, config, "debugStub", VmIds::addStub((address)warning));
   set_long(env, config, "instanceofStub", VmIds::addStub(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
@@ -898,7 +780,9 @@
   set_long(env, config, "safepointPollingAddress", (jlong)(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size())));
   set_int(env, config, "runtimeCallStackSize", (jint)frame::arg_reg_save_area_bytes);
   set_int(env, config, "klassModifierFlagsOffset", Klass::modifier_flags_offset_in_bytes() + sizeof(oopDesc));
+  set_int(env, config, "graalMirrorKlassOffset", klassOopDesc::klass_part_offset_in_bytes() + Klass::graal_mirror_offset_in_bytes());
   set_int(env, config, "klassOopOffset", java_lang_Class::klass_offset_in_bytes());
+
   set_boolean(env, config, "isPollingPageFar", Assembler::is_polling_page_far());
 
   set_int(env, config, "nmethodEntryOffset", nmethod::verified_entry_point_offset());
@@ -1023,7 +907,6 @@
 #define METHOD          "Lcom/oracle/max/cri/ri/RiMethod;"
 #define RESOLVED_METHOD "Lcom/oracle/max/graal/hotspot/ri/HotSpotMethodResolved;"
 #define REFLECT_METHOD  "Ljava/lang/reflect/Method;"
-#define TYPE_PROFILE    "Lcom/oracle/max/cri/ri/RiTypeProfile;"
 #define SIGNATURE       "Lcom/oracle/max/cri/ri/RiSignature;"
 #define FIELD           "Lcom/oracle/max/cri/ri/RiField;"
 #define RESOLVED_FIELD  "Lcom/oracle/max/cri/ri/RiResolvedField;"
@@ -1033,6 +916,7 @@
 #define CONFIG          "Lcom/oracle/max/graal/hotspot/HotSpotVMConfig;"
 #define HS_METHOD       "Lcom/oracle/max/graal/hotspot/ri/HotSpotMethod;"
 #define HS_COMP_METHOD  "Lcom/oracle/max/graal/hotspot/ri/HotSpotCompiledMethod;"
+#define METHOD_DATA     "Lcom/oracle/max/graal/hotspot/ri/HotSpotMethodData;"
 #define CI_CONSTANT     "Lcom/oracle/max/cri/ci/CiConstant;"
 #define CI_KIND         "Lcom/oracle/max/cri/ci/CiKind;"
 #define CI_RUNTIME_CALL "Lcom/oracle/max/cri/ci/CiRuntimeCall;"
@@ -1047,11 +931,9 @@
   {CC"RiMethod_hasBalancedMonitors",      CC"("RESOLVED_METHOD")Z",                   FN_PTR(RiMethod_1hasBalancedMonitors)},
   {CC"RiMethod_uniqueConcreteMethod",     CC"("RESOLVED_METHOD")"METHOD,              FN_PTR(RiMethod_1uniqueConcreteMethod)},
   {CC"getRiMethod",                       CC"("REFLECT_METHOD")"METHOD,               FN_PTR(getRiMethod)},
-  {CC"RiMethod_typeProfile",              CC"("RESOLVED_METHOD"I)"TYPE_PROFILE,       FN_PTR(RiMethod_2typeProfile)},
-  {CC"RiMethod_branchProbability",        CC"("RESOLVED_METHOD"I)D",                  FN_PTR(RiMethod_2branchProbability)},
-  {CC"RiMethod_switchProbability",        CC"("RESOLVED_METHOD"I)[D",                 FN_PTR(RiMethod_2switchProbability)},
+  {CC"RiMethod_methodData",               CC"("RESOLVED_METHOD")"METHOD_DATA,         FN_PTR(RiMethod_1methodData)},
+  {CC"HotSpotMethodData_isMature",        CC"("METHOD_DATA")Z",                       FN_PTR(HotSpotMethodData_1isMature)},
   {CC"RiMethod_invocationCount",          CC"("RESOLVED_METHOD")I",                   FN_PTR(RiMethod_1invocationCount)},
-  {CC"RiMethod_exceptionProbability",     CC"("RESOLVED_METHOD"I)I",                  FN_PTR(RiMethod_2exceptionProbability)},
   {CC"RiMethod_hasCompiledCode",          CC"("RESOLVED_METHOD")Z",                   FN_PTR(RiMethod_1hasCompiledCode)},
   {CC"RiSignature_lookupType",            CC"("STRING RESOLVED_TYPE")"TYPE,           FN_PTR(RiSignature_1lookupType)},
   {CC"RiConstantPool_lookupConstant",     CC"("RESOLVED_TYPE"I)"OBJECT,               FN_PTR(RiConstantPool_1lookupConstant)},
--- a/src/share/vm/graal/graalJavaAccess.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -70,6 +70,13 @@
     boolean_field(HotSpotMethodResolved, canBeInlined)                                  \
     oop_field(HotSpotMethodResolved, callback, "Lcom/oracle/max/cri/ci/CiGenericCallback;") \
   end_class                                                                             \
+  start_class(HotSpotMethodData)                                                        \
+    oop_field(HotSpotMethodData, compiler, "Lcom/oracle/max/graal/hotspot/Compiler;")   \
+    oop_field(HotSpotMethodData, hotspotMirror, "Ljava/lang/Object;")                   \
+    int_field(HotSpotMethodData, normalDataSize)                                        \
+    int_field(HotSpotMethodData, extraDataSize)                                         \
+    boolean_field(HotSpotMethodData, mature)                                            \
+  end_class                                                                             \
   start_class(HotSpotType)                                                              \
     oop_field(HotSpotType, name, "Ljava/lang/String;")                                  \
   end_class                                                                             \
@@ -228,12 +235,6 @@
     oop_field(CiMonitorValue, lockData, "Lcom/oracle/max/cri/ci/CiValue;")              \
     boolean_field(CiMonitorValue, eliminated)                                           \
   end_class                                                                             \
-  start_class(RiTypeProfile)                                                            \
-    int_field(RiTypeProfile, count)                                                     \
-    int_field(RiTypeProfile, morphism)                                                  \
-    oop_field(RiTypeProfile, probabilities, "[F")                                       \
-    oop_field(RiTypeProfile, types, "[Lcom/oracle/max/cri/ri/RiResolvedType;")          \
-  end_class                                                                             \
   /* end*/
 
 #define START_CLASS(name)                       \
--- a/src/share/vm/oops/klass.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/oops/klass.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -386,6 +386,7 @@
   static int secondary_super_cache_offset_in_bytes() { return offset_of(Klass, _secondary_super_cache); }
   static int secondary_supers_offset_in_bytes() { return offset_of(Klass, _secondary_supers); }
   static int java_mirror_offset_in_bytes()   { return offset_of(Klass, _java_mirror); }
+  static int graal_mirror_offset_in_bytes()  { return offset_of(Klass, _graal_mirror); }
   static int modifier_flags_offset_in_bytes(){ return offset_of(Klass, _modifier_flags); }
   static int layout_helper_offset_in_bytes() { return offset_of(Klass, _layout_helper); }
   static int access_flags_offset_in_bytes()  { return offset_of(Klass, _access_flags); }
--- a/src/share/vm/oops/methodDataKlass.cpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/oops/methodDataKlass.cpp	Tue Feb 07 21:09:31 2012 +0100
@@ -35,6 +35,7 @@
 #include "oops/oop.inline2.hpp"
 #include "runtime/handles.inline.hpp"
 #ifndef SERIALGC
+#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
 #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
 #include "oops/oop.pcgc.inline.hpp"
 #endif
@@ -84,6 +85,7 @@
 
   obj->follow_header();
   MarkSweep::mark_and_push(m->adr_method());
+  MarkSweep::mark_and_push(m->adr_graal_mirror());
   ResourceMark rm;
   for (ProfileData* data = m->first_data();
        m->is_valid(data);
@@ -100,6 +102,7 @@
 
   obj->follow_header(cm);
   PSParallelCompact::mark_and_push(cm, m->adr_method());
+  PSParallelCompact::mark_and_push(cm, m->adr_graal_mirror());
   ResourceMark rm;
   for (ProfileData* data = m->first_data();
        m->is_valid(data);
@@ -119,6 +122,7 @@
 
   obj->oop_iterate_header(blk);
   blk->do_oop(m->adr_method());
+  blk->do_oop(m->adr_graal_mirror());
   ResourceMark rm;
   for (ProfileData* data = m->first_data();
        m->is_valid(data);
@@ -140,6 +144,11 @@
   if (mr.contains(adr)) {
     blk->do_oop(m->adr_method());
   }
+  adr = m->adr_graal_mirror();
+  if(mr.contains(adr)) {
+    blk->do_oop(m->adr_graal_mirror());
+  }
+
   ResourceMark rm;
   for (ProfileData* data = m->first_data();
        m->is_valid(data);
@@ -158,6 +167,7 @@
 
   obj->adjust_header();
   MarkSweep::adjust_pointer(m->adr_method());
+  MarkSweep::adjust_pointer(m->adr_graal_mirror());
   ResourceMark rm;
   ProfileData* data;
   for (data = m->first_data(); m->is_valid(data); data = m->next_data(data)) {
@@ -173,6 +183,11 @@
   methodDataOop m = methodDataOop(obj);
   // This should never point into the young gen.
   assert(!PSScavenge::should_scavenge(m->adr_method()), "Sanity");
+ 
+  oop* adr = m->adr_graal_mirror();
+  if(PSScavenge::should_scavenge(adr)) {
+    pm->claim_or_forward_depth(adr);
+  }
 }
 
 int methodDataKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
@@ -180,6 +195,7 @@
   methodDataOop m = methodDataOop(obj);
 
   PSParallelCompact::adjust_pointer(m->adr_method());
+  PSParallelCompact::adjust_pointer(m->adr_graal_mirror());
 
   ResourceMark rm;
   ProfileData* data;
--- a/src/share/vm/oops/methodDataOop.cpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/oops/methodDataOop.cpp	Tue Feb 07 21:09:31 2012 +0100
@@ -749,6 +749,7 @@
   ResourceMark rm;
   // Set the method back-pointer.
   _method = method();
+  _graal_mirror = NULL;
 
   if (TieredCompilation) {
     _invocation_counter.init();
--- a/src/share/vm/oops/methodDataOop.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/oops/methodDataOop.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -1194,6 +1194,9 @@
   // Back pointer to the methodOop
   methodOop _method;
 
+  // com/oracle/max/graal/hotspot/HotSpotProfilingInfo mirroring this method
+  oop               _graal_mirror;
+
   // Size of this oop in bytes
   int _size;
 
@@ -1423,6 +1426,10 @@
   // Accessors
   methodOop method() { return _method; }
 
+  // graal mirror
+  oop graal_mirror() const               { return _graal_mirror; }
+  void set_graal_mirror(oop m)           { oop_store((oop*) &_graal_mirror, m); }
+
   // Get the data at an arbitrary (sort of) data index.
   ProfileData* data_at(int data_index);
 
@@ -1520,6 +1527,7 @@
 
   // GC support
   oop* adr_method() const { return (oop*)&_method; }
+  oop* adr_graal_mirror() const { return (oop*)&_graal_mirror; }
   bool object_is_parsable() const { return _size != 0; }
   void set_object_is_parsable(int object_size_in_bytes) { _size = object_size_in_bytes; }
 
--- a/src/share/vm/oops/methodKlass.cpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/oops/methodKlass.cpp	Tue Feb 07 21:09:31 2012 +0100
@@ -144,11 +144,9 @@
   PSParallelCompact::mark_and_push(cm, m->adr_constMethod());
   PSParallelCompact::mark_and_push(cm, m->adr_constants());
   PSParallelCompact::mark_and_push(cm, m->adr_graal_mirror());
-#ifdef COMPILER2
   if (m->method_data() != NULL) {
     PSParallelCompact::mark_and_push(cm, m->adr_method_data());
   }
-#endif // COMPILER2
 }
 #endif // SERIALGC
 
@@ -221,11 +219,9 @@
   PSParallelCompact::adjust_pointer(m->adr_constMethod());
   PSParallelCompact::adjust_pointer(m->adr_constants());
   PSParallelCompact::adjust_pointer(m->adr_graal_mirror());
-#ifdef COMPILER2
   if (m->method_data() != NULL) {
     PSParallelCompact::adjust_pointer(m->adr_method_data());
   }
-#endif // COMPILER2
   return m->object_size();
 }
 #endif // SERIALGC
--- a/src/share/vm/runtime/globals.hpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/runtime/globals.hpp	Tue Feb 07 21:09:31 2012 +0100
@@ -3124,7 +3124,7 @@
           "if non-zero, start verifying C heap after Nth call to "          \
           "malloc/realloc/free")                                            \
                                                                             \
-  product(intx, TypeProfileWidth,     2,                                   \
+  product_pd(intx, TypeProfileWidth,                                        \
           "number of receiver types to record in call/cast profile")        \
                                                                             \
   develop(intx, BciProfileWidth,      2,                                    \
--- a/src/share/vm/runtime/reflectionUtils.cpp	Sun Feb 05 05:40:36 2012 +0100
+++ b/src/share/vm/runtime/reflectionUtils.cpp	Tue Feb 07 21:09:31 2012 +0100
@@ -82,6 +82,8 @@
   if (UseGraal) {
     compute_offset(offset, SystemDictionary::HotSpotMethodResolved_klass(), "javaMirror", "Ljava/lang/Object;", false);
     _filtered_fields->append(new FilteredField(SystemDictionary::HotSpotMethodResolved_klass(), offset));
+    compute_offset(offset, SystemDictionary::HotSpotMethodData_klass(), "hotspotMirror", "Ljava/lang/Object;", false);
+    _filtered_fields->append(new FilteredField(SystemDictionary::HotSpotMethodData_klass(), offset));
   }
 #endif
 }