changeset 9774:20963f52fdd5

Merge.
author Doug Simon <doug.simon@oracle.com>
date Fri, 17 May 2013 22:45:55 +0200
parents 8a1b0a3d4fc3 (current diff) 2461285a2f90 (diff)
children 5dc05fdcf3c2
files
diffstat 26 files changed, 727 insertions(+), 298 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java	Fri May 17 22:45:55 2013 +0200
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import java.io.*;
+
+/**
+ * This profile object represents a certain set of profiling information 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 abstract class AbstractJavaProfile<T extends AbstractProfiledItem<U>, U> implements Serializable {
+
+    private static final long serialVersionUID = 5493379044459116749L;
+
+    private final double notRecordedProbability;
+    private final T[] pitems;
+
+    public AbstractJavaProfile(double notRecordedProbability, T[] pitems) {
+        this.pitems = pitems;
+        assert notRecordedProbability != Double.NaN;
+        this.notRecordedProbability = notRecordedProbability;
+        assert isSorted();
+    }
+
+    /**
+     * Determines if an array of profiled items are sorted in descending order of their
+     * probabilities.
+     */
+    private boolean isSorted() {
+        for (int i = 1; i < pitems.length; i++) {
+            if (pitems[i - 1].getProbability() < pitems[i].getProbability()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 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;
+    }
+
+    protected T[] getItems() {
+        return pitems;
+    }
+
+    /**
+     * Searches for an entry of a given resolved Java type.
+     * 
+     * @param type the type for which an entry should be searched
+     * @return the entry or null if no entry for this type can be found
+     */
+    public T findEntry(ResolvedJavaType type) {
+        if (pitems != null) {
+            for (T pt : pitems) {
+                if (pt.getItem() == type) {
+                    return pt;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(this.getClass().getName());
+        builder.append("[");
+        if (pitems != null) {
+            for (T pt : pitems) {
+                builder.append(pt.toString());
+                builder.append(", ");
+            }
+        }
+        builder.append(this.notRecordedProbability);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public boolean isIncluded(U item) {
+        if (this.getNotRecordedProbability() > 0.0) {
+            return true;
+        } else {
+            for (int i = 0; i < getItems().length; i++) {
+                T pitem = getItems()[i];
+                U curType = pitem.getItem();
+                if (curType == item) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (getClass() == other.getClass()) {
+            AbstractJavaProfile javaTypeProfile = (AbstractJavaProfile) other;
+            if (javaTypeProfile.notRecordedProbability != notRecordedProbability) {
+                return false;
+            }
+            if (javaTypeProfile.pitems.length != pitems.length) {
+                return false;
+            }
+
+            for (int i = 0; i < pitems.length; ++i) {
+                if (!pitems[i].equals(javaTypeProfile.pitems[i])) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) Double.doubleToLongBits(notRecordedProbability) + pitems.length * 13;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractProfiledItem.java	Fri May 17 22:45:55 2013 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import java.io.*;
+
+/**
+ * A profiled type that has a probability. Profiled types are naturally sorted in descending order
+ * of their probabilities.
+ */
+public abstract class AbstractProfiledItem<T> implements Comparable<AbstractProfiledItem>, Serializable {
+
+    private static final long serialVersionUID = 7838575753661305744L;
+
+    protected final T item;
+    protected final double probability;
+
+    public AbstractProfiledItem(T item, double probability) {
+        assert item != null;
+        assert probability >= 0.0D && probability <= 1.0D;
+        this.item = item;
+        this.probability = probability;
+    }
+
+    protected T getItem() {
+        return item;
+    }
+
+    /**
+     * Returns the estimated probability of {@link #getItem()}.
+     * 
+     * @return double value >= 0.0 and <= 1.0
+     */
+    public double getProbability() {
+        return probability;
+    }
+
+    @Override
+    public int compareTo(AbstractProfiledItem o) {
+        if (getProbability() > o.getProbability()) {
+            return -1;
+        } else if (getProbability() < o.getProbability()) {
+            return 1;
+        }
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        long temp;
+        temp = Double.doubleToLongBits(probability);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        result = prime * result + item.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AbstractProfiledItem other = (AbstractProfiledItem) obj;
+        if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) {
+            return false;
+        }
+        return item.equals(other.item);
+    }
+
+    @Override
+    public abstract String toString();
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java	Fri May 17 22:45:55 2013 +0200
@@ -48,6 +48,11 @@
     }
 
     @Override
+    public JavaMethodProfile getMethodProfile(int bci) {
+        return null;
+    }
+
+    @Override
     public double getBranchTakenProbability(int bci) {
         return -1;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java	Fri May 17 22:45:55 2013 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import com.oracle.graal.api.meta.JavaMethodProfile.ProfiledMethod;
+
+/**
+ * This profile object represents the method 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 final class JavaMethodProfile extends AbstractJavaProfile<ProfiledMethod, ResolvedJavaMethod> {
+
+    private static final long serialVersionUID = -1440572119913692689L;
+
+    public JavaMethodProfile(double notRecordedProbability, ProfiledMethod[] pitems) {
+        super(notRecordedProbability, pitems);
+    }
+
+    public ProfiledMethod[] getMethods() {
+        return super.getItems();
+    }
+
+    public static class ProfiledMethod extends AbstractProfiledItem<ResolvedJavaMethod> {
+
+        private static final long serialVersionUID = 5418813647187024693L;
+
+        public ProfiledMethod(ResolvedJavaMethod item, double probability) {
+            super(item, probability);
+        }
+
+        /**
+         * Returns the type for this profile entry.
+         */
+        public ResolvedJavaMethod getMethod() {
+            return getItem();
+        }
+
+        @Override
+        public String toString() {
+            return "{" + item.getName() + ", " + probability + "}";
+        }
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Fri May 17 22:45:55 2013 +0200
@@ -22,134 +22,26 @@
  */
 package com.oracle.graal.api.meta;
 
-import java.io.*;
 import java.util.*;
 
-import com.oracle.graal.api.meta.ProfilingInfo.*;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 
 /**
  * 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 final class JavaTypeProfile implements Serializable {
+public final class JavaTypeProfile extends AbstractJavaProfile<ProfiledType, ResolvedJavaType> {
 
     private static final long serialVersionUID = -6877016333706838441L;
-
-    /**
-     * A profiled type that has a probability. Profiled types are naturally sorted in descending
-     * order of their probabilities.
-     */
-    public static final class ProfiledType implements Comparable<ProfiledType>, Serializable {
-
-        private static final long serialVersionUID = 7838575753661305744L;
-
-        public static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0];
-
-        private final ResolvedJavaType type;
-        private final double probability;
-
-        public ProfiledType(ResolvedJavaType type, double probability) {
-            assert type != null;
-            assert probability >= 0.0D && probability <= 1.0D;
-            this.type = type;
-            this.probability = probability;
-        }
-
-        /**
-         * Returns the type for this profile entry.
-         */
-        public ResolvedJavaType getType() {
-            return type;
-        }
-
-        /**
-         * Returns the estimated probability of {@link #getType()}.
-         * 
-         * @return double value >= 0.0 and <= 1.0
-         */
-        public double getProbability() {
-            return probability;
-        }
-
-        @Override
-        public int compareTo(ProfiledType o) {
-            if (getProbability() > o.getProbability()) {
-                return -1;
-            } else if (getProbability() < o.getProbability()) {
-                return 1;
-            }
-            return 0;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            long temp;
-            temp = Double.doubleToLongBits(probability);
-            result = prime * result + (int) (temp ^ (temp >>> 32));
-            result = prime * result + type.hashCode();
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            ProfiledType other = (ProfiledType) obj;
-            if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) {
-                return false;
-            }
-            return type.equals(other.type);
-        }
-
-        @Override
-        public String toString() {
-            return "{" + type.getName() + ", " + probability + "}";
-        }
-    }
+    private static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0];
 
     private final TriState nullSeen;
-    private final double notRecordedProbability;
-    private final ProfiledType[] ptypes;
 
-    /**
-     * Determines if an array of profiled types are sorted in descending order of their
-     * probabilities.
-     */
-    private static boolean isSorted(ProfiledType[] ptypes) {
-        for (int i = 1; i < ptypes.length; i++) {
-            if (ptypes[i - 1].getProbability() < ptypes[i].getProbability()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType... ptypes) {
+    public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType[] pitems) {
+        super(notRecordedProbability, pitems);
         this.nullSeen = nullSeen;
-        this.ptypes = ptypes;
-        assert notRecordedProbability != Double.NaN;
-        this.notRecordedProbability = notRecordedProbability;
-        assert isSorted(ptypes);
-    }
-
-    /**
-     * 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;
     }
 
     /**
@@ -165,41 +57,7 @@
      * type and a negative type is not.
      */
     public ProfiledType[] getTypes() {
-        return ptypes;
-    }
-
-    /**
-     * Searches for an entry of a given resolved Java type.
-     * 
-     * @param type the type for which an entry should be searched
-     * @return the entry or null if no entry for this type can be found
-     */
-    public ProfiledType findEntry(ResolvedJavaType type) {
-        if (ptypes != null) {
-            for (ProfiledType pt : ptypes) {
-                if (pt.getType() == type) {
-                    return pt;
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("JavaTypeProfile[");
-        builder.append(this.nullSeen);
-        builder.append(", ");
-        if (ptypes != null) {
-            for (ProfiledType pt : ptypes) {
-                builder.append(pt.toString());
-                builder.append(", ");
-            }
-        }
-        builder.append(this.notRecordedProbability);
-        builder.append("]");
-        return builder.toString();
+        return getItems();
     }
 
     public JavaTypeProfile restrict(JavaTypeProfile otherProfile) {
@@ -214,57 +72,42 @@
         }
 
         ArrayList<ProfiledType> result = new ArrayList<>();
-        for (int i = 0; i < getTypes().length; i++) {
-            ProfiledType ptype = getTypes()[i];
-            ResolvedJavaType type = ptype.getType();
+        for (int i = 0; i < getItems().length; i++) {
+            ProfiledType ptype = getItems()[i];
+            ResolvedJavaType type = ptype.getItem();
             if (otherProfile.isIncluded(type)) {
                 result.add(ptype);
             }
         }
 
-        TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : this.nullSeen;
-        double newNotRecorded = this.notRecordedProbability;
+        TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : getNullSeen();
+        double newNotRecorded = getNotRecordedProbability();
         return createAdjustedProfile(result, newNullSeen, newNotRecorded);
     }
 
-    public boolean isIncluded(ResolvedJavaType type) {
-        if (this.getNotRecordedProbability() > 0.0) {
-            return true;
-        } else {
-            for (int i = 0; i < getTypes().length; i++) {
-                ProfiledType ptype = getTypes()[i];
-                ResolvedJavaType curType = ptype.getType();
-                if (curType == type) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) {
         ArrayList<ProfiledType> result = new ArrayList<>();
-        for (int i = 0; i < getTypes().length; i++) {
-            ProfiledType ptype = getTypes()[i];
-            ResolvedJavaType type = ptype.getType();
+        for (int i = 0; i < getItems().length; i++) {
+            ProfiledType ptype = getItems()[i];
+            ResolvedJavaType type = ptype.getItem();
             if (declaredType.isAssignableFrom(type)) {
                 result.add(ptype);
             }
         }
 
-        TriState newNullSeen = (nonNull) ? TriState.FALSE : this.nullSeen;
+        TriState newNullSeen = (nonNull) ? TriState.FALSE : getNullSeen();
         double newNotRecorded = this.getNotRecordedProbability();
         // Assume for the types not recorded, the incompatibility rate is the same.
-        if (getTypes().length != 0) {
-            newNotRecorded *= ((double) result.size() / (double) getTypes().length);
+        if (getItems().length != 0) {
+            newNotRecorded *= ((double) result.size() / (double) getItems().length);
         }
         return createAdjustedProfile(result, newNullSeen, newNotRecorded);
     }
 
     private JavaTypeProfile createAdjustedProfile(ArrayList<ProfiledType> result, TriState newNullSeen, double newNotRecorded) {
-        if (result.size() != this.getTypes().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != this.nullSeen) {
+        if (result.size() != this.getItems().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != getNullSeen()) {
             if (result.size() == 0) {
-                return new JavaTypeProfile(newNullSeen, 1.0, ProfiledType.EMPTY_ARRAY);
+                return new JavaTypeProfile(newNullSeen, 1.0, EMPTY_ARRAY);
             }
             double probabilitySum = 0.0;
             for (int i = 0; i < result.size(); i++) {
@@ -277,7 +120,7 @@
             ProfiledType[] newResult = new ProfiledType[result.size()];
             for (int i = 0; i < newResult.length; ++i) {
                 ProfiledType curType = result.get(i);
-                newResult[i] = new ProfiledType(curType.getType(), Math.min(1.0, curType.getProbability() * factor));
+                newResult[i] = new ProfiledType(curType.getItem(), Math.min(1.0, curType.getProbability() * factor));
             }
             double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor);
             return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult);
@@ -287,34 +130,32 @@
 
     @Override
     public boolean equals(Object other) {
-        if (other == this) {
-            return true;
-        }
-        if (other instanceof JavaTypeProfile) {
-            JavaTypeProfile javaTypeProfile = (JavaTypeProfile) other;
-            if (javaTypeProfile.nullSeen != nullSeen) {
-                return false;
-            }
-            if (javaTypeProfile.notRecordedProbability != notRecordedProbability) {
-                return false;
-            }
-            if (javaTypeProfile.ptypes.length != ptypes.length) {
-                return false;
-            }
-
-            for (int i = 0; i < ptypes.length; ++i) {
-                if (!ptypes[i].equals(javaTypeProfile.ptypes[i])) {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-        return false;
+        return super.equals(other) && nullSeen.equals(((JavaTypeProfile) other).nullSeen);
     }
 
     @Override
     public int hashCode() {
-        return nullSeen.hashCode() + (int) Double.doubleToLongBits(notRecordedProbability) + ptypes.length * 13;
+        return nullSeen.hashCode() + super.hashCode();
+    }
+
+    public static class ProfiledType extends AbstractProfiledItem<ResolvedJavaType> {
+
+        private static final long serialVersionUID = 1481773321889860837L;
+
+        public ProfiledType(ResolvedJavaType item, double probability) {
+            super(item, probability);
+        }
+
+        /**
+         * Returns the type for this profile entry.
+         */
+        public ResolvedJavaType getType() {
+            return getItem();
+        }
+
+        @Override
+        public String toString() {
+            return "{" + item.getName() + ", " + probability + "}";
+        }
     }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Fri May 17 22:45:55 2013 +0200
@@ -28,7 +28,6 @@
 import java.lang.reflect.*;
 import java.util.*;
 
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 
 /**
@@ -546,21 +545,10 @@
             }
 
             JavaTypeProfile typeProfile = info.getTypeProfile(i);
-            if (typeProfile != null) {
-                ProfiledType[] ptypes = typeProfile.getTypes();
-                if (ptypes != null) {
-                    buf.append(String.format("types@%d:", i));
-                    for (int j = 0; j < ptypes.length; j++) {
-                        ProfiledType ptype = ptypes[j];
-                        buf.append(String.format(" %.6f (%s)%s", ptype.getProbability(), ptype.getType(), sep));
-                    }
-                    if (typeProfile.getNotRecordedProbability() != 0) {
-                        buf.append(String.format(" %.6f <other types>%s", typeProfile.getNotRecordedProbability(), sep));
-                    } else {
-                        buf.append(String.format(" <no other types>%s", sep));
-                    }
-                }
-            }
+            appendProfile(buf, typeProfile, i, "types", sep);
+
+            JavaMethodProfile methodProfile = info.getMethodProfile(i);
+            appendProfile(buf, methodProfile, i, "methods", sep);
         }
 
         boolean firstDeoptReason = true;
@@ -582,6 +570,24 @@
         return s.substring(0, s.length() - sep.length());
     }
 
+    private static void appendProfile(StringBuilder buf, AbstractJavaProfile profile, int bci, String type, String sep) {
+        if (profile != null) {
+            AbstractProfiledItem[] pitems = profile.getItems();
+            if (pitems != null) {
+                buf.append(String.format("%s@%d:", type, bci));
+                for (int j = 0; j < pitems.length; j++) {
+                    AbstractProfiledItem pitem = pitems[j];
+                    buf.append(String.format(" %.6f (%s)%s", pitem.getProbability(), pitem.getItem(), sep));
+                }
+                if (profile.getNotRecordedProbability() != 0) {
+                    buf.append(String.format(" %.6f <other %s>%s", profile.getNotRecordedProbability(), type, sep));
+                } else {
+                    buf.append(String.format(" <no other %s>%s", type, sep));
+                }
+            }
+        }
+    }
+
     /**
      * Converts a Java source-language class name into the internal form.
      * 
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java	Fri May 17 22:45:55 2013 +0200
@@ -66,25 +66,31 @@
     /**
      * Returns the TypeProfile for the given BCI.
      * 
-     * @return Returns an JavaTypeProfile object, or null if not available.
+     * @return Returns a JavaTypeProfile object, or null if not available.
      */
     JavaTypeProfile getTypeProfile(int bci);
 
     /**
+     * Returns the MethodProfile for the given BCI.
+     * 
+     * @return Returns a JavaMethodProfile object, or null if not available.
+     */
+    JavaMethodProfile getMethodProfile(int bci);
+
+    /**
      * Returns information if the given BCI did ever throw an exception.
      * 
      * @return {@link TriState#TRUE} if the instruction has thrown an exception at least once,
-     *         {@link TriState#FALSE} if it never threw an exception, and
-     *         {@link TriState#UNKNOWN} if this information was not recorded.
+     *         {@link TriState#FALSE} if it never threw an exception, and {@link TriState#UNKNOWN}
+     *         if this information was not recorded.
      */
     TriState getExceptionSeen(int bci);
 
     /**
      * Returns information if null was ever seen for the given BCI.
      * 
-     * @return {@link TriState#TRUE} if null was seen for the instruction,
-     *         {@link TriState#FALSE} if null was NOT seen, and
-     *         {@link TriState#UNKNOWN} if this information was not recorded.
+     * @return {@link TriState#TRUE} if null was seen for the instruction, {@link TriState#FALSE} if
+     *         null was NOT seen, and {@link TriState#UNKNOWN} if this information was not recorded.
      */
     TriState getNullSeen(int bci);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java	Fri May 17 22:45:55 2013 +0200
@@ -105,7 +105,7 @@
     }
 
     @Test
-    public void testTypeProfileInvokeVirtual() {
+    public void testProfileInvokeVirtual() {
         testTypeProfile("invokeVirtualSnippet", 1);
     }
 
@@ -140,18 +140,18 @@
         return obj instanceof Serializable;
     }
 
-    private void testTypeProfile(String methodName, int bci) {
+    private void testTypeProfile(String testSnippet, int bci) {
         ResolvedJavaType stringType = runtime.lookupJavaType(String.class);
         ResolvedJavaType stringBuilderType = runtime.lookupJavaType(StringBuilder.class);
 
-        ProfilingInfo info = profile(methodName, "ABC");
+        ProfilingInfo info = profile(testSnippet, "ABC");
         JavaTypeProfile typeProfile = info.getTypeProfile(bci);
         Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA);
         Assert.assertEquals(1, typeProfile.getTypes().length);
         Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType());
         Assert.assertEquals(1.0, typeProfile.getTypes()[0].getProbability(), DELTA);
 
-        continueProfiling(methodName, new StringBuilder());
+        continueProfiling(testSnippet, new StringBuilder());
         typeProfile = info.getTypeProfile(bci);
         Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA);
         Assert.assertEquals(2, typeProfile.getTypes().length);
@@ -160,7 +160,7 @@
         Assert.assertEquals(0.5, typeProfile.getTypes()[0].getProbability(), DELTA);
         Assert.assertEquals(0.5, typeProfile.getTypes()[1].getProbability(), DELTA);
 
-        resetProfile(methodName);
+        resetProfile(testSnippet);
         typeProfile = info.getTypeProfile(bci);
         Assert.assertNull(typeProfile);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri May 17 22:45:55 2013 +0200
@@ -226,6 +226,16 @@
     public int constMethodMaxStackOffset;
 
     /**
+     * Offset of _constants in a metaspace ConstMethod object.
+     */
+    public int constMethodConstantsOffset;
+
+    /**
+     * Offset of _pool_holder in a metaspace ConstantPool object.
+     */
+    public int constantPoolHolderOffset;
+
+    /**
      * Value of extra_stack_entries() in method.hpp.
      */
     public int extraStackEntries;
@@ -365,6 +375,7 @@
     public int dataLayoutCellSize;
     public int bciProfileWidth;
     public int typeProfileWidth;
+    public int methodProfileWidth;
 
     public long inlineCacheMissStub;
     public long handleDeoptStub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Fri May 17 22:45:55 2013 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graph.FieldIntrospection.*;
+import static com.oracle.graal.graph.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaMethodProfile.ProfiledMethod;
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.hotspot.*;
@@ -204,6 +205,11 @@
         }
 
         @Override
+        public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) {
+            return null;
+        }
+
+        @Override
         public double getBranchTakenProbability(HotSpotMethodData data, int position) {
             return -1;
         }
@@ -332,14 +338,14 @@
 
     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(2) + RECEIVER_TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
-        protected static final int NONPROFILED_RECEIVER_COUNT_OFFSET = cellIndexToOffset(1);
-        private static final int RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET = cellIndexToOffset(2);
-        private static final int RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET = cellIndexToOffset(3);
+        protected static final int TYPE_DATA_ROW_SIZE = cellsToBytes(2);
 
-        protected AbstractTypeData(int tag) {
-            super(tag, RECEIVER_TYPE_DATA_SIZE);
+        protected static final int NONPROFILED_COUNT_OFFSET = cellIndexToOffset(1);
+        protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2);
+        protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3);
+
+        protected AbstractTypeData(int tag, int staticSize) {
+            super(tag, staticSize);
         }
 
         @Override
@@ -352,10 +358,10 @@
             int entries = 0;
 
             for (int i = 0; i < typeProfileWidth; i++) {
-                long receiverKlass = data.readWord(position, getReceiverOffset(i));
+                long receiverKlass = data.readWord(position, getTypeOffset(i));
                 if (receiverKlass != 0) {
                     types[entries] = HotSpotResolvedObjectType.fromMetaspaceKlass(receiverKlass);
-                    long count = data.readUnsignedInt(position, getCountOffset(i));
+                    long count = data.readUnsignedInt(position, getTypeCountOffset(i));
                     totalCount += count;
                     counts[entries] = count;
 
@@ -390,21 +396,22 @@
             return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes);
         }
 
-        private static int getReceiverOffset(int row) {
-            return RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET + row * RECEIVER_TYPE_DATA_ROW_SIZE;
+        private static int getTypeOffset(int row) {
+            return TYPE_DATA_FIRST_TYPE_OFFSET + row * TYPE_DATA_ROW_SIZE;
         }
 
-        protected static int getCountOffset(int row) {
-            return RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET + row * RECEIVER_TYPE_DATA_ROW_SIZE;
+        protected static int getTypeCountOffset(int row) {
+            return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE;
         }
     }
 
     private static class TypeCheckData extends AbstractTypeData {
 
-        private static final int RECEIVER_TYPE_DATA_TAG = 4;
+        private static final int TYPE_CHECK_DATA_TAG = 4;
+        private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
 
         public TypeCheckData() {
-            super(RECEIVER_TYPE_DATA_TAG);
+            super(TYPE_CHECK_DATA_TAG, TYPE_CHECK_DATA_SIZE);
         }
 
         @Override
@@ -414,16 +421,19 @@
 
         @Override
         protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
-            return data.readUnsignedIntAsSignedInt(position, NONPROFILED_RECEIVER_COUNT_OFFSET);
+            return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET);
         }
     }
 
     private static class VirtualCallData extends AbstractTypeData {
 
         private static final int VIRTUAL_CALL_DATA_TAG = 5;
+        private static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth);
+        private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
+        private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
 
         public VirtualCallData() {
-            super(VIRTUAL_CALL_DATA_TAG);
+            super(VIRTUAL_CALL_DATA_TAG, VIRTUAL_CALL_DATA_SIZE);
         }
 
         @Override
@@ -432,7 +442,7 @@
 
             long total = 0;
             for (int i = 0; i < typeProfileWidth; i++) {
-                total += data.readUnsignedInt(position, getCountOffset(i));
+                total += data.readUnsignedInt(position, getTypeCountOffset(i));
             }
 
             total += getCounterValue(data, position);
@@ -443,6 +453,64 @@
         protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
             return getCounterValue(data, position);
         }
+
+        private static long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) {
+            return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET);
+        }
+
+        @Override
+        public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) {
+            int profileWidth = config.methodProfileWidth;
+
+            ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth];
+            long[] counts = new long[profileWidth];
+            long totalCount = 0;
+            int entries = 0;
+
+            for (int i = 0; i < profileWidth; i++) {
+                long method = data.readWord(position, getMethodOffset(i));
+                if (method != 0) {
+                    methods[entries] = HotSpotResolvedJavaMethod.fromMetaspace(method);
+                    long count = data.readUnsignedInt(position, getMethodCountOffset(i));
+                    totalCount += count;
+                    counts[entries] = count;
+
+                    entries++;
+                }
+            }
+
+            totalCount += getMethodsNotRecordedExecutionCount(data, position);
+            return createMethodProfile(methods, counts, totalCount, entries);
+        }
+
+        private static JavaMethodProfile createMethodProfile(ResolvedJavaMethod[] methods, long[] counts, long totalCount, int entries) {
+            if (entries <= 0 || totalCount < GraalOptions.MatureExecutionsTypeProfile) {
+                return null;
+            }
+
+            ProfiledMethod[] pmethods = new ProfiledMethod[entries];
+            double totalProbability = 0.0;
+            for (int i = 0; i < entries; i++) {
+                double p = counts[i];
+                p = p / totalCount;
+                totalProbability += p;
+                pmethods[i] = new ProfiledMethod(methods[i], p);
+            }
+
+            Arrays.sort(pmethods);
+
+            double notRecordedMethodProbability = entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
+            assert notRecordedMethodProbability == 0 || entries == config.methodProfileWidth;
+            return new JavaMethodProfile(notRecordedMethodProbability, pmethods);
+        }
+
+        private static int getMethodOffset(int row) {
+            return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE;
+        }
+
+        private static int getMethodCountOffset(int row) {
+            return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE;
+        }
     }
 
     private static class RetData extends CounterData {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Fri May 17 22:45:55 2013 +0200
@@ -55,6 +55,8 @@
 
     JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position);
 
+    JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position);
+
     double getBranchTakenProbability(HotSpotMethodData data, int position);
 
     double[] getSwitchProbabilities(HotSpotMethodData data, int position);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java	Fri May 17 22:45:55 2013 +0200
@@ -57,6 +57,12 @@
     }
 
     @Override
+    public JavaMethodProfile getMethodProfile(int bci) {
+        findBCI(bci, false);
+        return dataAccessor.getMethodProfile(methodData, position);
+    }
+
+    @Override
     public double getBranchTakenProbability(int bci) {
         findBCI(bci, false);
         return dataAccessor.getBranchTakenProbability(methodData, position);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Fri May 17 22:45:55 2013 +0200
@@ -66,6 +66,35 @@
     private CompilationTask currentTask;
     private SpeculationLog speculationLog;
 
+    /**
+     * Gets the holder of a HotSpot metaspace method native object.
+     * 
+     * @param metaspaceMethod a metaspace Method object
+     * @return the {@link ResolvedJavaType} corresponding to the holder of the
+     *         {@code metaspaceMethod}
+     */
+    public static HotSpotResolvedObjectType getHolder(long metaspaceMethod) {
+        HotSpotVMConfig config = graalRuntime().getConfig();
+        long constMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset);
+        assert constMethod != 0;
+        long constantPool = unsafe.getLong(constMethod + config.constMethodConstantsOffset);
+        assert constantPool != 0;
+        long holder = unsafe.getLong(constantPool + config.constantPoolHolderOffset);
+        assert holder != 0;
+        return (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromMetaspaceKlass(holder);
+    }
+
+    /**
+     * Gets the {@link ResolvedJavaMethod} for a HotSpot metaspace method native object.
+     * 
+     * @param metaspaceMethod a metaspace Method object
+     * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod}
+     */
+    public static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) {
+        HotSpotResolvedObjectType holder = getHolder(metaspaceMethod);
+        return holder.createMethod(metaspaceMethod);
+    }
+
     HotSpotResolvedJavaMethod(HotSpotResolvedObjectType holder, long metaspaceMethod) {
         this.metaspaceMethod = metaspaceMethod;
         this.holder = holder;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri May 17 22:45:24 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri May 17 22:45:55 2013 +0200
@@ -60,7 +60,7 @@
     public static int     TrivialInliningSize                = 10;
     public static int     MaximumInliningSize                = 300;
     public static int     SmallCompiledLowLevelGraphSize     = 300;
-    public static double  LimitInlinedInvokes                = 10.0;
+    public static double  LimitInlinedInvokes                = 5.0;
 
     // escape analysis settings
     public static boolean PartialEscapeAnalysis              = true;
--- a/src/cpu/sparc/vm/c2_globals_sparc.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp	Fri May 17 22:45:55 2013 +0200
@@ -38,6 +38,7 @@
 define_pd_global(bool, ProfileTraps,                 true);
 define_pd_global(bool, UseOnStackReplacement,        true);
 define_pd_global(intx, TypeProfileWidth,             2   );
+define_pd_global(intx, MethodProfileWidth,           0   );
 #ifdef CC_INTERP
 define_pd_global(bool, ProfileInterpreter,           false);
 #else
--- a/src/cpu/x86/vm/c1_globals_x86.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/cpu/x86/vm/c1_globals_x86.hpp	Fri May 17 22:45:55 2013 +0200
@@ -56,6 +56,7 @@
 define_pd_global(uint64_t,MaxRAM,                    1ULL*G);
 define_pd_global(bool, CICompileOSR,                 true );
 define_pd_global(intx, TypeProfileWidth,             0);
+define_pd_global(intx, MethodProfileWidth,           0);
 #endif // !TIERED
 define_pd_global(bool, UseTypeProfile,               false);
 define_pd_global(bool, RoundFPResults,               true );
--- a/src/cpu/x86/vm/c2_globals_x86.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/cpu/x86/vm/c2_globals_x86.hpp	Fri May 17 22:45:55 2013 +0200
@@ -40,6 +40,7 @@
 define_pd_global(bool, ProfileTraps,                 true);
 define_pd_global(bool, UseOnStackReplacement,        true);
 define_pd_global(intx, TypeProfileWidth,             2   );
+define_pd_global(intx, MethodProfileWidth,           0   );
 #ifdef CC_INTERP
 define_pd_global(bool, ProfileInterpreter,           false);
 #else
--- a/src/cpu/x86/vm/graalGlobals_x86.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/cpu/x86/vm/graalGlobals_x86.hpp	Fri May 17 22:45:55 2013 +0200
@@ -58,6 +58,7 @@
 define_pd_global(intx, CodeCacheExpansionSize,       64*K );
 define_pd_global(uintx,CodeCacheMinBlockLength,      4);
 define_pd_global(intx, TypeProfileWidth,             8);
+define_pd_global(intx, MethodProfileWidth,           4);
 #endif
 
 #endif // CPU_X86_VM_GRAALGLOBALS_X86_HPP
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp	Fri May 17 22:45:55 2013 +0200
@@ -1082,9 +1082,10 @@
     increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
 
     // The method data pointer needs to be updated to reflect the new target.
-    update_mdp_by_constant(mdp,
-                           in_bytes(VirtualCallData::
+    update_mdp_by_constant(mdp,
+                           in_bytes(VirtualCallData::
                                     virtual_call_data_size()));
+
     bind(profile_continue);
   }
 }
@@ -1116,13 +1117,38 @@
     bind(skip_receiver_profile);
 
     // The method data pointer needs to be updated to reflect the new target.
-    update_mdp_by_constant(mdp,
-                           in_bytes(VirtualCallData::
-                                    virtual_call_data_size()));
+#ifdef GRAAL
+    if (MethodProfileWidth == 0) {
+      update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size()));
+    }
+#else
+    update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size()));
+#endif
     bind(profile_continue);
   }
 }
 
+#ifdef GRAAL
+void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) {
+  assert_different_registers(method, mdp, reg2);
+  if (ProfileInterpreter && MethodProfileWidth > 0) {
+    Label profile_continue;
+
+    // If no method data exists, go to profile_continue.
+    test_method_data_pointer(mdp, profile_continue);
+    
+    Label done;
+    record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth,
+      &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset()));
+    bind (done);
+
+    update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size()));
+    bind(profile_continue);
+  }
+}
+
+#endif
+
 // This routine creates a state machine for updating the multi-row
 // type profile at a virtual call site (or other type-sensitive bytecode).
 // The machine visits each row (of receiver/count) until the receiver type
