# HG changeset patch # User Christian Haeubl # Date 1368797902 -7200 # Node ID c76b43ed50891f28b8ff1a735b1445ad4be9a94f # Parent 580faa2ee288a2bb57519f99d6b383c794b0c857 Added infrastructure for recording invoked methods in the profiling information. diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java --- /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 15:38:22 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, 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; + } +} diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractProfiledItem.java --- /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 15:38:22 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 implements Comparable, 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(); +} diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java Fri May 17 15:38:22 2013 +0200 @@ -48,6 +48,11 @@ } @Override + public JavaMethodProfile getMethodProfile(int bci) { + return null; + } + + @Override public double getBranchTakenProbability(int bci) { return -1; } diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java --- /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 15:38:22 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 { + + 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 { + + 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 + "}"; + } + } +} diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Fri May 17 15:38:22 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 { 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, 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 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 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 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 { + + 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 + "}"; + } } } diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Fri May 17 15:38:22 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 %s", typeProfile.getNotRecordedProbability(), sep)); - } else { - buf.append(String.format(" %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 kind, String sep) { + if (profile != null) { + AbstractProfiledItem[] pitems = profile.getItems(); + if (pitems != null) { + buf.append(String.format("%s@%d:", kind, 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 %s", profile.getNotRecordedProbability(), kind, sep)); + } else { + buf.append(String.format(" %s", kind, sep)); + } + } + } + } + /** * Converts a Java source-language class name into the internal form. * diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java Fri May 17 15:38:22 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); diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Fri May 17 15:38:22 2013 +0200 @@ -105,8 +105,9 @@ } @Test - public void testTypeProfileInvokeVirtual() { + public void testProfileInvokeVirtual() throws NoSuchMethodException { testTypeProfile("invokeVirtualSnippet", 1); + testMethodProfile("invokeVirtualSnippet", 1, "hashCode"); } public static int invokeVirtualSnippet(Object obj) { @@ -114,8 +115,9 @@ } @Test - public void testTypeProfileInvokeInterface() { + public void testTypeProfileInvokeInterface() throws NoSuchMethodException { testTypeProfile("invokeInterfaceSnippet", 1); + testMethodProfile("invokeInterfaceSnippet", 1, "length"); } public static int invokeInterfaceSnippet(CharSequence a) { @@ -140,18 +142,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,11 +162,36 @@ 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); } + private void testMethodProfile(String testSnippet, int bci, String expectedProfiledMethod) throws NoSuchMethodException { + ResolvedJavaMethod stringMethod = runtime.lookupJavaMethod(String.class.getMethod(expectedProfiledMethod)); + ResolvedJavaMethod stringBuilderMethod = runtime.lookupJavaMethod(StringBuilder.class.getMethod(expectedProfiledMethod)); + + ProfilingInfo info = profile(testSnippet, "ABC"); + JavaMethodProfile methodProfile = info.getMethodProfile(bci); + Assert.assertEquals(0.0, methodProfile.getNotRecordedProbability(), DELTA); + Assert.assertEquals(1, methodProfile.getMethods().length); + Assert.assertEquals(stringMethod, methodProfile.getMethods()[0].getMethod()); + Assert.assertEquals(1.0, methodProfile.getMethods()[0].getProbability(), DELTA); + + continueProfiling(testSnippet, new StringBuilder()); + methodProfile = info.getMethodProfile(bci); + Assert.assertEquals(0.0, methodProfile.getNotRecordedProbability(), DELTA); + Assert.assertEquals(2, methodProfile.getMethods().length); + Assert.assertEquals(stringMethod, methodProfile.getMethods()[0].getMethod()); + Assert.assertEquals(stringBuilderMethod, methodProfile.getMethods()[1].getMethod()); + Assert.assertEquals(0.5, methodProfile.getMethods()[0].getProbability(), DELTA); + Assert.assertEquals(0.5, methodProfile.getMethods()[1].getProbability(), DELTA); + + resetProfile(testSnippet); + methodProfile = info.getMethodProfile(bci); + Assert.assertNull(methodProfile); + } + @Test public void testExceptionSeen() { // NullPointerException diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri May 17 15:38:22 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; diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Fri May 17 15:38:22 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 { diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java Fri May 17 15:38:22 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); diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Fri May 17 15:38:22 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); diff -r 580faa2ee288 -r c76b43ed5089 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Fri May 17 09:28:41 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Fri May 17 15:38:22 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; diff -r 580faa2ee288 -r c76b43ed5089 src/cpu/sparc/vm/c2_globals_sparc.hpp --- a/src/cpu/sparc/vm/c2_globals_sparc.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp Fri May 17 15:38:22 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 diff -r 580faa2ee288 -r c76b43ed5089 src/cpu/x86/vm/c1_globals_x86.hpp --- a/src/cpu/x86/vm/c1_globals_x86.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/cpu/x86/vm/c1_globals_x86.hpp Fri May 17 15:38:22 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 ); diff -r 580faa2ee288 -r c76b43ed5089 src/cpu/x86/vm/c2_globals_x86.hpp --- a/src/cpu/x86/vm/c2_globals_x86.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/cpu/x86/vm/c2_globals_x86.hpp Fri May 17 15:38:22 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 diff -r 580faa2ee288 -r c76b43ed5089 src/cpu/x86/vm/graalGlobals_x86.hpp --- a/src/cpu/x86/vm/graalGlobals_x86.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/cpu/x86/vm/graalGlobals_x86.hpp Fri May 17 15:38:22 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 diff -r 580faa2ee288 -r c76b43ed5089 src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri May 17 09:28:41 2013 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri May 17 15:38:22 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); diff -r 580faa2ee288 -r c76b43ed5089 src/cpu/x86/vm/interp_masm_x86_64.hpp --- a/src/cpu/x86/vm/interp_masm_x86_64.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp Fri May 17 15:38:22 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); diff -r 580faa2ee288 -r c76b43ed5089 src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Fri May 17 09:28:41 2013 +0200 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Fri May 17 15:38:22 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(); diff -r 580faa2ee288 -r c76b43ed5089 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Fri May 17 09:28:41 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Fri May 17 15:38:22 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)); diff -r 580faa2ee288 -r c76b43ed5089 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/share/vm/oops/methodData.hpp Fri May 17 15:38:22 2013 +0200 @@ -759,13 +759,28 @@ 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() { return 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; + } +#endif + // Direct accessors static ByteSize virtual_call_data_size() { return cell_offset(static_cell_count()); diff -r 580faa2ee288 -r c76b43ed5089 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/share/vm/runtime/globals.hpp Fri May 17 15:38:22 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") \ \ diff -r 580faa2ee288 -r c76b43ed5089 src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Fri May 17 09:28:41 2013 +0200 +++ b/src/share/vm/utilities/macros.hpp Fri May 17 15:38:22 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