@@ -1136,8 +1162,7 @@
 // See below for example code.
 void InterpreterMacroAssembler::record_klass_in_profile_helper(
                                         Register receiver, Register mdp,
-                                        Register reg2, int start_row,
-                                        Label& done, bool is_virtual_call) {
+                                        Register reg2, Label& done, bool is_virtual_call) {
   if (TypeProfileWidth == 0) {
     if (is_virtual_call) {
       increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
@@ -1147,14 +1172,33 @@
       increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()));
     }
 #endif
-    return;
-  }
+  } else {                                      
+    bool use_non_profiled_counter = !is_virtual_call || IS_GRAAL_DEFINED;
+    int non_profiled_offset = -1;
+    if (use_non_profiled_counter) {
+       non_profiled_offset = in_bytes(CounterData::count_offset());
+    #ifdef GRAAL
+      if (!is_virtual_call) {
+        non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset());
+      }
+    #endif
+      assert(non_profiled_offset >= 0, "must be");
+    }
 
-  int last_row = VirtualCallData::row_limit() - 1;
+    record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth,
+      &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset);
+  }
+}
+
+void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp,
+                                        Register reg2, int start_row, Label& done, int total_rows,
+                                        OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
+                                        int non_profiled_offset) {
+  int last_row = total_rows - 1;
   assert(start_row <= last_row, "must be work left to do");
-  // Test this row for both the receiver and for null.
+  // Test this row for both the item and for null.
   // Take any of three different outcomes:
-  //   1. found receiver => increment count and goto done
+  //   1. found item => increment count and goto done
   //   2. found null => keep looking for case 1, maybe allocate this cell
   //   3. found something else => keep looking for cases 1 and 2
   // Case 3 is handled by a recursive call.
@@ -1162,36 +1206,30 @@
     Label next_test;
     bool test_for_null_also = (row == start_row);
 
-    // See if the receiver is receiver[n].
-    int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row));
-    test_mdp_data_at(mdp, recvr_offset, receiver,
+    // See if the item is item[n].
+    int item_offset = in_bytes(item_offset_fn(row));
+    test_mdp_data_at(mdp, item_offset, item,
                      (test_for_null_also ? reg2 : noreg),
                      next_test);
-    // (Reg2 now contains the receiver from the CallData.)
+    // (Reg2 now contains the item from the CallData.)
 
-    // The receiver is receiver[n].  Increment count[n].
-    int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row));
+    // The item is item[n].  Increment count[n].
+    int count_offset = in_bytes(item_count_offset_fn(row));
     increment_mdp_data_at(mdp, count_offset);
     jmp(done);
     bind(next_test);
 
     if (test_for_null_also) {
       Label found_null;
-      // Failed the equality check on receiver[n]...  Test for null.
+      // Failed the equality check on item[n]...  Test for null.
       testptr(reg2, reg2);
       if (start_row == last_row) {
         // The only thing left to do is handle the null case.
-        if (is_virtual_call GRAAL_ONLY(|| true)) {
+        if (non_profiled_offset >= 0) {
           jccb(Assembler::zero, found_null);
-          // Receiver did not match any saved receiver and there is no empty row for it.
+          // Item did not match any saved item and there is no empty row for it.
           // Increment total counter to indicate polymorphic case.
-          int offset = in_bytes(CounterData::count_offset());
-#ifdef GRAAL
-          if (!is_virtual_call) {
-            offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset());
-          }
-#endif
-          increment_mdp_data_at(mdp, offset);
+          increment_mdp_data_at(mdp, non_profiled_offset);
           jmp(done);
           bind(found_null);
         } else {
@@ -1203,21 +1241,22 @@
       jcc(Assembler::zero, found_null);
 
       // Put all the "Case 3" tests here.
-      record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call);
+      record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows,
+        item_offset_fn, item_count_offset_fn, non_profiled_offset);
 
-      // Found a null.  Keep searching for a matching receiver,
+      // Found a null.  Keep searching for a matching item,
       // but remember that this is an empty (unused) slot.
       bind(found_null);
     }
   }
 
-  // In the fall-through case, we found no matching receiver, but we
-  // observed the receiver[start_row] is NULL.
+  // In the fall-through case, we found no matching item, but we
+  // observed the item[start_row] is NULL.
 
-  // Fill in the receiver field and increment the count.
-  int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row));
-  set_mdp_data_at(mdp, recvr_offset, receiver);
-  int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
+  // Fill in the item field and increment the count.
+  int item_offset = in_bytes(item_offset_fn(start_row));
+  set_mdp_data_at(mdp, item_offset, item);
+  int count_offset = in_bytes(item_count_offset_fn(start_row));
   movl(reg2, DataLayout::counter_increment);
   set_mdp_data_at(mdp, count_offset, reg2);
   if (start_row > 0) {
@@ -1255,7 +1294,7 @@
   assert(ProfileInterpreter, "must be profiling");
   Label done;
 
-  record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call);
+  record_klass_in_profile_helper(receiver, mdp, reg2, done, is_virtual_call);
 
   bind (done);
 }
@@ -1310,7 +1349,7 @@
     // The method data pointer needs to be updated.
     int mdp_delta = in_bytes(BitData::bit_data_size());
     if (TypeProfileCasts) {
-      mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
+      mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size());
     }
     update_mdp_by_constant(mdp, mdp_delta);
 
@@ -1328,7 +1367,7 @@
 
     int count_offset = in_bytes(CounterData::count_offset());
     // Back up the address, since we have already bumped the mdp.
-    count_offset -= in_bytes(VirtualCallData::virtual_call_data_size());
+    count_offset -= in_bytes(ReceiverTypeData::receiver_type_data_size());
 
     // *Decrement* the counter.  We expect to see zero or small negatives.
     increment_mdp_data_at(mdp, count_offset, true);
@@ -1348,7 +1387,7 @@
     // The method data pointer needs to be updated.
     int mdp_delta = in_bytes(BitData::bit_data_size());
     if (TypeProfileCasts) {
-      mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
+      mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size());
 
       // Record the object type.
       record_klass_in_profile(klass, mdp, reg2, false);
--- a/src/cpu/x86/vm/interp_masm_x86_64.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp	Fri May 17 22:45:55 2013 +0200
@@ -32,6 +32,7 @@
 
 // This file specializes the assember with interpreter-specific macros
 
+typedef ByteSize (*OffsetFunction)(uint);
 
 class InterpreterMacroAssembler: public MacroAssembler {
 #ifndef CC_INTERP
@@ -213,8 +214,11 @@
   void record_klass_in_profile(Register receiver, Register mdp,
                                Register reg2, bool is_virtual_call);
   void record_klass_in_profile_helper(Register receiver, Register mdp,
-                                      Register reg2, int start_row,
-                                      Label& done, bool is_virtual_call);
+                                      Register reg2, Label& done, bool is_virtual_call);
+  void record_item_in_profile_helper(Register item, Register mdp,
+                                        Register reg2, int start_row, Label& done, int total_rows,
+                                        OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
+                                        int non_profiled_offset);
 
   void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
   void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
@@ -228,6 +232,7 @@
   void profile_virtual_call(Register receiver, Register mdp,
                             Register scratch2,
                             bool receiver_can_be_null = false);
+  void profile_called_method(Register method, Register mdp, Register reg2);
   void profile_ret(Register return_bci, Register mdp);
   void profile_null_seen(Register mdp);
   void profile_typecheck(Register mdp, Register klass, Register scratch);
--- a/src/cpu/x86/vm/templateTable_x86_64.cpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/cpu/x86/vm/templateTable_x86_64.cpp	Fri May 17 22:45:55 2013 +0200
@@ -3017,6 +3017,10 @@
 
   // get target Method* & entry point
   __ lookup_virtual_method(rax, index, method);
+#ifdef GRAAL
+  // r14: MethodDataPointer (r14 is callee saved)
+  __ profile_called_method(method, r14, r13);
+#endif
   __ jump_from_interpreted(method, rdx);
 }
 
@@ -3101,7 +3105,7 @@
   __ lookup_interface_method(// inputs: rec. class, interface, itable index
                              rdx, rax, rbx,
                              // outputs: method, scan temp. reg
-                             rbx, r13,
+                             rbx, r14,
                              no_such_interface);
 
   // rbx: Method* to call
@@ -3116,6 +3120,10 @@
   // do the call
   // rcx: receiver
   // rbx,: Method*
+#ifdef GRAAL
+  // r13: MethodDataPointer (r13 is callee saved)
+  __ profile_called_method(rbx, r13, r14);
+#endif
   __ jump_from_interpreted(rbx, rdx);
   __ should_not_reach_here();
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri May 17 22:45:55 2013 +0200
@@ -687,6 +687,8 @@
   set_int("methodMaxLocalsOffset", in_bytes(ConstMethod::size_of_locals_offset()));
   set_int("methodConstMethodOffset", in_bytes(Method::const_offset()));
   set_int("constMethodMaxStackOffset", in_bytes(ConstMethod::max_stack_offset()));
+  set_int("constMethodConstantsOffset", in_bytes(ConstMethod::constants_offset()));
+  set_int("constantPoolHolderOffset", ConstantPool::pool_holder_offset_in_bytes());
   set_int("extraStackEntries", Method::extra_stack_entries());
   set_int("methodAccessFlagsOffset", in_bytes(Method::access_flags_offset()));
   set_int("methodIntrinsicIdOffset", Method::intrinsic_id_offset_in_bytes());
@@ -730,6 +732,7 @@
   set_int("dataLayoutCellSize", DataLayout::cell_size);
   set_int("bciProfileWidth", BciProfileWidth);
   set_int("typeProfileWidth", TypeProfileWidth);
+  set_int("methodProfileWidth", MethodProfileWidth);
 
   set_int("tlabAlignmentReserve", (int32_t)ThreadLocalAllocBuffer::alignment_reserve());
   set_long("tlabIntArrayMarkWord", (intptr_t)markOopDesc::prototype()->copy_set_hash(0x2));
--- a/src/share/vm/oops/methodData.cpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/share/vm/oops/methodData.cpp	Fri May 17 22:45:55 2013 +0200
@@ -168,6 +168,18 @@
   }
 }
 
+#ifdef GRAAL
+void VirtualCallData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
+  ReceiverTypeData::clean_weak_klass_links(is_alive_cl);
+  for (uint row = 0; row < method_row_limit(); row++) {
+    Method* p = method(row);
+    if (p != NULL && !p->method_holder()->is_loader_alive(is_alive_cl)) {
+      clear_method_row(row);
+    }
+  }
+}
+#endif // GRAAL
+
 #ifndef PRODUCT
 void ReceiverTypeData::print_receiver_data_on(outputStream* st) {
   uint row;
--- a/src/share/vm/oops/methodData.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/share/vm/oops/methodData.hpp	Fri May 17 22:45:55 2013 +0200
@@ -635,9 +635,17 @@
 protected:
   enum {
 #ifdef GRAAL
-    // Graal is interested in knowing the percentage of type checks
-    // involving a type not explicitly in the profile
-    nonprofiled_receiver_count_off_set = counter_cell_count,
+    // Description of the different counters
+    // ReceiverTypeData for instanceof/checkcast/aastore:
+    //   C1/C2: count is incremented on type overflow and decremented for failed type checks
+    //   Graal: count decremented for failed type checks and nonprofiled_count is incremented on type overflow
+    //          TODO (chaeubl): in fact, Graal should also increment the count for failed type checks to mimic the C1/C2 behavior
+    // VirtualCallData for invokevirtual/invokeinterface:
+    //   C1/C2: count is incremented on type overflow
+    //   Graal: count is incremented on type overflow, nonprofiled_count is increment on method overflow
+
+    // Graal is interested in knowing the percentage of type checks involving a type not explicitly in the profile
+    nonprofiled_count_off_set = counter_cell_count,
     receiver0_offset,
 #else
     receiver0_offset = counter_cell_count,
@@ -717,6 +725,13 @@
     set_count(0);
     set_receiver(row, NULL);
     set_receiver_count(row, 0);
+#ifdef GRAAL
+    if (!this->is_VirtualCallData()) {
+      // if this is a ReceiverTypeData for Graal, the nonprofiled_count
+      // must also be reset (see "Description of the different counters" above)
+      set_nonprofiled_count(0);
+    }
+#endif
   }
 
   // Code generation support
@@ -728,7 +743,10 @@
   }
 #ifdef GRAAL
   static ByteSize nonprofiled_receiver_count_offset() {
-    return cell_offset(nonprofiled_receiver_count_off_set);
+    return cell_offset(nonprofiled_count_off_set);
+  }
+  void set_nonprofiled_count(uint count) {
+    set_uint_at(nonprofiled_count_off_set, count);
   }
 #endif
   static ByteSize receiver_type_data_size() {
@@ -759,7 +777,7 @@
   static int static_cell_count() {
     // At this point we could add more profile state, e.g., for arguments.
     // But for now it's the same size as the base record type.
-    return ReceiverTypeData::static_cell_count();
+    return ReceiverTypeData::static_cell_count() GRAAL_ONLY(+ (uint) MethodProfileWidth * receiver_type_row_cell_count);
   }
 
   virtual int cell_count() {
@@ -771,6 +789,53 @@
     return cell_offset(static_cell_count());
   }
 
+#ifdef GRAAL
+  static ByteSize method_offset(uint row) {
+    return cell_offset(method_cell_index(row));
+  }
+  static ByteSize method_count_offset(uint row) {
+    return cell_offset(method_count_cell_index(row));
+  }
+  static int method_cell_index(uint row) {
+    return receiver0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count;
+  }
+  static int method_count_cell_index(uint row) {
+    return count0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count;
+  }
+  static uint method_row_limit() {
+    return MethodProfileWidth;
+  }
+
+  Method* method(uint row) {
+    assert(row < method_row_limit(), "oob");
+
+    Method* method = (Method*)intptr_at(method_cell_index(row));
+    assert(method == NULL || method->is_method(), "must be");
+    return method;
+  }
+
+  void set_method(uint row, Method* m) {
+    assert((uint)row < method_row_limit(), "oob");
+    set_intptr_at(method_cell_index(row), (uintptr_t)m);
+  }
+
+  void set_method_count(uint row, uint count) {
+    assert(row < method_row_limit(), "oob");
+    set_uint_at(method_count_cell_index(row), count);
+  }
+
+  void clear_method_row(uint row) {
+    assert(row < method_row_limit(), "oob");
+    // Clear total count - indicator of polymorphic call site (see comment for clear_row() in ReceiverTypeData).
+    set_nonprofiled_count(0);
+    set_method(row, NULL);
+    set_method_count(row, 0);
+  }
+
+  // GC support
+  virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
+#endif
+
 #ifndef PRODUCT
   void print_data_on(outputStream* st);
 #endif
--- a/src/share/vm/runtime/globals.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/share/vm/runtime/globals.hpp	Fri May 17 22:45:55 2013 +0200
@@ -2949,6 +2949,9 @@
   product_pd(intx, TypeProfileWidth,                                        \
           "number of receiver types to record in call/cast profile")        \
                                                                             \
+  product_pd(intx, MethodProfileWidth,                                      \
+          "number of methods to record in call profile")                    \
+                                                                            \
   develop(intx, BciProfileWidth,      2,                                    \
           "number of return bci's to record in ret profile")                \
                                                                             \
--- a/src/share/vm/utilities/macros.hpp	Fri May 17 22:45:24 2013 +0200
+++ b/src/share/vm/utilities/macros.hpp	Fri May 17 22:45:55 2013 +0200
@@ -182,6 +182,7 @@
 #ifdef GRAAL
 #define GRAAL_ONLY(code) code
 #define NOT_GRAAL(code)
+#define IS_GRAAL_DEFINED true
 #if !defined(COMPILER1) && !defined(COMPILER2)
 // Graal is the only compiler in the system and so will be used for compilation
 // requests issued by the compile broker.
@@ -197,6 +198,7 @@
 #else // !GRAAL
 #define GRAAL_ONLY(code)
 #define NOT_GRAAL(code) code
+#define IS_GRAAL_DEFINED false
 #define GRAALVM_ONLY(code)
 #define NOT_GRAALVM(code) code
 #endif // GRAAL