# HG changeset patch # User Christian Humer # Date 1369158660 -7200 # Node ID 5402504894fe7487fd082993aae25f4d9f7f8267 # Parent ba02d19dd3cc325809c45efa498f1f830751366a# Parent 05b719a4ae09457ab67ccbc172fdbe610c2aa862 Merge. diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Tue May 21 19:51:00 2013 +0200 @@ -161,8 +161,25 @@ /** * Determine the maximum vector length supported for vector operations on values of a given * {@link Kind}. + * + * @param kind the kind of the individual vector elements + * @return the maximum supported vector size */ - public int getMaxVectorLength(@SuppressWarnings("unused") Kind kind) { + public int getMaxVectorLength(Kind kind) { + return 1; + } + + /** + * Get a natively supported vector length for breaking down some vector operation on a constant + * length vector. + * + * @param kind the kind of the individual vector elements + * @param maxLength the maximum length that should be returned + * @param arithmetic whether the vector length needs to support arithmetic operations or just + * load and store + * @return a supported vector size, but at most {@code maxLength} + */ + public int getSupportedVectorLength(Kind kind, int maxLength, boolean arithmetic) { return 1; } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java Tue May 21 19:51:00 2013 +0200 @@ -27,9 +27,8 @@ import com.oracle.graal.api.meta.*; /** - * A calling convention describes the locations in which the arguments for a call are placed, the - * location in which the return value is placed if the call is not void and any - * {@linkplain #getTemporaries() extra} locations used (and killed) by the call. + * A calling convention describes the locations in which the arguments for a call are placed and the + * location in which the return value is placed if the call is not void. */ public class CallingConvention { @@ -78,11 +77,6 @@ private final AllocatableValue[] argumentLocations; /** - * The locations used (and killed) by the call in addition to the arguments. - */ - private final AllocatableValue[] temporaryLocations; - - /** * Creates a description of the registers and stack locations used by a call. * * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of @@ -92,28 +86,11 @@ * @param argumentLocations the ordered locations in which the arguments are placed */ public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) { - this(AllocatableValue.NONE, stackSize, returnLocation, argumentLocations); - } - - /** - * Creates a description of the registers and stack locations used by a call. - * - * @param temporaryLocations the locations used (and killed) by the call in addition to - * {@code arguments} - * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of - * the call - * @param returnLocation the location for the return value or {@link Value#ILLEGAL} if a void - * call - * @param argumentLocations the ordered locations in which the arguments are placed - */ - public CallingConvention(AllocatableValue[] temporaryLocations, int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) { assert argumentLocations != null; - assert temporaryLocations != null; assert returnLocation != null; this.argumentLocations = argumentLocations; this.stackSize = stackSize; this.returnLocation = returnLocation; - this.temporaryLocations = temporaryLocations; assert verify(); } @@ -155,17 +132,6 @@ return argumentLocations.clone(); } - /** - * Gets the locations used (and killed) by the call apart from the - * {@linkplain #getArgument(int) arguments}. - */ - public AllocatableValue[] getTemporaries() { - if (temporaryLocations.length == 0) { - return temporaryLocations; - } - return temporaryLocations.clone(); - } - @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -178,14 +144,6 @@ if (!returnLocation.equals(Value.ILLEGAL)) { sb.append(" -> ").append(returnLocation); } - if (temporaryLocations.length != 0) { - sb.append("; temps="); - sep = ""; - for (Value op : temporaryLocations) { - sb.append(sep).append(op); - sep = ", "; - } - } sb.append("]"); return sb.toString(); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.api.code; import com.oracle.graal.api.code.CompilationResult.DataPatch; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; /** @@ -68,9 +67,9 @@ int getMinimumOutgoingSize(); /** - * Gets the signature and linkage information for a runtime call. + * Gets the linkage for a foreign call. */ - RuntimeCallTarget lookupRuntimeCall(Descriptor descriptor); + ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor); /** * Encodes a deoptimization action and a deoptimization reason in an integer value. diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallLinkage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallLinkage.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.code; + +import com.oracle.graal.api.meta.*; + +/** + * The runtime specific details of a {@linkplain ForeignCallDescriptor foreign} call. + */ +public interface ForeignCallLinkage extends InvokeTarget { + + /** + * Gets the details of where parameters are passed and value(s) are returned. + */ + CallingConvention getCallingConvention(); + + /** + * Returns the maximum absolute offset of PC relative call to this stub from any position in the + * code cache or -1 when not applicable. Intended for determining the required size of + * address/offset fields. + */ + long getMaxCallTargetOffset(); + + ForeignCallDescriptor getDescriptor(); + + /** + * Gets the values used/killed by this foreign call. + */ + Value[] getTemporaries(); + + /** + * Determines if the foreign call target destroys all registers. + * + * @return {@code true} if the register allocator must save all live registers around a call to + * this target + */ + boolean destroysRegisters(); +} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.api.code; - -import java.util.*; - -import com.oracle.graal.api.meta.*; - -/** - * The name, signature and calling convention of a call from compiled code to the runtime. The - * target of such a call may be a leaf stub or a call into the runtime code proper. - */ -public interface RuntimeCallTarget extends InvokeTarget { - - /** - * The name and signature of a runtime call. - */ - public static class Descriptor { - - private final String name; - private final boolean hasSideEffect; - private final Class resultType; - private final Class[] argumentTypes; - - public Descriptor(String name, boolean hasSideEffect, Class resultType, Class... argumentTypes) { - this.name = name; - this.hasSideEffect = hasSideEffect; - this.resultType = resultType; - this.argumentTypes = argumentTypes; - } - - /** - * Gets the name of this runtime call. - */ - public String getName() { - return name; - } - - /** - * Determines if this call changes state visible to other threads. Such calls denote - * boundaries across which deoptimization points cannot be moved. - */ - public boolean hasSideEffect() { - return hasSideEffect; - } - - /** - * Gets the return kind of this runtime call. - */ - public Class getResultType() { - return resultType; - } - - /** - * Gets the argument kinds of this runtime call. - */ - public Class[] getArgumentTypes() { - return argumentTypes.clone(); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Descriptor) { - Descriptor nas = (Descriptor) obj; - return nas.name.equals(name) && nas.resultType.equals(resultType) && Arrays.equals(nas.argumentTypes, argumentTypes); - } - return false; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(name).append('('); - String sep = ""; - for (Class arg : argumentTypes) { - sb.append(sep).append(arg.getSimpleName()); - sep = ","; - } - return sb.append(')').append(resultType.getSimpleName()).toString(); - } - } - - CallingConvention getCallingConvention(); - - /** - * Returns the maximum absolute offset of PC relative call to this stub from any position in the - * code cache or -1 when not applicable. Intended for determining the required size of - * address/offset fields. - */ - long getMaxCallTargetOffset(); - - Descriptor getDescriptor(); - - /** - * Determines if the target routine destroys all registers. - * - * @return {@code true} if the register allocator must save all live registers around a call to - * this target - */ - boolean destroysRegisters(); -} diff -r ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java Tue May 21 19:51:00 2013 +0200 @@ -48,6 +48,11 @@ } @Override + public JavaMethodProfile getMethodProfile(int bci) { + return null; + } + + @Override public double getBranchTakenProbability(int bci) { return -1; } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ForeignCallDescriptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ForeignCallDescriptor.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009, 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.util.*; + +/** + * The name and signature of a foreign call. A foreign call differs from a normal compiled Java call + * in at least one of these aspects: + *
    + *
  • The call is to C/C++/assembler code.
  • + *
  • The call uses different conventions for passing parameters or returning values.
  • + *
  • The callee has different register saving semantics. For example, the callee may save all + * registers (apart from some specified temporaries) in which case the register allocator doesn't + * not need to spill all live registers around the call site.
  • + *
  • The call does not occur at an INVOKE* bytecode. Such a call could be transformed into a + * standard Java call if the foreign routine is a normal Java method and the runtime supports + * linking Java calls at arbitrary bytecodes.
  • + *
+ */ +public class ForeignCallDescriptor { + + private final String name; + private final Class resultType; + private final Class[] argumentTypes; + + public ForeignCallDescriptor(String name, Class resultType, Class... argumentTypes) { + this.name = name; + this.resultType = resultType; + this.argumentTypes = argumentTypes; + } + + /** + * Gets the name of this foreign call. + */ + public String getName() { + return name; + } + + /** + * Gets the return type of this foreign call. + */ + public Class getResultType() { + return resultType; + } + + /** + * Gets the argument types of this foreign call. + */ + public Class[] getArgumentTypes() { + return argumentTypes.clone(); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ForeignCallDescriptor) { + ForeignCallDescriptor other = (ForeignCallDescriptor) obj; + return other.name.equals(name) && other.resultType.equals(resultType) && Arrays.equals(other.argumentTypes, argumentTypes); + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(name).append('('); + String sep = ""; + for (Class arg : argumentTypes) { + sb.append(sep).append(arg.getSimpleName()); + sep = ","; + } + return sb.append(')').append(resultType.getSimpleName()).toString(); + } +} diff -r ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Tue May 21 19:51:00 2013 +0200 @@ -94,4 +94,10 @@ * value cannot be read. */ Constant readUnsafeConstant(Kind kind, Object base, long displacement); + + /** + * Determines if a given foreign call has a side-effect. Deoptimization cannot return execution + * to a point before a foreign call that has a side effect. + */ + boolean hasSideEffect(ForeignCallDescriptor descriptor); } diff -r ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Tue May 21 19:51:00 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 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 %s", profile.getNotRecordedProbability(), type, sep)); + } else { + buf.append(String.format(" %s", type, sep)); + } + } + } + } + /** * Converts a Java source-language class name into the internal form. * diff -r ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Tue May 21 19:51:00 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; /** * This class implements commonly used X86 code patterns. @@ -255,7 +256,7 @@ private AMD64Address trigPrologue(Register value) { assert value.getRegisterCategory() == AMD64.XMM; AMD64Address tmp = new AMD64Address(AMD64.rsp); - subq(AMD64.rsp, 8); + subq(AMD64.rsp, target.arch.getSizeInBytes(Kind.Double)); movsd(tmp, value); fld_d(tmp); return tmp; @@ -265,7 +266,7 @@ assert dest.getRegisterCategory() == AMD64.XMM; fstp_d(tmp); movsd(dest, tmp); - addq(AMD64.rsp, 8); + addq(AMD64.rsp, target.arch.getSizeInBytes(Kind.Double)); } /** diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue May 21 19:51:00 2013 +0200 @@ -135,7 +135,7 @@ @Override public Variable emitMove(Value input) { - Variable result = newVariable(input.getKind()); + Variable result = newVariable(input.getPlatformKind()); emitMove(result, input); return result; } @@ -784,13 +784,12 @@ } @Override - protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { - - long maxOffset = callTarget.getMaxCallTargetOffset(); + protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + long maxOffset = linkage.getMaxCallTargetOffset(); if (maxOffset != (int) maxOffset) { - append(new AMD64Call.DirectFarRuntimeCallOp(this, callTarget, result, arguments, temps, info)); + append(new AMD64Call.DirectFarForeignCallOp(this, linkage, result, arguments, temps, info)); } else { - append(new AMD64Call.DirectNearRuntimeCallOp(callTarget, result, arguments, temps, info)); + append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Tue May 21 19:51:00 2013 +0200 @@ -29,7 +29,6 @@ import static com.oracle.graal.lir.ptx.PTXCompare.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.NumUtil; import com.oracle.graal.compiler.gen.LIRGenerator; @@ -70,8 +69,8 @@ */ public class PTXLIRGenerator extends LIRGenerator { - public static final Descriptor ARITHMETIC_FREM = new Descriptor("arithmeticFrem", false, float.class, float.class, float.class); - public static final Descriptor ARITHMETIC_DREM = new Descriptor("arithmeticDrem", false, double.class, double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class); + public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class); public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory { @@ -643,7 +642,7 @@ } @Override - protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + protected void emitForeignCall(ForeignCallLinkage callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { throw new InternalError("NYI"); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue May 21 19:51:00 2013 +0200 @@ -112,7 +112,7 @@ } @Override - protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { // SPARC: Auto-generated method stub } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue May 21 19:51:00 2013 +0200 @@ -426,18 +426,29 @@ } long start = System.currentTimeMillis(); PhasePlan phasePlan = new PhasePlan(); - StructuredGraph graphCopy = graph.copy(); + final StructuredGraph graphCopy = graph.copy(); GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); phasePlan.addPhase(PhasePosition.LOW_LEVEL, new WriteBarrierAdditionPhase()); editPhasePlan(method, graph, phasePlan); CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); - CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, method, runtime, replacements, backend, runtime().getTarget(), null, phasePlan, OptimisticOptimizations.ALL, + final CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, method, runtime, replacements, backend, runtime().getTarget(), null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog()); if (printCompilation) { TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize())); } - return addMethod(method, compResult, graphCopy); + return Debug.scope("CodeInstall", new Object[]{runtime, method}, new Callable() { + + @Override + public InstalledCode call() throws Exception { + InstalledCode code = addMethod(method, compResult, graphCopy); + if (Debug.isDumpEnabled()) { + Debug.dump(new Object[]{compResult, code}, "After code installation"); + } + + return code; + } + }); } }); @@ -448,18 +459,7 @@ } protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compResult, final StructuredGraph graph) { - return Debug.scope("CodeInstall", new Object[]{runtime, method}, new Callable() { - - @Override - public InstalledCode call() throws Exception { - InstalledCode installedCode = runtime.addMethod(method, compResult, graph); - if (Debug.isDumpEnabled()) { - Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); - } - - return installedCode; - } - }); + return runtime.addMethod(method, compResult, graph); } /** diff -r ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Tue May 21 19:51:00 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); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Tue May 21 19:51:00 2013 +0200 @@ -608,9 +608,9 @@ Value result = invokeCc.getReturn(); if (callTarget instanceof DirectCallTargetNode) { - emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState); + emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); } else if (callTarget instanceof IndirectCallTargetNode) { - emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState); + emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); } else { throw GraalInternalError.shouldNotReachHere(); } @@ -624,7 +624,7 @@ protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); - protected abstract void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info); + protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info); protected static AllocatableValue toStackKind(AllocatableValue value) { if (value.getKind().getStackKind() != value.getKind()) { @@ -659,43 +659,29 @@ } @Override - public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) { + public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) { LIRFrameState state = info != null ? state(info) : null; // move the arguments into the correct location - frameMap.callsMethod(callCc); - assert callCc.getArgumentCount() == args.length : "argument count mismatch"; + CallingConvention linkageCc = linkage.getCallingConvention(); + frameMap.callsMethod(linkageCc); + assert linkageCc.getArgumentCount() == args.length : "argument count mismatch"; Value[] argLocations = new Value[args.length]; for (int i = 0; i < args.length; i++) { Value arg = args[i]; - AllocatableValue loc = callCc.getArgument(i); + AllocatableValue loc = linkageCc.getArgument(i); emitMove(loc, arg); argLocations[i] = loc; } - emitCall(callTarget, callCc.getReturn(), argLocations, callCc.getTemporaries(), state); + emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state); - if (isLegal(callCc.getReturn())) { - return emitMove(callCc.getReturn()); + if (isLegal(linkageCc.getReturn())) { + return emitMove(linkageCc.getReturn()); } else { return null; } } - @Override - public void visitRuntimeCall(RuntimeCallNode x) { - RuntimeCallTarget call = runtime.lookupRuntimeCall(x.getDescriptor()); - CallingConvention callCc = call.getCallingConvention(); - frameMap.callsMethod(callCc); - Value resultOperand = callCc.getReturn(); - Value[] args = visitInvokeArguments(callCc, x.arguments()); - - emitCall(call, resultOperand, args, callCc.getTemporaries(), state(x)); - - if (isLegal(resultOperand)) { - setResult(x, emitMove(resultOperand)); - } - } - /** * This method tries to create a switch implementation that is optimal for the given switch. It * will either generate a sequential if/then/else cascade, a set of range tests or a table diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Tue May 21 19:51:00 2013 +0200 @@ -52,6 +52,6 @@ HotSpotGraalRuntime runtime = graalRuntime(); Register thread = runtime.getRuntime().threadRegister(); masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason)); - AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP), null, false, info); + AMD64Call.directCall(tasm, masm, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP), null, false, info); } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue May 21 19:51:00 2013 +0200 @@ -250,9 +250,9 @@ HotSpotFrameContext frameContext = (HotSpotFrameContext) tasm.frameContext; if (frameContext != null && !frameContext.isStub) { tasm.recordMark(Marks.MARK_EXCEPTION_HANDLER_ENTRY); - AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(EXCEPTION_HANDLER), null, false, null); + AMD64Call.directCall(tasm, asm, runtime().lookupForeignCall(EXCEPTION_HANDLER), null, false, null); tasm.recordMark(Marks.MARK_DEOPT_HANDLER_ENTRY); - AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(DEOPT_HANDLER), null, false, null); + AMD64Call.directCall(tasm, asm, runtime().lookupForeignCall(DEOPT_HANDLER), null, false, null); } else { // No need to emit the stubs for entries back into the method since // it has no calls that can cause such "return" entries @@ -261,7 +261,7 @@ if (unverifiedStub != null) { asm.bind(unverifiedStub); - AMD64Call.directJmp(tasm, asm, runtime().lookupRuntimeCall(IC_MISS_HANDLER)); + AMD64Call.directJmp(tasm, asm, runtime().lookupForeignCall(IC_MISS_HANDLER)); } } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Tue May 21 19:51:00 2013 +0200 @@ -54,6 +54,6 @@ HotSpotGraalRuntime runtime = graalRuntime(); Register thread = runtime.getRuntime().threadRegister(); masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason)); - AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP)); + AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP)); } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue May 21 19:51:00 2013 +0200 @@ -186,9 +186,9 @@ private LIRFrameState currentRuntimeCallInfo; @Override - protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { currentRuntimeCallInfo = info; - super.emitCall(callTarget, result, arguments, temps, info); + super.emitForeignCall(linkage, result, arguments, temps, info); } protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations) { @@ -209,39 +209,50 @@ } @Override - public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) { + public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) { Stub stub = getStub(); - boolean destroysRegisters = ((HotSpotRuntimeCallTarget) callTarget).destroysRegisters(); - assert !destroysRegisters || stub != null : "foreign call that destroys registers can only be made from compiled stub, not from " + graph; + HotSpotForeignCallLinkage hsLinkage = (HotSpotForeignCallLinkage) linkage; + boolean destroysRegisters = hsLinkage.destroysRegisters(); AMD64SaveRegistersOp save = null; StackSlot[] savedRegisterLocations = null; if (destroysRegisters) { - if (stub.preservesRegisters()) { - Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters(); - savedRegisterLocations = new StackSlot[savedRegisters.length]; - for (int i = 0; i < savedRegisters.length; i++) { - PlatformKind kind = target.arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory()); - assert kind != Kind.Illegal; - StackSlot spillSlot = frameMap.allocateSpillSlot(kind); - savedRegisterLocations[i] = spillSlot; + if (stub != null) { + if (stub.preservesRegisters()) { + Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters(); + savedRegisterLocations = new StackSlot[savedRegisters.length]; + for (int i = 0; i < savedRegisters.length; i++) { + PlatformKind kind = target.arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory()); + assert kind != Kind.Illegal; + StackSlot spillSlot = frameMap.allocateSpillSlot(kind); + savedRegisterLocations[i] = spillSlot; + } + save = emitSaveRegisters(savedRegisters, savedRegisterLocations); } - save = emitSaveRegisters(savedRegisters, savedRegisterLocations); } - append(new AMD64HotSpotCRuntimeCallPrologueOp()); } - Variable result = super.emitCall(callTarget, callCc, info, args); + Variable result; + + if (!hsLinkage.isLeaf()) { + assert info != null; + append(new AMD64HotSpotCRuntimeCallPrologueOp()); + result = super.emitForeignCall(linkage, info, args); + append(new AMD64HotSpotCRuntimeCallEpilogueOp()); + } else { + result = super.emitForeignCall(linkage, null, args); + } if (destroysRegisters) { - append(new AMD64HotSpotCRuntimeCallEpilogueOp()); - if (stub.preservesRegisters()) { - assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); - calleeSaveInfo.put(currentRuntimeCallInfo, save); + if (stub != null) { + if (stub.preservesRegisters()) { + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, save); - emitRestoreRegisters(save); - } else { - assert zapRegisters(); + emitRestoreRegisters(save); + } else { + assert zapRegisters(); + } } } @@ -331,10 +342,10 @@ @Override public void emitUnwind(Value exception) { - RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); - CallingConvention stubCc = stub.getCallingConvention(); - assert stubCc.getArgumentCount() == 2; - RegisterValue exceptionParameter = (RegisterValue) stubCc.getArgument(0); + ForeignCallLinkage linkage = getRuntime().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + CallingConvention linkageCc = linkage.getCallingConvention(); + assert linkageCc.getArgumentCount() == 2; + RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0); emitMove(exceptionParameter, exception); append(new AMD64HotSpotUnwindOp(exceptionParameter)); } @@ -357,11 +368,11 @@ @Override public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { Variable handler = load(operand(handlerInCallerPc)); - RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(EXCEPTION_HANDLER_IN_CALLER); - CallingConvention stubCc = stub.getCallingConvention(); - assert stubCc.getArgumentCount() == 2; - RegisterValue exceptionFixed = (RegisterValue) stubCc.getArgument(0); - RegisterValue exceptionPcFixed = (RegisterValue) stubCc.getArgument(1); + ForeignCallLinkage linkage = getRuntime().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention linkageCc = linkage.getCallingConvention(); + assert linkageCc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1); emitMove(exceptionFixed, operand(exception)); emitMove(exceptionPcFixed, operand(exceptionPc)); AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed); diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Tue May 21 19:51:00 2013 +0200 @@ -24,13 +24,13 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.CallingConvention.Type.*; +import static com.oracle.graal.api.meta.Value.*; import static com.oracle.graal.hotspot.HotSpotBackend.*; -import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.*; -import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*; -import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.DecryptBlockStubCall.*; -import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*; -import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*; -import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*; +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*; +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*; +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*; +import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.*; +import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -59,15 +59,15 @@ // in templateInterpreter_x86_64.cpp around line 1923 RegisterValue exception = rax.asValue(Kind.Object); RegisterValue exceptionPc = rdx.asValue(word); - CallingConvention exceptionCc = new CallingConvention(0, Value.ILLEGAL, exception, exceptionPc); - register(new HotSpotRuntimeCallTarget(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, exceptionCc, graalRuntime.getCompilerToVM())); - register(new HotSpotRuntimeCallTarget(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, exceptionCc, graalRuntime.getCompilerToVM())); + CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc); + register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, exceptionCc)); + register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc)); - // The crypto stubs do callee saving - registerLeafCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS); - registerLeafCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS); - registerLeafCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS); - registerLeafCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS); + // The x86 crypto stubs do callee saving + registerForeignCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF); + registerForeignCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF); + registerForeignCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF); + registerForeignCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF); convertSnippets = new AMD64ConvertSnippets.Templates(this, replacements, graalRuntime.getTarget()); super.registerReplacements(replacements); diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Tue May 21 19:51:00 2013 +0200 @@ -51,8 +51,8 @@ public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { leaveFrameAndRestoreRbp(tasm, masm); - RuntimeCallTarget stub = tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION_TO_CALLER); - CallingConvention cc = stub.getCallingConvention(); + ForeignCallLinkage linkage = tasm.runtime.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER); + CallingConvention cc = linkage.getCallingConvention(); assert cc.getArgumentCount() == 2; assert exception.equals(cc.getArgument(0)); @@ -60,6 +60,6 @@ Register returnAddress = asRegister(cc.getArgument(1)); masm.movq(returnAddress, new AMD64Address(rsp, 0)); - AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER)); + AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER)); } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2013, 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.hotspot.test; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import java.io.*; +import java.lang.reflect.*; +import java.security.*; + +import javax.crypto.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; + +/** + * Tests the intrinsification of certain crypto methods. + */ +public class HotSpotCryptoSubstitutionTest extends GraalCompilerTest { + + @Override + protected InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, StructuredGraph graph) { + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; + HotSpotNmethod installedCode = new HotSpotNmethod(hsMethod, graph, true); + HotSpotCompiledNmethod compiledNmethod = new HotSpotCompiledNmethod(hsMethod, StructuredGraph.INVOCATION_ENTRY_BCI, compResult); + CodeInstallResult result = graalRuntime().getCompilerToVM().installCode(compiledNmethod, installedCode, null); + Assert.assertEquals("Error installing method " + method + ": " + result, result, CodeInstallResult.OK); + + // HotSpotRuntime hsRuntime = (HotSpotRuntime) runtime; + // TTY.println(hsMethod.toString()); + // TTY.println(hsRuntime.disassemble(installedCode)); + return installedCode; + } + + @Test + public void testAESEncryptSubstitution() throws Exception { + byte[] seed = {0x4, 0x7, 0x1, 0x1}; + SecureRandom random = new SecureRandom(seed); + KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES"); + aesKeyGen.init(128, random); + SecretKey aesKey = aesKeyGen.generateKey(); + byte[] input = readClassfile16(getClass()); + + ByteArrayOutputStream expected = new ByteArrayOutputStream(); + expected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); + expected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + + if (compiledAndInstall("com.sun.crypto.provider.AESCrypt", "encryptBlock", "decryptBlock")) { + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray()); + } + + if (compiledAndInstall("com.sun.crypto.provider.CipherBlockChaining", "encrypt", "decrypt")) { + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray()); + } + } + + /** + * Compiles and installs the substitution for some specified methods. Once installed, the next + * execution of the methods will use the newly installed code. + * + * @param className the name of the class for which substitutions are available + * @param methodNames the names of the substituted methods + * @return true if at least one substitution was compiled and installed + */ + private boolean compiledAndInstall(String className, String... methodNames) { + boolean atLeastOneCompiled = false; + for (String methodName : methodNames) { + Method method = lookup(className, methodName); + if (method != null) { + ResolvedJavaMethod installedCodeOwner = runtime.lookupJavaMethod(method); + StructuredGraph graph = replacements.getMethodSubstitution(installedCodeOwner); + if (graph != null) { + Assert.assertNotNull(getCode(installedCodeOwner, graph, true)); + atLeastOneCompiled = true; + } else { + Assert.assertFalse(graalRuntime().getConfig().useAESIntrinsics); + } + } + } + return atLeastOneCompiled; + } + + private static Method lookup(String className, String methodName) { + Class c; + try { + c = Class.forName(className); + for (Method m : c.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + return m; + } + } + // If the expected security provider exists, the specific method should also exist + throw new NoSuchMethodError(className + "." + methodName); + } catch (ClassNotFoundException e) { + // It's ok to not find the class - a different security provider + // may have been installed + return null; + } + } + + AlgorithmParameters algorithmParameters; + + private byte[] encrypt(byte[] indata, SecretKey key, String algorithm) throws Exception { + + byte[] result = indata; + + Cipher c = Cipher.getInstance(algorithm); + c.init(Cipher.ENCRYPT_MODE, key); + algorithmParameters = c.getParameters(); + + byte[] r1 = c.update(result); + byte[] r2 = c.doFinal(); + + result = new byte[r1.length + r2.length]; + System.arraycopy(r1, 0, result, 0, r1.length); + System.arraycopy(r2, 0, result, r1.length, r2.length); + + return result; + } + + private byte[] decrypt(byte[] indata, SecretKey key, String algorithm) throws Exception { + + byte[] result = indata; + + Cipher c = Cipher.getInstance(algorithm); + c.init(Cipher.DECRYPT_MODE, key, algorithmParameters); + + byte[] r1 = c.update(result); + byte[] r2 = c.doFinal(); + + result = new byte[r1.length + r2.length]; + System.arraycopy(r1, 0, result, 0, r1.length); + System.arraycopy(r2, 0, result, r1.length, r2.length); + return result; + } + + private static byte[] readClassfile16(Class c) throws IOException { + String classFilePath = "/" + c.getName().replace('.', '/') + ".class"; + InputStream stream = c.getResourceAsStream(classFilePath); + int bytesToRead = stream.available(); + bytesToRead -= bytesToRead % 16; + byte[] classFile = new byte[bytesToRead]; + new DataInputStream(stream).readFully(classFile); + return classFile; + } + + public byte[] runEncryptDecrypt(SecretKey key, String algorithm, byte[] input) throws Exception { + byte[] indata = input.clone(); + byte[] cipher = encrypt(indata, key, algorithm); + byte[] plain = decrypt(cipher, key, algorithm); + Assert.assertArrayEquals(indata, plain); + return plain; + } +} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Tue May 21 19:51:00 2013 +0200 @@ -22,8 +22,8 @@ */ package com.oracle.graal.hotspot; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; @@ -39,34 +39,34 @@ /** * Descriptor for SharedRuntime::deopt_blob()->uncommon_trap(). */ - public static final Descriptor UNCOMMON_TRAP = new Descriptor("deoptimize", true, void.class); + public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("deoptimize", void.class); /** * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the * {@linkplain Marks#MARK_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled method. */ - public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class, Object.class, Word.class); + public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class); /** * Descriptor for SharedRuntime::deopt_blob()->unpack(). */ - public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class); + public static final ForeignCallDescriptor DEOPT_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class); /** * Descriptor for SharedRuntime::get_ic_miss_stub(). */ - public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class); + public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class); /** * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated * from {@link UnwindNode}. */ - public static final Descriptor UNWIND_EXCEPTION_TO_CALLER = new Descriptor("unwindExceptionToCaller", true, void.class, Object.class, Word.class); + public static final ForeignCallDescriptor UNWIND_EXCEPTION_TO_CALLER = new ForeignCallDescriptor("unwindExceptionToCaller", void.class, Object.class, Word.class); /** * Descriptor for the arguments when unwinding to an exception handler in a caller. */ - public static final Descriptor EXCEPTION_HANDLER_IN_CALLER = new Descriptor("exceptionHandlerInCaller", false, void.class, Object.class, Word.class); + public static final ForeignCallDescriptor EXCEPTION_HANDLER_IN_CALLER = new ForeignCallDescriptor("exceptionHandlerInCaller", void.class, Object.class, Word.class); public HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) { super(runtime, target); diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java Tue May 21 19:51:00 2013 +0200 @@ -57,9 +57,9 @@ for (Infopoint infopoint : compResult.getInfopoints()) { assert infopoint instanceof Call : this + " cannot have non-call infopoint: " + infopoint; Call call = (Call) infopoint; - assert call.target instanceof HotSpotRuntimeCallTarget : this + " cannot have non runtime call: " + call.target; - HotSpotRuntimeCallTarget callTarget = (HotSpotRuntimeCallTarget) call.target; - assert !callTarget.isCompiledStub() : this + " cannot call compiled stub " + callTarget; + assert call.target instanceof HotSpotForeignCallLinkage : this + " cannot have non runtime call: " + call.target; + HotSpotForeignCallLinkage linkage = (HotSpotForeignCallLinkage) call.target; + assert !linkage.isCompiledStub() : this + " cannot call compiled stub " + linkage; } return true; } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot; + +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.word.*; + +/** + * The details required to link a HotSpot runtime or stub call. + */ +public class HotSpotForeignCallLinkage implements ForeignCallLinkage, InvokeTarget { + + /** + * Constants for specifying whether a foreign call destroys or preserves registers. A foreign + * call will always destroy {@link HotSpotForeignCallLinkage#getCallingConvention() its} + * {@linkplain ForeignCallLinkage#getTemporaries() temporary} registers. + */ + public enum RegisterEffect { + DESTROYS_REGISTERS, PRESERVES_REGISTERS + } + + /** + * Constants for specifying whether a call is a leaf or not. A leaf function does not lock, GC + * or throw exceptions. That is, the thread's execution state during the call is never inspected + * by another thread. + */ + public enum Transition { + LEAF, NOT_LEAF; + } + + /** + * Sentinel marker for a computed jump address. + */ + public static final long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL; + + /** + * The descriptor of the call. + */ + private final ForeignCallDescriptor descriptor; + + /** + * The entry point address of this call's target. + */ + private long address; + + /** + * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}. + */ + private Stub stub; + + /** + * The calling convention for this call. + */ + private final CallingConvention cc; + + private final RegisterEffect effect; + + private final Transition transition; + + /** + * The locations defined/killed by the call. + */ + private Value[] temporaries = AllocatableValue.NONE; + + /** + * Creates a {@link HotSpotForeignCallLinkage}. + * + * @param descriptor the descriptor of the call + * @param address the address of the code to call + * @param effect specifies if the call destroys or preserves all registers (apart from + * temporaries which are always destroyed) + * @param ccType calling convention type + * @param transition specifies if this is a {@linkplain #isLeaf() leaf} call + */ + public static HotSpotForeignCallLinkage create(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Type ccType, Transition transition) { + CallingConvention targetCc = createCallingConvention(descriptor, ccType); + return new HotSpotForeignCallLinkage(descriptor, address, effect, transition, targetCc); + } + + /** + * Gets a calling convention for a given descriptor and call type. + */ + public static CallingConvention createCallingConvention(ForeignCallDescriptor descriptor, Type ccType) { + HotSpotRuntime runtime = graalRuntime().getRuntime(); + Class[] argumentTypes = descriptor.getArgumentTypes(); + JavaType[] parameterTypes = new JavaType[argumentTypes.length]; + for (int i = 0; i < parameterTypes.length; ++i) { + parameterTypes[i] = asJavaType(argumentTypes[i], runtime); + } + TargetDescription target = graalRuntime().getTarget(); + JavaType returnType = asJavaType(descriptor.getResultType(), runtime); + return runtime.lookupRegisterConfig().getCallingConvention(ccType, returnType, parameterTypes, target, false); + } + + private static JavaType asJavaType(Class type, HotSpotRuntime runtime) { + if (WordBase.class.isAssignableFrom(type)) { + return runtime.lookupJavaType(wordKind().toJavaClass()); + } else { + return runtime.lookupJavaType(type); + } + } + + public HotSpotForeignCallLinkage(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, CallingConvention cc) { + this.address = address; + this.effect = effect; + this.transition = transition; + this.descriptor = descriptor; + this.cc = cc; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(stub == null ? descriptor.toString() : stub.toString()); + sb.append("@0x").append(Long.toHexString(address)).append(':').append(cc); + if (temporaries != null && temporaries.length != 0) { + sb.append("; temps="); + String sep = ""; + for (Value op : temporaries) { + sb.append(sep).append(op); + sep = ","; + } + } + return sb.toString(); + } + + public CallingConvention getCallingConvention() { + return cc; + } + + public Value[] getTemporaries() { + if (temporaries.length == 0) { + return temporaries; + } + return temporaries.clone(); + } + + public long getMaxCallTargetOffset() { + return graalRuntime().getCompilerToVM().getMaxCallTargetOffset(address); + } + + public ForeignCallDescriptor getDescriptor() { + return descriptor; + } + + public void setCompiledStub(Stub stub) { + assert address == 0L : "cannot set stub for linkage that already has an address: " + this; + this.stub = stub; + } + + /** + * Determines if this is a call to a compiled {@linkplain Stub stub}. + */ + public boolean isCompiledStub() { + return address == 0L || stub != null; + } + + public void finalizeAddress(Backend backend) { + if (address == 0) { + assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?"; + InstalledCode code = stub.getCode(backend); + + Set destroyedRegisters = stub.getDestroyedRegisters(); + if (!destroyedRegisters.isEmpty()) { + AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()]; + int i = 0; + for (Register reg : destroyedRegisters) { + temporaryLocations[i++] = reg.asValue(); + } + temporaries = temporaryLocations; + } + address = code.getStart(); + } + } + + public long getAddress() { + assert address != 0L : "address not yet finalized: " + this; + return address; + } + + @Override + public boolean destroysRegisters() { + return effect == DESTROYS_REGISTERS; + } + + /** + * Determines if this is call to a function that does not lock, GC or throw exceptions. That is, + * the thread's execution state during the call is never inspected by another thread. + */ + public boolean isLeaf() { + return transition == Transition.LEAF; + } +} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot; - -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CallingConvention.Type; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.hotspot.bridge.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.stubs.*; -import com.oracle.graal.word.*; - -/** - * The details required to link a HotSpot runtime or stub call. - */ -public class HotSpotRuntimeCallTarget implements RuntimeCallTarget, InvokeTarget { - - /** - * Constants for specifying whether a call destroys or preserves registers. A call will always - * destroy {@link HotSpotRuntimeCallTarget#getCallingConvention() its} - * {@linkplain CallingConvention#getTemporaries() temporary} registers. - */ - public enum RegisterEffect { - DESTROYS_REGISTERS, PRESERVES_REGISTERS - } - - /** - * Sentinel marker for a computed jump address. - */ - public static final long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL; - - /** - * The descriptor of the call. - */ - private final Descriptor descriptor; - - /** - * The entry point address of this call's target. - */ - private long address; - - /** - * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}. - */ - private Stub stub; - - /** - * The calling convention for this call. - */ - private CallingConvention cc; - - private final CompilerToVM vm; - - private final RegisterEffect effect; - - /** - * Creates a {@link HotSpotRuntimeCallTarget}. - * - * @param descriptor the descriptor of the call - * @param address the address of the code to call - * @param effect specifies if the call destroys or preserves all registers (apart from - * temporaries which are always destroyed) - * @param ccType calling convention type - * @param ccProvider calling convention provider - * @param vm the Java to HotSpot C/C++ runtime interface - */ - public static HotSpotRuntimeCallTarget create(Descriptor descriptor, long address, RegisterEffect effect, Type ccType, RegisterConfig ccProvider, HotSpotRuntime runtime, CompilerToVM vm) { - CallingConvention targetCc = createCallingConvention(descriptor, ccType, ccProvider, runtime); - return new HotSpotRuntimeCallTarget(descriptor, address, effect, targetCc, vm); - } - - /** - * Gets a calling convention for a given descriptor and call type. - */ - public static CallingConvention createCallingConvention(Descriptor descriptor, Type ccType, RegisterConfig ccProvider, HotSpotRuntime runtime) { - Class[] argumentTypes = descriptor.getArgumentTypes(); - JavaType[] parameterTypes = new JavaType[argumentTypes.length]; - for (int i = 0; i < parameterTypes.length; ++i) { - parameterTypes[i] = asJavaType(argumentTypes[i], runtime); - } - TargetDescription target = graalRuntime().getTarget(); - JavaType returnType = asJavaType(descriptor.getResultType(), runtime); - return ccProvider.getCallingConvention(ccType, returnType, parameterTypes, target, false); - } - - private static JavaType asJavaType(Class type, HotSpotRuntime runtime) { - if (WordBase.class.isAssignableFrom(type)) { - return runtime.lookupJavaType(wordKind().toJavaClass()); - } else { - return runtime.lookupJavaType(type); - } - } - - public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, RegisterEffect effect, CallingConvention cc, CompilerToVM vm) { - this.address = address; - this.effect = effect; - this.descriptor = descriptor; - this.cc = cc; - this.vm = vm; - } - - @Override - public String toString() { - return (stub == null ? descriptor.toString() : stub) + "@0x" + Long.toHexString(address) + ":" + cc; - } - - public CallingConvention getCallingConvention() { - return cc; - } - - public long getMaxCallTargetOffset() { - return vm.getMaxCallTargetOffset(address); - } - - public Descriptor getDescriptor() { - return descriptor; - } - - public void setCompiledStub(Stub stub) { - assert address == 0L : "cannot set stub for linkage that already has an address: " + this; - this.stub = stub; - } - - /** - * Determines if this is a call to a compiled {@linkplain Stub stub}. - */ - public boolean isCompiledStub() { - return address == 0L || stub != null; - } - - public void finalizeAddress(Backend backend) { - if (address == 0) { - assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?"; - InstalledCode code = stub.getCode(backend); - - Set destroyedRegisters = stub.getDestroyedRegisters(); - AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()]; - int i = 0; - for (Register reg : destroyedRegisters) { - temporaryLocations[i++] = reg.asValue(); - } - // Update calling convention with temporaries - cc = new CallingConvention(temporaryLocations, cc.getStackSize(), cc.getReturn(), cc.getArguments()); - address = code.getStart(); - } - } - - public long getAddress() { - assert address != 0L : "address not yet finalized: " + this; - return address; - } - - @Override - public boolean destroysRegisters() { - return effect == DESTROYS_REGISTERS; - } -} diff -r ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Tue May 21 19:51:00 2013 +0200 @@ -53,7 +53,7 @@ void shutdownCompiler() throws Throwable; - void startCompiler() throws Throwable; + void startCompiler(boolean bootstrapEnabled) throws Throwable; void bootstrap() throws Throwable; diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Tue May 21 19:51:00 2013 +0200 @@ -101,7 +101,9 @@ assert unsafe.getObject(mirror, offset) == type; } - public void startCompiler() throws Throwable { + public void startCompiler(boolean bootstrapEnabled) throws Throwable { + + bootstrapRunning = bootstrapEnabled; HotSpotVMConfig config = graalRuntime.getConfig(); long offset = config.graalMirrorInClassOffset; @@ -339,7 +341,6 @@ TTY.flush(); long startTime = System.currentTimeMillis(); - bootstrapRunning = true; boolean firstRun = true; do { // Initialize compile queue with a selected set of methods. diff -r ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe 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 Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Tue May 21 19:51:00 2013 +0200 @@ -28,32 +28,24 @@ import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.graph.UnsafeAccess.*; import static com.oracle.graal.hotspot.HotSpotBackend.*; -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.wordKind; -import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*; -import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*; +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*; +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*; import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*; import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*; -import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*; import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; -import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*; import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*; import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*; -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*; import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*; +import static com.oracle.graal.hotspot.replacements.ThreadSubstitutions.*; import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*; -import static com.oracle.graal.hotspot.stubs.LogObjectStub.*; -import static com.oracle.graal.hotspot.stubs.LogPrimitiveStub.*; -import static com.oracle.graal.hotspot.stubs.LogPrintfStub.*; import static com.oracle.graal.hotspot.stubs.NewArrayStub.*; import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; -import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*; -import static com.oracle.graal.hotspot.stubs.OSRMigrationEndStub.*; import static com.oracle.graal.hotspot.stubs.StubUtil.*; -import static com.oracle.graal.hotspot.stubs.ThreadIsInterruptedStub.*; import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*; -import static com.oracle.graal.hotspot.stubs.VMErrorStub.*; import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; import static com.oracle.graal.replacements.Log.*; @@ -70,11 +62,11 @@ import com.oracle.graal.api.code.CompilationResult.DataPatch; import com.oracle.graal.api.code.CompilationResult.Infopoint; import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.*; +import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect; +import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.nodes.*; @@ -100,7 +92,9 @@ */ public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider { - public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class); + public static final ForeignCallDescriptor OSR_MIGRATION_END = new ForeignCallDescriptor("OSR_migration_end", void.class, long.class); + public static final ForeignCallDescriptor IDENTITY_HASHCODE = new ForeignCallDescriptor("identity_hashcode", int.class, Object.class); + public static final ForeignCallDescriptor VERIFY_OOP = new ForeignCallDescriptor("verify_oop", Object.class, Object.class); public final HotSpotVMConfig config; @@ -115,7 +109,7 @@ private BoxingSnippets.Templates boxingSnippets; private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; - private final Map runtimeCalls = new HashMap<>(); + private final Map foreignCalls = new HashMap<>(); /** * The offset from the origin of an array to the first element. @@ -183,82 +177,95 @@ regConfig = createRegisterConfig(); } - protected HotSpotRuntimeCallTarget register(HotSpotRuntimeCallTarget call) { - HotSpotRuntimeCallTarget oldValue = runtimeCalls.put(call.getDescriptor(), call); - assert oldValue == null; - return call; - } + protected abstract RegisterConfig createRegisterConfig(); /** - * Registers the details for linking a call to a {@link Stub}. + * Registers the linkage for a foreign call. */ - protected RuntimeCallTarget registerStubCall(Descriptor descriptor) { - return register(HotSpotRuntimeCallTarget.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, regConfig, this, graalRuntime.getCompilerToVM())); + protected HotSpotForeignCallLinkage register(HotSpotForeignCallLinkage linkage) { + assert !foreignCalls.containsKey(linkage.getDescriptor()) : "already registered linkage for " + linkage.getDescriptor(); + foreignCalls.put(linkage.getDescriptor(), linkage); + return linkage; } /** - * Registers the details for a call to a runtime C/C++ function. + * Creates and registers the details for linking a foreign call to a {@link Stub}. */ - protected RuntimeCallTarget registerCRuntimeCall(Descriptor descriptor, long address) { - Class resultType = descriptor.getResultType(); - assert resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "C runtime call must return object thread local storage: " + descriptor; - return register(HotSpotRuntimeCallTarget.create(descriptor, address, DESTROYS_REGISTERS, NativeCall, regConfig, this, graalRuntime.getCompilerToVM())); + protected HotSpotForeignCallLinkage registerStubCall(ForeignCallDescriptor descriptor) { + return register(HotSpotForeignCallLinkage.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, NOT_LEAF)); } /** - * Registers the details for a call to a stub that never returns. + * Creates and registers the linkage for a foreign call. */ - protected RuntimeCallTarget registerNoReturnStub(Descriptor descriptor, long address, CallingConvention.Type ccType) { - return register(HotSpotRuntimeCallTarget.create(descriptor, address, PRESERVES_REGISTERS, ccType, regConfig, this, graalRuntime.getCompilerToVM())); + protected HotSpotForeignCallLinkage registerForeignCall(ForeignCallDescriptor descriptor, long address, CallingConvention.Type ccType, RegisterEffect effect, Transition transition) { + Class resultType = descriptor.getResultType(); + assert resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "foreign calls must return objects in thread local storage: " + descriptor; + return register(HotSpotForeignCallLinkage.create(descriptor, address, effect, ccType, transition)); + } + + private static void link(Stub stub) { + stub.getLinkage().setCompiledStub(stub); } /** - * Registers the details for a call to a leaf function. A leaf function does not lock, GC or - * throw exceptions. That is, the thread's execution state during the call is never inspected by - * another thread. + * Creates a {@linkplain ForeignCallStub stub} for a non-leaf foreign call. + * + * @param descriptor the signature of the call to this stub + * @param address the address of the code to call + * @param prependThread true if the JavaThread value for the current thread is to be prepended + * to the arguments for the call to {@code address} */ - protected RuntimeCallTarget registerLeafCall(Descriptor descriptor, long address, CallingConvention.Type ccType, RegisterEffect effect) { - return register(HotSpotRuntimeCallTarget.create(descriptor, address, effect, ccType, regConfig, this, graalRuntime.getCompilerToVM())); + private void linkForeignCall(ForeignCallDescriptor descriptor, long address, boolean prependThread, Replacements replacements) { + ForeignCallStub stub = new ForeignCallStub(address, descriptor, prependThread, this, replacements); + HotSpotForeignCallLinkage linkage = stub.getLinkage(); + HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage(); + linkage.setCompiledStub(stub); + register(linkage); + register(targetLinkage); } - protected abstract RegisterConfig createRegisterConfig(); - public void registerReplacements(Replacements replacements) { - registerStubCall(VERIFY_OOP); - registerStubCall(OSR_MIGRATION_END); - registerStubCall(NEW_ARRAY); - registerStubCall(UNWIND_EXCEPTION_TO_CALLER); - registerStubCall(NEW_INSTANCE); - registerStubCall(NEW_MULTI_ARRAY); - registerStubCall(LOG_PRIMITIVE); - registerStubCall(LOG_PRINTF); - registerStubCall(LOG_OBJECT); - registerStubCall(THREAD_IS_INTERRUPTED); - registerStubCall(VM_ERROR); + HotSpotVMConfig c = config; + TargetDescription target = getTarget(); + + registerForeignCall(UNCOMMON_TRAP, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF); + registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF); + registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall, PRESERVES_REGISTERS, LEAF); - HotSpotVMConfig c = config; - registerNoReturnStub(UNCOMMON_TRAP, c.uncommonTrapStub, NativeCall); - registerNoReturnStub(DEOPT_HANDLER, c.handleDeoptStub, NativeCall); - registerNoReturnStub(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall); + registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF); + registerForeignCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS, LEAF); + registerForeignCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF); + registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF); + registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF); + + registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF); + registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF); + registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF); + registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF); + registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF); - registerLeafCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS); - registerLeafCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS); - registerLeafCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS); - registerLeafCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS); - registerLeafCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS); + link(new NewInstanceStub(this, replacements, target, registerStubCall(NEW_INSTANCE))); + link(new NewArrayStub(this, replacements, target, registerStubCall(NEW_ARRAY))); + link(new ExceptionHandlerStub(this, replacements, target, foreignCalls.get(EXCEPTION_HANDLER))); + link(new UnwindExceptionToCallerStub(this, replacements, target, registerStubCall(UNWIND_EXCEPTION_TO_CALLER))); + link(new VerifyOopStub(this, replacements, target, registerStubCall(VERIFY_OOP))); - registerCRuntimeCall(OSR_MIGRATION_END_C, c.osrMigrationEndAddress); - registerCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress); - registerCRuntimeCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress); - registerCRuntimeCall(NEW_ARRAY_C, c.newArrayAddress); - registerCRuntimeCall(NEW_INSTANCE_C, c.newInstanceAddress); - registerCRuntimeCall(NEW_MULTI_ARRAY_C, c.newMultiArrayAddress); - registerCRuntimeCall(LOG_PRIMITIVE_C, c.logPrimitiveAddress); - registerCRuntimeCall(LOG_PRINTF_C, c.logObjectAddress); - registerCRuntimeCall(VM_MESSAGE_C, c.vmMessageAddress); - registerCRuntimeCall(LOG_OBJECT_C, c.logObjectAddress); - registerCRuntimeCall(THREAD_IS_INTERRUPTED_C, c.threadIsInterruptedAddress); - registerCRuntimeCall(VM_ERROR_C, c.vmErrorAddress); + linkForeignCall(IDENTITY_HASHCODE, c.identityHashCodeAddress, true, replacements); + linkForeignCall(REGISTER_FINALIZER, c.registerFinalizerAddress, true, replacements); + linkForeignCall(CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, true, replacements); + linkForeignCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, true, replacements); + linkForeignCall(MONITORENTER, c.monitorenterAddress, true, replacements); + linkForeignCall(MONITOREXIT, c.monitorexitAddress, true, replacements); + linkForeignCall(WRITE_BARRIER_PRE, c.writeBarrierPreAddress, true, replacements); + linkForeignCall(WRITE_BARRIER_POST, c.writeBarrierPostAddress, true, replacements); + linkForeignCall(NEW_MULTI_ARRAY, c.newMultiArrayAddress, true, replacements); + linkForeignCall(LOG_PRINTF, c.logPrintfAddress, true, replacements); + linkForeignCall(LOG_OBJECT, c.logObjectAddress, true, replacements); + linkForeignCall(LOG_PRIMITIVE, c.logPrimitiveAddress, true, replacements); + linkForeignCall(THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, true, replacements); + linkForeignCall(VM_ERROR, c.vmErrorAddress, true, replacements); + linkForeignCall(OSR_MIGRATION_END, c.osrMigrationEndAddress, false, replacements); if (GraalOptions.IntrinsifyObjectMethods) { replacements.registerSubstitutions(ObjectSubstitutions.class); @@ -286,46 +293,10 @@ checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget()); instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget()); newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget()); - monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking); + monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), c.useFastLocking); writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget()); boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget()); exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget()); - - TargetDescription target = getTarget(); - link(new NewInstanceStub(this, replacements, target, runtimeCalls.get(NEW_INSTANCE))); - link(new NewArrayStub(this, replacements, target, runtimeCalls.get(NEW_ARRAY))); - link(new NewMultiArrayStub(this, replacements, target, runtimeCalls.get(NEW_MULTI_ARRAY))); - link(new ThreadIsInterruptedStub(this, replacements, target, runtimeCalls.get(THREAD_IS_INTERRUPTED))); - link(new ExceptionHandlerStub(this, replacements, target, runtimeCalls.get(EXCEPTION_HANDLER))); - link(new UnwindExceptionToCallerStub(this, replacements, target, runtimeCalls.get(UNWIND_EXCEPTION_TO_CALLER))); - link(new VerifyOopStub(this, replacements, target, runtimeCalls.get(VERIFY_OOP))); - link(new OSRMigrationEndStub(this, replacements, target, runtimeCalls.get(OSR_MIGRATION_END))); - link(new LogPrimitiveStub(this, replacements, target, runtimeCalls.get(LOG_PRIMITIVE))); - link(new LogObjectStub(this, replacements, target, runtimeCalls.get(LOG_OBJECT))); - link(new LogPrintfStub(this, replacements, target, runtimeCalls.get(LOG_PRINTF))); - link(new VMErrorStub(this, replacements, target, runtimeCalls.get(VM_ERROR))); - - linkRuntimeCall(IDENTITY_HASHCODE, config.identityHashCodeAddress, replacements); - linkRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerAddress, replacements); - linkRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionAddress, replacements); - linkRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionAddress, replacements); - linkRuntimeCall(MONITORENTER, config.monitorenterAddress, replacements); - linkRuntimeCall(MONITOREXIT, config.monitorexitAddress, replacements); - linkRuntimeCall(WRITE_BARRIER_PRE, config.writeBarrierPreAddress, replacements); - linkRuntimeCall(WRITE_BARRIER_POST, config.writeBarrierPostAddress, replacements); - } - - private static void link(Stub stub) { - stub.getLinkage().setCompiledStub(stub); - } - - private void linkRuntimeCall(Descriptor descriptor, long address, Replacements replacements) { - RuntimeCallStub stub = new RuntimeCallStub(address, descriptor, true, this, replacements, regConfig, graalRuntime.getCompilerToVM()); - HotSpotRuntimeCallTarget linkage = stub.getLinkage(); - HotSpotRuntimeCallTarget targetLinkage = stub.getTargetLinkage(); - linkage.setCompiledStub(stub); - runtimeCalls.put(linkage.getDescriptor(), linkage); - runtimeCalls.put(targetLinkage.getDescriptor(), targetLinkage); } public HotSpotGraalRuntime getGraalRuntime() { @@ -712,8 +683,8 @@ OSRStartNode osrStart = (OSRStartNode) n; StartNode newStart = graph.add(new StartNode()); LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind()))); - RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer)); - migrationEnd.setStateAfter(osrStart.stateAfter()); + ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(OSR_MIGRATION_END, buffer)); + newStart.setStateAfter(osrStart.stateAfter()); newStart.setNext(migrationEnd); FixedNode next = osrStart.next(); @@ -854,9 +825,9 @@ return HotSpotResolvedObjectType.fromClass(clazz); } - public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) { - HotSpotRuntimeCallTarget callTarget = runtimeCalls.get(descriptor); - assert runtimeCalls != null : descriptor; + public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) { + HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor); + assert foreignCalls != null : descriptor; callTarget.finalizeAddress(graalRuntime.getBackend()); return callTarget; } @@ -996,6 +967,15 @@ } @Override + public boolean hasSideEffect(ForeignCallDescriptor descriptor) { + // Only these two foreign calls are expected to be made with + // a node that implements StateSplit. They need to be a state + // split so that the stack trace they produce is accurate. + assert descriptor == CREATE_NULL_POINTER_EXCEPTION || descriptor == CREATE_OUT_OF_BOUNDS_EXCEPTION : descriptor; + return false; + } + + @Override public TargetDescription getTarget() { return graalRuntime.getTarget(); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * Implements a direct call to a C/C++ HotSpot function. - */ -public class CRuntimeCall extends DeoptimizingFixedWithNextNode implements LIRGenLowerable { - - @Input private final NodeInputList arguments; - - private final Descriptor descriptor; - - public CRuntimeCall(Descriptor descriptor, ValueNode... arguments) { - super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); - this.arguments = new NodeInputList<>(this, arguments); - this.descriptor = descriptor; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); - Value[] args = new Value[arguments.size()]; - for (int i = 0; i < args.length; i++) { - args[i] = gen.operand(arguments.get(i)); - } - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, args); - if (result != null) { - gen.setResult(this, result); - } - } - - @Override - public boolean canDeoptimize() { - return true; - } - - @Override - public DeoptimizationReason getDeoptimizationReason() { - return null; - } -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -/** - * Node implementing a call to {@code GraalRuntime::monitorenter}. - */ -public class MonitorEnterStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - @Input private ValueNode object; - @Input private ValueNode lock; - public static final Descriptor MONITORENTER = new Descriptor("monitorenter", true, void.class, Object.class, Word.class); - - public MonitorEnterStubCall(ValueNode object, ValueNode lock) { - super(StampFactory.forVoid()); - this.object = object; - this.lock = lock; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MONITORENTER); - gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.operand(lock)); - } - - @NodeIntrinsic - public static native void call(Object object, Word lock); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; @@ -38,7 +38,7 @@ @Input private ValueNode object; private int lockDepth; - public static final Descriptor MONITOREXIT = new Descriptor("monitorexit", true, void.class, Object.class, Word.class); + public static final ForeignCallDescriptor MONITOREXIT = new ForeignCallDescriptor("monitorexit", void.class, Object.class, Word.class); public MonitorExitStubCall(ValueNode object, int lockDepth) { super(StampFactory.forVoid()); @@ -51,8 +51,8 @@ assert lockDepth != -1; HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; StackSlot slot = hsGen.getLockSlot(lockDepth); - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT); - gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.emitAddress(slot)); + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(MonitorExitStubCall.MONITOREXIT); + gen.emitForeignCall(linkage, this, gen.operand(object), gen.emitAddress(slot)); } @NodeIntrinsic diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; @@ -43,7 +43,7 @@ @Input private ValueNode hub; @Input private ValueNode length; - public static final Descriptor NEW_ARRAY = new Descriptor("new_array", false, Object.class, Word.class, int.class); + public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class); public NewArrayStubCall(ValueNode hub, ValueNode length) { super(defaultStamp); @@ -62,8 +62,8 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length)); + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(NEW_ARRAY); + Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length)); gen.setResult(this, result); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; @@ -42,7 +42,7 @@ @Input private ValueNode hub; - public static final Descriptor NEW_INSTANCE = new Descriptor("new_instance", false, Object.class, Word.class); + public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class); public NewInstanceStubCall(ValueNode hub) { super(defaultStamp); @@ -60,8 +60,8 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub)); + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(NEW_INSTANCE); + Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub)); gen.setResult(this, result); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Tue May 21 19:51:00 2013 +0200 @@ -22,22 +22,18 @@ */ package com.oracle.graal.hotspot.nodes; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.stubs.*; -import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** - * Node implementing a call to {@link NewMultiArrayStub}. + * Node implementing a call to {@code GraalRuntime::new_multi_array}. */ -public class NewMultiArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable { +public class NewMultiArrayStubCall extends ForeignCallNode { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -45,10 +41,10 @@ @Input private ValueNode dims; private final int rank; - public static final Descriptor NEW_MULTI_ARRAY = new Descriptor("new_multi_array", false, Object.class, Word.class, int.class, Word.class); + public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class); public NewMultiArrayStubCall(ValueNode hub, int rank, ValueNode dims) { - super(defaultStamp); + super(NEW_MULTI_ARRAY, defaultStamp); this.hub = hub; this.rank = rank; this.dims = dims; @@ -64,10 +60,8 @@ } @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NewMultiArrayStubCall.NEW_MULTI_ARRAY); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), Constant.forInt(rank), gen.operand(dims)); - gen.setResult(this, result); + protected Value[] operands(LIRGeneratorTool gen) { + return new Value[]{gen.operand(hub), Constant.forInt(rank), gen.operand(dims)}; } @NodeIntrinsic diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.stubs.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * Node implementing a call to {@link ThreadIsInterruptedStub}. - */ -public class ThreadIsInterruptedStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - @Input private ValueNode thread; - @Input private ValueNode clearIsInterrupted; - public static final Descriptor THREAD_IS_INTERRUPTED = new Descriptor("thread_is_interrupted", false, boolean.class, Object.class, boolean.class); - - public ThreadIsInterruptedStubCall(ValueNode thread, ValueNode clearIsInterrupted) { - super(StampFactory.forInteger(Kind.Int, 0, 1)); - this.thread = thread; - this.clearIsInterrupted = clearIsInterrupted; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(ThreadIsInterruptedStubCall.THREAD_IS_INTERRUPTED); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(thread), gen.operand(clearIsInterrupted)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static boolean call(Thread thread, boolean clearIsInterrupted) { - try { - Method isInterrupted = Thread.class.getDeclaredMethod("isInterrupted", boolean.class); - isInterrupted.setAccessible(true); - return (Boolean) isInterrupted.invoke(thread, clearIsInterrupted); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; @@ -39,7 +38,7 @@ private final String format; @Input private ValueNode value; - public static final Descriptor VM_ERROR = new Descriptor("vm_error", false, void.class, Object.class, Object.class, long.class); + public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); private VMErrorNode(String format, ValueNode value) { super(StampFactory.forVoid()); @@ -58,8 +57,8 @@ Constant whereArg = Constant.forObject(whereString.intern()); Constant formatArg = Constant.forObject(format.intern()); - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VMErrorNode.VM_ERROR); - gen.emitCall(stub, stub.getCallingConvention(), null, whereArg, formatArg, gen.operand(value)); + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(VMErrorNode.VM_ERROR); + gen.emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value)); } @NodeIntrinsic diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.hotspot.stubs.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * Call to {@link VerifyOopStub}. - */ -public class VerifyOopStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - @Input private ValueNode object; - public static final Descriptor VERIFY_OOP = new Descriptor("verify_oop", false, Object.class, Object.class); - - public VerifyOopStubCall(ValueNode object) { - super(StampFactory.objectNonNull()); - this.object = object; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VerifyOopStubCall.VERIFY_OOP); - gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object)); - } - - @NodeIntrinsic - public static native Object call(Object object); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; @@ -37,7 +37,7 @@ @Input private ValueNode object; @Input private ValueNode card; - public static final Descriptor WRITE_BARRIER_POST = new Descriptor("writeBarrierPost", true, void.class, Object.class, Word.class); + public static final ForeignCallDescriptor WRITE_BARRIER_POST = new ForeignCallDescriptor("writeBarrierPost", void.class, Object.class, Word.class); public WriteBarrierPostStubCall(ValueNode object, ValueNode card) { super(StampFactory.forVoid()); @@ -47,8 +47,8 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPostStubCall.WRITE_BARRIER_POST); - gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object), gen.operand(card)); + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(WriteBarrierPostStubCall.WRITE_BARRIER_POST); + gen.emitForeignCall(linkage, null, gen.operand(object), gen.operand(card)); } @NodeIntrinsic diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; @@ -35,7 +35,7 @@ public class WriteBarrierPreStubCall extends FixedWithNextNode implements LIRGenLowerable { @Input private ValueNode object; - public static final Descriptor WRITE_BARRIER_PRE = new Descriptor("writeBarrierPre", true, void.class, Object.class); + public static final ForeignCallDescriptor WRITE_BARRIER_PRE = new ForeignCallDescriptor("writeBarrierPre", void.class, Object.class); public WriteBarrierPreStubCall(ValueNode object) { super(StampFactory.forVoid()); @@ -44,8 +44,8 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPreStubCall.WRITE_BARRIER_PRE); - gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object)); + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(WriteBarrierPreStubCall.WRITE_BARRIER_PRE); + gen.emitForeignCall(linkage, null, gen.operand(object)); } @NodeIntrinsic diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Tue May 21 19:51:00 2013 +0200 @@ -25,16 +25,13 @@ import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import sun.misc.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.word.*; /** @@ -73,56 +70,18 @@ Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); if (encrypt) { - EncryptBlockStubCall.call(inAddr, outAddr, kAddr); + encryptBlockStub(ENCRYPT_BLOCK, inAddr, outAddr, kAddr); } else { - DecryptBlockStubCall.call(inAddr, outAddr, kAddr); + decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr); } } - abstract static class CryptBlockStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - @Input private ValueNode in; - @Input private ValueNode out; - @Input private ValueNode key; - - private final Descriptor descriptor; - - public CryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key, Descriptor descriptor) { - super(StampFactory.forVoid()); - this.in = in; - this.out = out; - this.key = key; - this.descriptor = descriptor; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); - gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(in), gen.operand(out), gen.operand(key)); - } - } + public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Word.class); + public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Word.class); - public static class EncryptBlockStubCall extends CryptBlockStubCall { - - public static final Descriptor ENCRYPT_BLOCK = new Descriptor("encrypt_block", false, void.class, Word.class, Word.class, Word.class); - - public EncryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) { - super(in, out, key, ENCRYPT_BLOCK); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key); - } + @NodeIntrinsic(ForeignCallNode.class) + public static native void encryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key); - public static class DecryptBlockStubCall extends CryptBlockStubCall { - - public static final Descriptor DECRYPT_BLOCK = new Descriptor("decrypt_block", false, void.class, Word.class, Word.class, Word.class); - - public DecryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) { - super(in, out, key, DECRYPT_BLOCK); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key); - } + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Tue May 21 19:51:00 2013 +0200 @@ -25,16 +25,13 @@ import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import sun.misc.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.replacements.Snippet.Fold; import com.oracle.graal.word.*; @@ -73,19 +70,6 @@ } } - private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { - Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); - Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); - Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); - Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); - if (encrypt) { - EncryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); - } else { - DecryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); - } - - } - @MethodSubstitution(isStatic = false) static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), ANY_LOCATION); @@ -96,54 +80,24 @@ } } - abstract static class AESCryptStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - @Input private ValueNode in; - @Input private ValueNode out; - @Input private ValueNode key; - @Input private ValueNode r; - @Input private ValueNode inLength; - - private final Descriptor descriptor; - - public AESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength, Descriptor descriptor) { - super(StampFactory.forVoid()); - this.in = in; - this.out = out; - this.key = key; - this.r = r; - this.inLength = inLength; - this.descriptor = descriptor; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); - gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength)); + private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { + Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); + Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); + if (encrypt) { + encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength); + } else { + decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength); } } - public static class EncryptAESCryptStubCall extends AESCryptStubCall { - - public static final Descriptor ENCRYPT = new Descriptor("encrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class); - - public EncryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) { - super(in, out, key, r, inLength, ENCRYPT); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key, Word r, int inLength); - } + public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class); + public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class); - public static class DecryptAESCryptStubCall extends AESCryptStubCall { - - public static final Descriptor DECRYPT = new Descriptor("decrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class); + @NodeIntrinsic(ForeignCallNode.class) + public static native void encryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key, Word r, int inLength); - public DecryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) { - super(in, out, key, r, inLength, DECRYPT); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key, Word r, int inLength); - } + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key, Word r, int inLength); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Tue May 21 19:51:00 2013 +0200 @@ -23,17 +23,16 @@ package com.oracle.graal.hotspot.replacements; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.meta.HotSpotRuntime.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import sun.misc.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.replacements.Snippet.Fold; @@ -450,11 +449,14 @@ public static Object verifyOop(Object object) { if (verifyOops()) { - VerifyOopStubCall.call(object); + verifyOopStub(VERIFY_OOP, object); } return object; } + @NodeIntrinsic(ForeignCallNode.class) + private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object); + /** * Gets the value of the stack pointer register as a Word. */ @@ -672,11 +674,9 @@ return identityHashCode(IDENTITY_HASHCODE, x); } - public static final Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class); - @SuppressWarnings("unused") - @NodeIntrinsic(RuntimeCallNode.class) - public static int identityHashCode(@ConstantNodeParameter Descriptor descriptor, Object object) { + @NodeIntrinsic(ForeignCallNode.class) + public static int identityHashCode(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object) { return System.identityHashCode(object); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Tue May 21 19:51:00 2013 +0200 @@ -35,6 +35,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.hotspot.nodes.*; @@ -159,7 +160,7 @@ // owns the bias and we need to revoke that bias. The revocation will occur // in the interpreter runtime. traceObject(trace, "+lock{stub:revoke}", object); - MonitorEnterStubCall.call(object, lock); + monitorenterStub(MONITORENTER, object, lock); return; } else { // At this point we know the epoch has expired, meaning that the @@ -179,7 +180,7 @@ // succeeded in biasing it toward itself and we need to revoke that // bias. The revocation will occur in the runtime in the slow case. traceObject(trace, "+lock{stub:epoch-expired}", object); - MonitorEnterStubCall.call(object, lock); + monitorenterStub(MONITORENTER, object, lock); return; } } else { @@ -236,7 +237,7 @@ if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) { // Most likely not a recursive lock, go into a slow runtime call traceObject(trace, "+lock{stub:failed-cas}", object); - MonitorEnterStubCall.call(object, lock); + monitorenterStub(MONITORENTER, object, lock); return; } else { // Recursively locked => write 0 to the lock slot @@ -262,7 +263,7 @@ // cannot float about the null check above final Word lock = beginLockScope(lockDepth); traceObject(trace, "+lock{stub}", object); - MonitorEnterStubCall.call(object, lock); + monitorenterStub(MONITORENTER, object, lock); } @Snippet @@ -517,4 +518,10 @@ } } } + + public static final ForeignCallDescriptor MONITORENTER = new ForeignCallDescriptor("monitorenter", void.class, Object.class, Word.class); + + @NodeIntrinsic(ForeignCallNode.class) + private static native void monitorenterStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock); + } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Tue May 21 19:51:00 2013 +0200 @@ -25,7 +25,7 @@ import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; @@ -38,8 +38,8 @@ @ClassSubstitution(java.lang.System.class) public class SystemSubstitutions { - public static final Descriptor JAVA_TIME_MILLIS = new Descriptor("javaTimeMillis", false, long.class); - public static final Descriptor JAVA_TIME_NANOS = new Descriptor("javaTimeNanos", false, long.class); + public static final ForeignCallDescriptor JAVA_TIME_MILLIS = new ForeignCallDescriptor("javaTimeMillis", long.class); + public static final ForeignCallDescriptor JAVA_TIME_NANOS = new ForeignCallDescriptor("javaTimeNanos", long.class); @MacroSubstitution(macro = ArrayCopyNode.class) public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); @@ -63,8 +63,8 @@ return computeHashCode(x); } - @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) - public static long callLong(@ConstantNodeParameter Descriptor descriptor) { + @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true) + public static long callLong(@ConstantNodeParameter ForeignCallDescriptor descriptor) { if (descriptor == JAVA_TIME_MILLIS) { return System.currentTimeMillis(); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Tue May 21 19:51:00 2013 +0200 @@ -24,8 +24,15 @@ import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.word.*; /** @@ -51,6 +58,22 @@ } } - return ThreadIsInterruptedStubCall.call(thisObject, clearInterrupted); + return threadIsInterruptedStub(THREAD_IS_INTERRUPTED, thisObject, clearInterrupted); + } + + public static final ForeignCallDescriptor THREAD_IS_INTERRUPTED = new ForeignCallDescriptor("thread_is_interrupted", boolean.class, Object.class, boolean.class); + + /** + * @param descriptor + */ + @NodeIntrinsic(ForeignCallNode.class) + private static boolean threadIsInterruptedStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Thread thread, boolean clearIsInterrupted) { + try { + Method isInterrupted = Thread.class.getDeclaredMethod("isInterrupted", boolean.class); + isInterrupted.setAccessible(true); + return (Boolean) isInterrupted.invoke(thread, clearIsInterrupted); + } catch (Exception e) { + throw new GraalInternalError(e); + } } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CRuntimeStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CRuntimeStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.SnippetTemplate.Arguments; -import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; - -/** - * Base class for a stub that saves registers around a C runtime call. - */ -public abstract class CRuntimeStub extends SnippetStub { - - public CRuntimeStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Override - protected Arguments makeArguments(SnippetInfo stub) { - Arguments args = new Arguments(stub); - for (int i = 0; i < stub.getParameterCount(); i++) { - args.add(stub.getParameterName(i), null); - } - return args; - } -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Tue May 21 19:51:00 2013 +0200 @@ -27,14 +27,14 @@ import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.stubs.StubUtil.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.Fold; @@ -48,9 +48,9 @@ *

* The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}. */ -public class ExceptionHandlerStub extends CRuntimeStub { +public class ExceptionHandlerStub extends SnippetStub { - public ExceptionHandlerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + public ExceptionHandlerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(runtime, replacements, target, linkage); } @@ -125,8 +125,8 @@ return enabled || graalRuntime().getConfig().cAssertions; } - public static final Descriptor EXCEPTION_HANDLER_FOR_PC = descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc", false); + public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc"); - @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true) - public static native Word exceptionHandlerForPc(@ConstantNodeParameter Descriptor exceptionHandlerForPc, Word thread); + @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true) + public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.api.code.CallingConvention.Type.*; +import static com.oracle.graal.api.meta.MetaUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*; +import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; +import com.oracle.graal.word.phases.*; + +/** + * A {@linkplain #getGraph() generated} stub for a {@link Transition non-leaf} foreign call from + * compiled code. A stub is required for such calls as the caller may be scheduled for + * deoptimization while the call is in progress. And since these are foreign/runtime calls on slow + * paths, we don't want to force the register allocator to spill around the call. As such, this stub + * saves and restores all allocatable registers. It also + * {@linkplain StubUtil#handlePendingException(boolean) handles} any exceptions raised during the + * foreign call. + */ +public class ForeignCallStub extends Stub { + + /** + * The target of the call. + */ + private final HotSpotForeignCallLinkage target; + + /** + * Specifies if the JavaThread value for the current thread is to be prepended to the arguments + * for the call to {@link #target}. + */ + protected final boolean prependThread; + + /** + * Creates a stub for a call to code at a given address. + * + * @param address the address of the code to call + * @param descriptor the signature of the call to this stub + * @param prependThread true if the JavaThread value for the current thread is to be prepended + * to the arguments for the call to {@code address} + */ + public ForeignCallStub(long address, ForeignCallDescriptor descriptor, boolean prependThread, HotSpotRuntime runtime, Replacements replacements) { + super(runtime, replacements, HotSpotForeignCallLinkage.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, NOT_LEAF)); + this.prependThread = prependThread; + Class[] targetParameterTypes = createTargetParameters(descriptor); + ForeignCallDescriptor targetSig = new ForeignCallDescriptor(descriptor.getName() + ":C", descriptor.getResultType(), targetParameterTypes); + target = HotSpotForeignCallLinkage.create(targetSig, address, DESTROYS_REGISTERS, NativeCall, NOT_LEAF); + } + + /** + * Gets the linkage information for the call from this stub. + */ + public HotSpotForeignCallLinkage getTargetLinkage() { + return target; + } + + private Class[] createTargetParameters(ForeignCallDescriptor descriptor) { + Class[] parameters = descriptor.getArgumentTypes(); + if (prependThread) { + Class[] newParameters = new Class[parameters.length + 1]; + System.arraycopy(parameters, 0, newParameters, 1, parameters.length); + newParameters[0] = Word.class; + return newParameters; + } + return parameters; + } + + @Override + protected ResolvedJavaMethod getInstalledCodeOwner() { + return null; + } + + @Override + protected Object debugScopeContext() { + return new JavaMethod() { + + public Signature getSignature() { + ForeignCallDescriptor d = linkage.getDescriptor(); + Class[] arguments = d.getArgumentTypes(); + JavaType[] parameters = new JavaType[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + parameters[i] = runtime.lookupJavaType(arguments[i]); + } + return new HotSpotSignature(runtime.lookupJavaType(d.getResultType()), parameters); + } + + public String getName() { + return linkage.getDescriptor().getName(); + } + + public JavaType getDeclaringClass() { + return runtime.lookupJavaType(ForeignCallStub.class); + } + + @Override + public String toString() { + return format("ForeignCallStub<%n(%p)>", this); + } + }; + } + + static class GraphBuilder { + + public GraphBuilder(Stub stub) { + this.graph = new StructuredGraph(stub.toString(), null); + graph.replaceFixed(graph.start(), graph.add(new StubStartNode(stub))); + this.lastFixedNode = graph.start(); + } + + final StructuredGraph graph; + private FixedWithNextNode lastFixedNode; + + T add(T node) { + return graph.unique(node); + } + + T append(T node) { + T result = graph.add(node); + assert lastFixedNode != null; + assert result.predecessor() == null; + graph.addAfterFixed(lastFixedNode, result); + if (result instanceof FixedWithNextNode) { + lastFixedNode = (FixedWithNextNode) result; + } else { + lastFixedNode = null; + } + return result; + } + } + + /** + * Creates a graph for this stub. + *

+ * If the stub returns an object, the graph created corresponds to this pseudo code: + * + *

+     *     Object foreignFunctionStub(args...) {
+     *         foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             getAndClearObjectResult(thread());
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *         return verifyObject(getAndClearObjectResult(thread()));
+     *     }
+     * 
+ * + * If the stub returns a primitive or word, the graph created corresponds to this pseudo code + * (using {@code int} as the primitive return type): + * + *
+     *     int foreignFunctionStub(args...) {
+     *         int result = foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *         return result;
+     *     }
+     * 
+ * + * If the stub is void, the graph created corresponds to this pseudo code: + * + *
+     *     void foreignFunctionStub(args...) {
+     *         foreignFunction(currentThread,  args);
+     *         if (clearPendingException(thread())) {
+     *             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+     *         }
+     *     }
+     * 
+ * + * In each example above, the {@code currentThread} argument is the C++ JavaThread value (i.e., + * %r15 on AMD64) and is only prepended if {@link #prependThread} is true. + */ + @Override + protected StructuredGraph getGraph() { + Class[] args = linkage.getDescriptor().getArgumentTypes(); + boolean isObjectResult = linkage.getCallingConvention().getReturn().getKind() == Kind.Object; + GraphBuilder builder = new GraphBuilder(this); + LocalNode[] locals = createLocals(builder, args); + + ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(runtime.threadRegister(), true, false)) : null; + ValueNode result = createTargetCall(builder, locals, thread); + createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph)); + if (isObjectResult) { + InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); + result = createInvoke(builder, StubUtil.class, "verifyObject", object); + } + builder.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); + + if (Debug.isDumpEnabled()) { + Debug.dump(builder.graph, "Initial stub graph"); + } + + for (InvokeNode invoke : builder.graph.getNodes(InvokeNode.class).snapshot()) { + inline(invoke); + } + assert builder.graph.getNodes(InvokeNode.class).isEmpty(); + + if (Debug.isDumpEnabled()) { + Debug.dump(builder.graph, "Stub graph before compilation"); + } + + return builder.graph; + } + + private LocalNode[] createLocals(GraphBuilder builder, Class[] args) { + LocalNode[] locals = new LocalNode[args.length]; + ResolvedJavaType accessingClass = runtime.lookupJavaType(getClass()); + for (int i = 0; i < args.length; i++) { + ResolvedJavaType type = runtime.lookupJavaType(args[i]).resolve(accessingClass); + Kind kind = type.getKind().getStackKind(); + Stamp stamp; + if (kind == Kind.Object) { + stamp = StampFactory.declared(type); + } else { + stamp = StampFactory.forKind(kind); + } + LocalNode local = builder.add(new LocalNode(i, stamp)); + locals[i] = local; + } + return locals; + } + + private InvokeNode createInvoke(GraphBuilder builder, Class declaringClass, String name, ValueNode... hpeArgs) { + ResolvedJavaMethod method = null; + for (Method m : declaringClass.getDeclaredMethods()) { + if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) { + assert method == null : "found more than one method in " + declaringClass + " named " + name; + method = runtime.lookupJavaMethod(m); + } + } + assert method != null : "did not find method in " + declaringClass + " named " + name; + JavaType returnType = method.getSignature().getReturnType(null); + MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType)); + InvokeNode invoke = builder.append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI)); + return invoke; + } + + private ForeignCallNode createTargetCall(GraphBuilder builder, LocalNode[] locals, ReadRegisterNode thread) { + if (prependThread) { + ValueNode[] targetArguments = new ValueNode[1 + locals.length]; + targetArguments[0] = thread; + System.arraycopy(locals, 0, targetArguments, 1, locals.length); + return builder.append(new ForeignCallNode(target.getDescriptor(), targetArguments)); + } else { + return builder.append(new ForeignCallNode(target.getDescriptor(), locals)); + } + } + + private void inline(InvokeNode invoke) { + StructuredGraph graph = invoke.graph(); + ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); + ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget()); + StructuredGraph calleeGraph = repl.makeGraph(method, null, null); + InliningUtil.inline(invoke, calleeGraph, false); + new NodeIntrinsificationPhase(runtime).apply(graph); + new WordTypeRewriterPhase(runtime, wordKind()).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + } +} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogObjectStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogObjectStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.hotspot.stubs.StubUtil.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -/** - * Stub called from {@link Log}. - */ -public class LogObjectStub extends CRuntimeStub { - - public LogObjectStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Snippet - private static void logObject(Object object, int flags) { - logObjectC(LOG_OBJECT_C, thread(), object, flags); - } - - public static final Descriptor LOG_OBJECT_C = descriptorFor(LogObjectStub.class, "logObjectC", false); - - @NodeIntrinsic(CRuntimeCall.class) - public static native void logObjectC(@ConstantNodeParameter Descriptor logObjectC, Word thread, Object object, int flags); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrimitiveStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrimitiveStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.hotspot.stubs.StubUtil.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -/** - * Stub called from {@link Log}. - */ -public class LogPrimitiveStub extends CRuntimeStub { - - public LogPrimitiveStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Snippet - private static void logPrimitive(char typeChar, long value, boolean newline) { - logPrimitivefC(LOG_PRIMITIVE_C, thread(), typeChar, value, newline); - } - - public static final Descriptor LOG_PRIMITIVE_C = descriptorFor(LogPrimitiveStub.class, "logPrimitivefC", false); - - @NodeIntrinsic(CRuntimeCall.class) - public static native void logPrimitivefC(@ConstantNodeParameter Descriptor logPrimitivefC, Word thread, char typeChar, long value, boolean newline); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrintfStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrintfStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.hotspot.stubs.StubUtil.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -/** - * Stub called from {@link Log}. - */ -public class LogPrintfStub extends CRuntimeStub { - - public LogPrintfStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Snippet - private static void logPrintf(String format, long v1, long v2, long v3) { - logPrintfC(LOG_PRINTF_C, thread(), format, v1, v2, v3); - } - - public static final Descriptor LOG_PRINTF_C = descriptorFor(LogPrintfStub.class, "logPrintfC", false); - - @NodeIntrinsic(CRuntimeCall.class) - public static native void logPrintfC(@ConstantNodeParameter Descriptor logPrintfC, Word thread, String format, long v1, long v2, long v3); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue May 21 19:51:00 2013 +0200 @@ -28,7 +28,6 @@ import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; import static com.oracle.graal.hotspot.stubs.StubUtil.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; @@ -37,6 +36,7 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; @@ -53,7 +53,7 @@ */ public class NewArrayStub extends SnippetStub { - public NewArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + public NewArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(runtime, replacements, target, linkage); } @@ -120,8 +120,8 @@ return verifyObject(getAndClearObjectResult(thread())); } - public static final Descriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC", false); + public static final ForeignCallDescriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC"); - @NodeIntrinsic(CRuntimeCall.class) - public static native void newArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int length); + @NodeIntrinsic(ForeignCallNode.class) + public static native void newArrayC(@ConstantNodeParameter ForeignCallDescriptor newArrayC, Word thread, Word hub, int length); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue May 21 19:51:00 2013 +0200 @@ -28,7 +28,6 @@ import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; import static com.oracle.graal.hotspot.stubs.StubUtil.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; @@ -37,6 +36,7 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; @@ -53,7 +53,7 @@ */ public class NewInstanceStub extends SnippetStub { - public NewInstanceStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + public NewInstanceStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(runtime, replacements, target, linkage); } @@ -239,8 +239,8 @@ return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath"); } - public static final Descriptor NEW_INSTANCE_C = descriptorFor(NewInstanceStub.class, "newInstanceC", false); + public static final ForeignCallDescriptor NEW_INSTANCE_C = descriptorFor(NewInstanceStub.class, "newInstanceC"); - @NodeIntrinsic(CRuntimeCall.class) - public static native void newInstanceC(@ConstantNodeParameter Descriptor newInstanceC, Word thread, Word hub); + @NodeIntrinsic(ForeignCallNode.class) + public static native void newInstanceC(@ConstantNodeParameter ForeignCallDescriptor newInstanceC, Word thread, Word hub); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.hotspot.stubs.StubUtil.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -/** - * Stub called from {@link NewMultiArrayStubCall}. - */ -public class NewMultiArrayStub extends CRuntimeStub { - - public NewMultiArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Snippet - private static Object newMultiArray(Word hub, int rank, Word dims) { - newMultiArrayC(NEW_MULTI_ARRAY_C, thread(), hub, rank, dims); - handlePendingException(true); - return verifyObject(getAndClearObjectResult(thread())); - } - - public static final Descriptor NEW_MULTI_ARRAY_C = descriptorFor(NewMultiArrayStub.class, "newMultiArrayC", false); - - @NodeIntrinsic(CRuntimeCall.class) - public static native void newMultiArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int rank, Word dims); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/OSRMigrationEndStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/OSRMigrationEndStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.hotspot.stubs.StubUtil.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -/** - * Stub called from {@link OSRStartNode}. - */ -public class OSRMigrationEndStub extends CRuntimeStub { - - public OSRMigrationEndStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Snippet - private static void osrMigrationEnd(Word buffer) { - osrMigrationEndC(OSR_MIGRATION_END_C, buffer); - } - - public static final Descriptor OSR_MIGRATION_END_C = descriptorFor(OSRMigrationEndStub.class, "osrMigrationEndC", false); - - @NodeIntrinsic(CRuntimeCall.class) - public static native void osrMigrationEndC(@ConstantNodeParameter Descriptor osrMigrationEndC, Word buffer); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.api.code.CallingConvention.Type.*; -import static com.oracle.graal.api.meta.MetaUtil.*; -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.hotspot.HotSpotRuntimeCallTarget.RegisterEffect.*; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.bridge.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.replacements.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.word.*; -import com.oracle.graal.word.phases.*; - -/** - * A stub that calls into a HotSpot C/C++ runtime function using the native - * {@link CallingConvention}. - */ -public class RuntimeCallStub extends Stub { - - /** - * The target of the call. - */ - private final HotSpotRuntimeCallTarget target; - - /** - * Specifies if the JavaThread value for the current thread is to be prepended to the arguments - * for the call to {@link #target}. - */ - protected final boolean prependThread; - - /** - * Creates a stub for a call to code at a given address. - * - * @param address the address of the code to call - * @param sig the signature of the call to this stub - * @param prependThread true if the JavaThread value for the current thread is to be prepended - * to the arguments for the call to {@code address} - * @param regConfig used to get the calling convention for the call to this stub from Graal - * compiled Java code as well as the calling convention for the call to - * {@code address} - * @param vm the Java to HotSpot C/C++ runtime interface - */ - public RuntimeCallStub(long address, Descriptor sig, boolean prependThread, HotSpotRuntime runtime, Replacements replacements, RegisterConfig regConfig, CompilerToVM vm) { - super(runtime, replacements, HotSpotRuntimeCallTarget.create(sig, 0L, PRESERVES_REGISTERS, JavaCallee, regConfig, runtime, vm)); - this.prependThread = prependThread; - Class[] targetParameterTypes = createTargetParameters(sig); - Descriptor targetSig = new Descriptor(sig.getName() + ":C", sig.hasSideEffect(), sig.getResultType(), targetParameterTypes); - target = HotSpotRuntimeCallTarget.create(targetSig, address, DESTROYS_REGISTERS, NativeCall, regConfig, runtime, vm); - } - - /** - * Gets the linkage information for the runtime call. - */ - public HotSpotRuntimeCallTarget getTargetLinkage() { - return target; - } - - private Class[] createTargetParameters(Descriptor sig) { - Class[] parameters = sig.getArgumentTypes(); - if (prependThread) { - Class[] newParameters = new Class[parameters.length + 1]; - System.arraycopy(parameters, 0, newParameters, 1, parameters.length); - newParameters[0] = Word.class; - return newParameters; - } - return parameters; - } - - @Override - protected ResolvedJavaMethod getInstalledCodeOwner() { - return null; - } - - @Override - protected Object debugScopeContext() { - return new JavaMethod() { - - public Signature getSignature() { - Descriptor d = linkage.getDescriptor(); - Class[] arguments = d.getArgumentTypes(); - JavaType[] parameters = new JavaType[arguments.length]; - for (int i = 0; i < arguments.length; i++) { - parameters[i] = runtime.lookupJavaType(arguments[i]); - } - return new HotSpotSignature(runtime.lookupJavaType(d.getResultType()), parameters); - } - - public String getName() { - return linkage.getDescriptor().getName(); - } - - public JavaType getDeclaringClass() { - return runtime.lookupJavaType(RuntimeCallStub.class); - } - - @Override - public String toString() { - return format("HotSpotStub<%n(%p)>", this); - } - }; - } - - static class GraphBuilder { - - public GraphBuilder(Stub stub) { - this.graph = new StructuredGraph(stub.toString(), null); - graph.replaceFixed(graph.start(), graph.add(new StubStartNode(stub))); - this.lastFixedNode = graph.start(); - } - - final StructuredGraph graph; - private FixedWithNextNode lastFixedNode; - - T add(T node) { - return graph.unique(node); - } - - T append(T node) { - T result = graph.add(node); - assert lastFixedNode != null; - assert result.predecessor() == null; - graph.addAfterFixed(lastFixedNode, result); - if (result instanceof FixedWithNextNode) { - lastFixedNode = (FixedWithNextNode) result; - } else { - lastFixedNode = null; - } - return result; - } - } - - @Override - protected StructuredGraph getGraph() { - Class[] args = linkage.getDescriptor().getArgumentTypes(); - boolean isObjectResult = linkage.getCallingConvention().getReturn().getKind() == Kind.Object; - GraphBuilder builder = new GraphBuilder(this); - LocalNode[] locals = createLocals(builder, args); - - ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(runtime.threadRegister(), true, false)) : null; - ValueNode result = createTargetCall(builder, locals, thread); - createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph)); - if (isObjectResult) { - InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); - result = createInvoke(builder, StubUtil.class, "verifyObject", object); - } - builder.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); - - if (Debug.isDumpEnabled()) { - Debug.dump(builder.graph, "Initial stub graph"); - } - - for (InvokeNode invoke : builder.graph.getNodes(InvokeNode.class).snapshot()) { - inline(invoke); - } - assert builder.graph.getNodes(InvokeNode.class).isEmpty(); - - if (Debug.isDumpEnabled()) { - Debug.dump(builder.graph, "Stub graph before compilation"); - } - - return builder.graph; - } - - private LocalNode[] createLocals(GraphBuilder builder, Class[] args) { - LocalNode[] locals = new LocalNode[args.length]; - ResolvedJavaType accessingClass = runtime.lookupJavaType(getClass()); - for (int i = 0; i < args.length; i++) { - ResolvedJavaType type = runtime.lookupJavaType(args[i]).resolve(accessingClass); - Kind kind = type.getKind().getStackKind(); - Stamp stamp; - if (kind == Kind.Object) { - stamp = StampFactory.declared(type); - } else { - stamp = StampFactory.forKind(kind); - } - LocalNode local = builder.add(new LocalNode(i, stamp)); - locals[i] = local; - } - return locals; - } - - private InvokeNode createInvoke(GraphBuilder builder, Class declaringClass, String name, ValueNode... hpeArgs) { - ResolvedJavaMethod method = null; - for (Method m : declaringClass.getDeclaredMethods()) { - if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) { - assert method == null : "found more than one method in " + declaringClass + " named " + name; - method = runtime.lookupJavaMethod(m); - } - } - assert method != null : "did not find method in " + declaringClass + " named " + name; - JavaType returnType = method.getSignature().getReturnType(null); - MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType)); - InvokeNode invoke = builder.append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI)); - return invoke; - } - - private CRuntimeCall createTargetCall(GraphBuilder builder, LocalNode[] locals, ReadRegisterNode thread) { - if (prependThread) { - ValueNode[] targetArguments = new ValueNode[1 + locals.length]; - targetArguments[0] = thread; - System.arraycopy(locals, 0, targetArguments, 1, locals.length); - return builder.append(new CRuntimeCall(target.getDescriptor(), targetArguments)); - } else { - return builder.append(new CRuntimeCall(target.getDescriptor(), locals)); - } - } - - private void inline(InvokeNode invoke) { - StructuredGraph graph = invoke.graph(); - ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); - ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget()); - StructuredGraph calleeGraph = repl.makeGraph(method, null, null); - InliningUtil.inline(invoke, calleeGraph, false); - new NodeIntrinsificationPhase(runtime).apply(graph); - new WordTypeRewriterPhase(runtime, wordKind()).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - } -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Tue May 21 19:51:00 2013 +0200 @@ -30,7 +30,6 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.Snippet.ConstantParameter; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; @@ -66,7 +65,7 @@ * * @param linkage linkage details for a call to the stub */ - public SnippetStub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + public SnippetStub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(runtime, replacements, linkage); this.snippet = new Template(runtime, replacements, target, getClass()); } @@ -77,9 +76,15 @@ } /** - * Adds the {@linkplain ConstantParameter constant} arguments of this stub. + * Adds the arguments to this snippet stub. */ - protected abstract Arguments makeArguments(SnippetInfo stub); + protected Arguments makeArguments(SnippetInfo stub) { + Arguments args = new Arguments(stub); + for (int i = 0; i < stub.getParameterCount(); i++) { + args.add(stub.getParameterName(i), null); + } + return args; + } @Override protected Object debugScopeContext() { diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Tue May 21 19:51:00 2013 +0200 @@ -56,7 +56,7 @@ /** * The linkage information for a call to this stub from compiled code. */ - protected final HotSpotRuntimeCallTarget linkage; + protected final HotSpotForeignCallLinkage linkage; /** * The code installed for the stub. @@ -100,7 +100,7 @@ * * @param linkage linkage details for a call to the stub */ - public Stub(HotSpotRuntime runtime, Replacements replacements, HotSpotRuntimeCallTarget linkage) { + public Stub(HotSpotRuntime runtime, Replacements replacements, HotSpotForeignCallLinkage linkage) { this.linkage = linkage; this.runtime = runtime; this.replacements = replacements; @@ -109,7 +109,7 @@ /** * Gets the linkage for a call to this stub from compiled code. */ - public HotSpotRuntimeCallTarget getLinkage() { + public HotSpotForeignCallLinkage getLinkage() { return linkage; } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Tue May 21 19:51:00 2013 +0200 @@ -31,10 +31,11 @@ import java.lang.reflect.*; import java.util.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.Fold; import com.oracle.graal.word.*; @@ -46,28 +47,29 @@ */ public class StubUtil { - public static final Descriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC", false); + public static final ForeignCallDescriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC"); /** - * Looks for a {@link CRuntimeCall} node intrinsic named {@code name} in {@code stubClass} and - * returns a {@link Descriptor} based on its signature and the value of {@code hasSideEffect}. + * Looks for a {@link ForeignCallNode} node intrinsic named {@code name} in {@code stubClass} + * and returns a {@link ForeignCallDescriptor} based on its signature and the value of + * {@code hasSideEffect}. */ - public static Descriptor descriptorFor(Class stubClass, String name, boolean hasSideEffect) { + public static ForeignCallDescriptor descriptorFor(Class stubClass, String name) { Method found = null; for (Method method : stubClass.getDeclaredMethods()) { if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) { - if (method.getAnnotation(NodeIntrinsic.class).value() == CRuntimeCall.class) { - assert found == null : "found more than one C runtime call named " + name + " in " + stubClass; - assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == Descriptor.class : "first parameter of C runtime call '" + name + "' in " + stubClass + - " must be of type " + Descriptor.class.getSimpleName(); + if (method.getAnnotation(NodeIntrinsic.class).value() == ForeignCallNode.class) { + assert found == null : "found more than one foreign call named " + name + " in " + stubClass; + assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == ForeignCallDescriptor.class : "first parameter of foreign call '" + name + "' in " + stubClass + + " must be of type " + ForeignCallDescriptor.class.getSimpleName(); found = method; } } } - assert found != null : "could not find C runtime call named " + name + " in " + stubClass; + assert found != null : "could not find foreign call named " + name + " in " + stubClass; List> paramList = Arrays.asList(found.getParameterTypes()); Class[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class[paramList.size() - 1]); - return new Descriptor(name, hasSideEffect, found.getReturnType(), cCallTypes); + return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes); } public static void handlePendingException(boolean isObjectResult) { @@ -79,8 +81,8 @@ } } - @NodeIntrinsic(CRuntimeCall.class) - private static native void vmMessageC(@ConstantNodeParameter Descriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); + @NodeIntrinsic(ForeignCallNode.class) + private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); /** * Prints a message to the log stream. diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ThreadIsInterruptedStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ThreadIsInterruptedStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.hotspot.stubs.StubUtil.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -/** - * Stub called from {@link ThreadIsInterruptedStubCall}. - */ -public class ThreadIsInterruptedStub extends CRuntimeStub { - - public ThreadIsInterruptedStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Snippet - private static boolean threadIsInterrupted(Thread receiverThread, boolean clearIsInterrupted) { - boolean result = threadIsInterruptedC(THREAD_IS_INTERRUPTED_C, thread(), receiverThread, clearIsInterrupted); - handlePendingException(false); - return result; - } - - public static final Descriptor THREAD_IS_INTERRUPTED_C = descriptorFor(ThreadIsInterruptedStub.class, "threadIsInterruptedC", false); - - @NodeIntrinsic(CRuntimeCall.class) - public static native boolean threadIsInterruptedC(@ConstantNodeParameter Descriptor threadIsInterruptedC, Word thread, Thread receiverThread, boolean clearIsInterrupted); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java Tue May 21 19:51:00 2013 +0200 @@ -28,14 +28,14 @@ import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*; import static com.oracle.graal.hotspot.stubs.StubUtil.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.Fold; @@ -45,9 +45,9 @@ * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an * exception and completes by jumping to the exception handler in the calling frame. */ -public class UnwindExceptionToCallerStub extends CRuntimeStub { +public class UnwindExceptionToCallerStub extends SnippetStub { - public UnwindExceptionToCallerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + public UnwindExceptionToCallerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(runtime, replacements, target, linkage); } @@ -97,8 +97,8 @@ return enabled || graalRuntime().getConfig().cAssertions; } - public static final Descriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", false); + public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress"); - @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true) - public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter Descriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress); + @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true) + public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VMErrorStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VMErrorStub.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.stubs; - -import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; -import static com.oracle.graal.hotspot.stubs.StubUtil.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -/** - * Stub called from {@link VMErrorNode}. - */ -public class VMErrorStub extends CRuntimeStub { - - public VMErrorStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage); - } - - @Snippet - private static void vmError(String where, String format, long value) { - vmErrorC(VM_ERROR_C, thread(), where, format, value); - } - - public static final Descriptor VM_ERROR_C = descriptorFor(VMErrorStub.class, "vmErrorC", false); - - @NodeIntrinsic(CRuntimeCall.class) - public static native void vmErrorC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, String where, String format, long value); -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java Tue May 21 19:51:00 2013 +0200 @@ -27,16 +27,15 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; /** - * Stub called from {@link VerifyOopStubCall}. + * Stub called via {@link HotSpotRuntime#VERIFY_OOP}. */ -public class VerifyOopStub extends CRuntimeStub { +public class VerifyOopStub extends SnippetStub { - public VerifyOopStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + public VerifyOopStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(runtime, replacements, target, linkage); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Tue May 21 19:51:00 2013 +0200 @@ -358,6 +358,7 @@ * @param object the object whose monitor will be locked. */ public void pushLock(ValueNode object) { + assert object.isAlive() && object.kind() == Kind.Object : "unexpected value: " + object; locks = Arrays.copyOf(locks, locks.length + 1); locks[locks.length - 1] = object; } @@ -406,7 +407,7 @@ * @param x the instruction which produces the value for the local */ public void storeLocal(int i, ValueNode x) { - assert x == null || x.kind() != Kind.Void && x.kind() != Kind.Illegal : "unexpected value: " + x; + assert x == null || x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal : "unexpected value: " + x; locals[i] = x; if (x != null && isTwoSlot(x.kind())) { // if this is a double word, then kill i+1 @@ -422,7 +423,7 @@ } private void storeStack(int i, ValueNode x) { - assert x == null || stack[i] == null || x.kind() == stack[i].kind() : "Method does not handle changes from one-slot to two-slot values"; + assert x == null || x.isAlive() && (stack[i] == null || x.kind() == stack[i].kind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; stack[i] = x; } @@ -433,7 +434,7 @@ * @param x the instruction to push onto the stack */ public void push(Kind kind, ValueNode x) { - assert !x.isDeleted() && x.kind() != Kind.Void && x.kind() != Kind.Illegal; + assert x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal; xpush(assertKind(kind, x)); if (isTwoSlot(kind)) { xpush(null); @@ -446,7 +447,7 @@ * @param x the instruction to push onto the stack */ public void xpush(ValueNode x) { - assert x == null || (!x.isDeleted() && x.kind() != Kind.Void && x.kind() != Kind.Illegal); + assert x == null || (x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal); stack[stackSize++] = x; } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue May 21 19:51:00 2013 +0200 @@ -33,7 +33,6 @@ import java.util.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.api.meta.ResolvedJavaType.Representation; @@ -59,8 +58,8 @@ public static final class RuntimeCalls { - public static final Descriptor CREATE_NULL_POINTER_EXCEPTION = new Descriptor("createNullPointerException", true, Object.class); - public static final Descriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new Descriptor("createOutOfBoundsException", true, Object.class, int.class); + public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", Object.class); + public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", Object.class, int.class); } /** @@ -305,8 +304,8 @@ * @param type the unresolved type of the constant */ protected void handleUnresolvedLoadConstant(JavaType type) { - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); - frameState.push(Kind.Object, append(ConstantNode.forObject(null, runtime, currentGraph))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + frameState.push(Kind.Object, appendConstant(Constant.NULL_OBJECT)); } /** @@ -314,7 +313,7 @@ * @param object the object value whose type is being checked against {@code type} */ protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile))); + append(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile)); frameState.apush(appendConstant(Constant.NULL_OBJECT)); } @@ -325,8 +324,7 @@ protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode()); DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1)); - append(ifNode); + append(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1)); lastInstr = successor; frameState.ipush(appendConstant(Constant.INT_0)); } @@ -335,7 +333,7 @@ * @param type the type being instantiated */ protected void handleUnresolvedNewInstance(JavaType type) { - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); frameState.apush(appendConstant(Constant.NULL_OBJECT)); } @@ -344,7 +342,7 @@ * @param length the length of the array */ protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); frameState.apush(appendConstant(Constant.NULL_OBJECT)); } @@ -353,7 +351,7 @@ * @param dims the dimensions for the multi-array */ protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); frameState.apush(appendConstant(Constant.NULL_OBJECT)); } @@ -363,8 +361,8 @@ */ protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { Kind kind = field.getKind(); - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); - frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + frameState.push(kind.getStackKind(), appendConstant(Constant.defaultForKind(kind))); } /** @@ -373,7 +371,7 @@ * @param receiver the object containing the field or {@code null} if {@code field} is static */ protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); } /** @@ -381,16 +379,16 @@ * @param type */ protected void handleUnresolvedExceptionType(Representation representation, JavaType type) { - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); } protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { boolean withReceiver = invokeKind != InvokeKind.Static; - append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); frameState.popArguments(javaMethod.getSignature().getParameterSlots(withReceiver), javaMethod.getSignature().getParameterCount(withReceiver)); Kind kind = javaMethod.getSignature().getReturnKind(); if (kind != Kind.Void) { - frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); + frameState.push(kind.getStackKind(), appendConstant(Constant.defaultForKind(kind))); } } @@ -433,7 +431,7 @@ // this is a load of class constant which might be unresolved JavaType type = (JavaType) con; if (type instanceof ResolvedJavaType) { - frameState.push(Kind.Object, append(ConstantNode.forConstant(((ResolvedJavaType) type).getEncoding(Representation.JavaClass), runtime, currentGraph))); + frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getEncoding(Representation.JavaClass))); } else { handleUnresolvedLoadConstant(type); } @@ -450,8 +448,7 @@ ValueNode index = frameState.ipop(); ValueNode array = frameState.apop(); - ValueNode v = append(currentGraph.add(new LoadIndexedNode(array, index, kind))); - frameState.push(kind.getStackKind(), v); + frameState.push(kind.getStackKind(), append(new LoadIndexedNode(array, index, kind))); } private void genStoreIndexed(Kind kind) { @@ -460,8 +457,7 @@ ValueNode value = frameState.pop(kind.getStackKind()); ValueNode index = frameState.ipop(); ValueNode array = frameState.apop(); - StoreIndexedNode result = currentGraph.add(new StoreIndexedNode(array, index, kind, value)); - append(result); + append(new StoreIndexedNode(array, index, kind, value)); } private void stackOp(int opcode) { @@ -586,8 +582,7 @@ default: throw new GraalInternalError("should not reach"); } - ValueNode result1 = append(currentGraph.unique(v)); - frameState.push(result, result1); + frameState.push(result, append(v)); } private void genIntegerDivOp(Kind result, int opcode) { @@ -606,12 +601,11 @@ default: throw new GraalInternalError("should not reach"); } - ValueNode result1 = append(currentGraph.add(v)); - frameState.push(result, result1); + frameState.push(result, append(v)); } private void genNegateOp(Kind kind) { - frameState.push(kind, append(currentGraph.unique(new NegateNode(frameState.pop(kind))))); + frameState.push(kind, append(new NegateNode(frameState.pop(kind)))); } private void genShiftOp(Kind kind, int opcode) { @@ -634,7 +628,7 @@ default: throw new GraalInternalError("should not reach"); } - frameState.push(kind, append(currentGraph.unique(v))); + frameState.push(kind, append(v)); } private void genLogicOp(Kind kind, int opcode) { @@ -657,26 +651,26 @@ default: throw new GraalInternalError("should not reach"); } - frameState.push(kind, append(currentGraph.unique(v))); + frameState.push(kind, append(v)); } private void genCompareOp(Kind kind, boolean isUnorderedLess) { ValueNode y = frameState.pop(kind); ValueNode x = frameState.pop(kind); - frameState.ipush(append(currentGraph.unique(new NormalizeCompareNode(x, y, isUnorderedLess)))); + frameState.ipush(append(new NormalizeCompareNode(x, y, isUnorderedLess))); } private void genConvert(ConvertNode.Op opcode) { ValueNode input = frameState.pop(opcode.from.getStackKind()); - frameState.push(opcode.to.getStackKind(), append(currentGraph.unique(new ConvertNode(opcode, input)))); + frameState.push(opcode.to.getStackKind(), append(new ConvertNode(opcode, input))); } private void genIncrement() { int index = stream().readLocalIndex(); int delta = stream().readIncrement(); ValueNode x = frameState.loadLocal(index); - ValueNode y = append(ConstantNode.forInt(delta, currentGraph)); - frameState.storeLocal(index, append(currentGraph.unique(new IntegerAddNode(Kind.Int, x, y)))); + ValueNode y = appendConstant(Constant.forInt(delta)); + frameState.storeLocal(index, append(new IntegerAddNode(Kind.Int, x, y))); } private void genGoto() { @@ -726,7 +720,7 @@ AbstractBeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState); IfNode ifNode = negate ? new IfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : new IfNode(condition, trueSuccessor, falseSuccessor, probability); - append(currentGraph.add(ifNode)); + append(ifNode); } private void genIfZero(Condition cond) { @@ -750,9 +744,8 @@ private void genThrow() { ValueNode exception = frameState.apop(); - FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); - append(node); - append(handleException(exception, bci())); + append(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); + lastInstr.setNext(handleException(exception, bci())); } private JavaType lookupType(int cpi, int bytecode) { @@ -804,9 +797,8 @@ ValueNode object = frameState.apop(); if (type instanceof ResolvedJavaType) { JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type); - CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck, false)); - append(checkCast); - frameState.apush(checkCast); + CheckCastNode checkCastNode = append(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck, false)); + frameState.apush(checkCastNode); } else { handleUnresolvedCheckCast(type, object); } @@ -819,8 +811,7 @@ if (type instanceof ResolvedJavaType) { ResolvedJavaType resolvedType = (ResolvedJavaType) type; InstanceOfNode instanceOfNode = new InstanceOfNode((ResolvedJavaType) type, object, getProfileForTypeCheck(resolvedType)); - ConditionalNode conditional = currentGraph.unique(new ConditionalNode(currentGraph.unique(instanceOfNode), ConstantNode.forInt(1, currentGraph), ConstantNode.forInt(0, currentGraph))); - frameState.ipush(append(conditional)); + frameState.ipush(append(new ConditionalNode(currentGraph.unique(instanceOfNode), ConstantNode.forInt(1, currentGraph), ConstantNode.forInt(0, currentGraph)))); } else { handleUnresolvedInstanceOf(type, object); } @@ -829,8 +820,7 @@ void genNewInstance(int cpi) { JavaType type = lookupType(cpi, NEW); if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) { - NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true)); - frameState.apush(append(n)); + frameState.apush(append(new NewInstanceNode((ResolvedJavaType) type, true))); } else { handleUnresolvedNewInstance(type); } @@ -871,16 +861,14 @@ private void genNewPrimitiveArray(int typeCode) { Class clazz = arrayTypeCodeToClass(typeCode); ResolvedJavaType elementType = runtime.lookupJavaType(clazz); - NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true)); - frameState.apush(append(nta)); + frameState.apush(append(new NewArrayNode(elementType, frameState.ipop(), true))); } private void genNewObjectArray(int cpi) { JavaType type = lookupType(cpi, ANEWARRAY); ValueNode length = frameState.ipop(); if (type instanceof ResolvedJavaType) { - NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true)); - frameState.apush(append(n)); + frameState.apush(append(new NewArrayNode((ResolvedJavaType) type, length, true))); } else { handleUnresolvedNewObjectArray(type, length); } @@ -895,8 +883,7 @@ dims[i] = frameState.ipop(); } if (type instanceof ResolvedJavaType) { - FixedWithNextNode n = currentGraph.add(new NewMultiArrayNode((ResolvedJavaType) type, dims)); - frameState.apush(append(n)); + frameState.apush(append(new NewMultiArrayNode((ResolvedJavaType) type, dims))); } else { handleUnresolvedNewMultiArray(type, dims); } @@ -908,8 +895,7 @@ Kind kind = field.getKind(); ValueNode receiver = frameState.apop(); if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - LoadFieldNode load = currentGraph.add(new LoadFieldNode(receiver, (ResolvedJavaField) field)); - appendOptimizedLoadField(kind, load); + appendOptimizedLoadField(kind, new LoadFieldNode(receiver, (ResolvedJavaField) field)); } else { handleUnresolvedLoadField(field, receiver); } @@ -932,16 +918,14 @@ } BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 0.1)); - - append(ifNode); + append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 0.1)); lastInstr = falseSucc; if (GraalOptions.OmitHotExceptionStacktrace) { ValueNode exception = ConstantNode.forObject(cachedNullPointerException, runtime, currentGraph); trueSucc.setNext(handleException(exception, bci())); } else { - RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CREATE_NULL_POINTER_EXCEPTION)); + ForeignCallStateSplitNode call = currentGraph.add(new ForeignCallStateSplitNode(runtime, CREATE_NULL_POINTER_EXCEPTION)); call.setStateAfter(frameState.create(bci())); trueSucc.setNext(call); call.setNext(handleException(call, bci())); @@ -958,16 +942,14 @@ private void emitBoundsCheck(ValueNode index, ValueNode length) { BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.9)); - - append(ifNode); + append(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.9)); lastInstr = trueSucc; if (GraalOptions.OmitHotExceptionStacktrace) { ValueNode exception = ConstantNode.forObject(cachedArrayIndexOutOfBoundsException, runtime, currentGraph); falseSucc.setNext(handleException(exception, bci())); } else { - RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CREATE_OUT_OF_BOUNDS_EXCEPTION, index)); + ForeignCallStateSplitNode call = currentGraph.add(new ForeignCallStateSplitNode(runtime, CREATE_OUT_OF_BOUNDS_EXCEPTION, index)); call.setStateAfter(frameState.create(bci())); falseSucc.setNext(call); call.setNext(handleException(call, bci())); @@ -982,7 +964,7 @@ emitNullCheck(receiver); if (outOfBoundsIndex != null) { - ValueNode length = append(currentGraph.add(new ArrayLengthNode(receiver))); + ValueNode length = append(new ArrayLengthNode(receiver)); emitBoundsCheck(outOfBoundsIndex, length); } Debug.metric("ExplicitExceptions").increment(); @@ -994,8 +976,7 @@ ValueNode value = frameState.pop(field.getKind().getStackKind()); ValueNode receiver = frameState.apop(); if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - StoreFieldNode store = currentGraph.add(new StoreFieldNode(receiver, (ResolvedJavaField) field, value)); - appendOptimizedStoreField(store); + appendOptimizedStoreField(new StoreFieldNode(receiver, (ResolvedJavaField) field, value)); } else { handleUnresolvedStoreField(field, value, receiver); } @@ -1004,8 +985,7 @@ private void genGetStatic(JavaField field) { Kind kind = field.getKind(); if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - LoadFieldNode load = currentGraph.add(new LoadFieldNode(null, (ResolvedJavaField) field)); - appendOptimizedLoadField(kind, load); + appendOptimizedLoadField(kind, new LoadFieldNode(null, (ResolvedJavaField) field)); } else { handleUnresolvedLoadField(field, null); } @@ -1014,8 +994,7 @@ private void genPutStatic(JavaField field) { ValueNode value = frameState.pop(field.getKind().getStackKind()); if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - StoreFieldNode store = currentGraph.add(new StoreFieldNode(null, (ResolvedJavaField) field, value)); - appendOptimizedStoreField(store); + appendOptimizedStoreField(new StoreFieldNode(null, (ResolvedJavaField) field, value)); } else { handleUnresolvedStoreField(field, value, null); } @@ -1142,8 +1121,7 @@ private void appendInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { Kind resultType = targetMethod.getSignature().getReturnKind(); if (GraalOptions.DeoptALot) { - DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint)); - append(deoptimize); + append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint)); frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, currentGraph)); return; } @@ -1164,15 +1142,12 @@ // be conservative if information was not recorded (could result in endless recompiles // otherwise) if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) { - InvokeNode invoke = new InvokeNode(callTarget, bci()); - ValueNode result = appendWithBCI(currentGraph.add(invoke)); - frameState.pushReturn(resultType, result); - return invoke; + frameState.pushReturn(resultType, append(new InvokeNode(callTarget, bci()))); + return new InvokeNode(callTarget, bci()); } else { DispatchBeginNode exceptionEdge = handleException(null, bci()); - InvokeWithExceptionNode invoke = currentGraph.add(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); - ValueNode result = append(invoke); - frameState.pushReturn(resultType, result); + InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); + frameState.pushReturn(resultType, invoke); Block nextBlock = currentBlock.successors.get(0); assert bci() == currentBlock.endBci; @@ -1193,19 +1168,17 @@ } private MonitorEnterNode genMonitorEnter(ValueNode x) { - MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x, frameState.lockDepth())); + MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, frameState.lockDepth())); frameState.pushLock(x); - appendWithBCI(monitorEnter); return monitorEnter; } private MonitorExitNode genMonitorExit(ValueNode x) { ValueNode lockedObject = frameState.popLock(); - MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x, frameState.lockDepth())); if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) { throw new BailoutException("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)); } - appendWithBCI(monitorExit); + MonitorExitNode monitorExit = append(new MonitorExitNode(x, frameState.lockDepth())); return monitorExit; } @@ -1228,7 +1201,7 @@ ValueNode local = frameState.loadLocal(localIndex); JsrScope scope = currentBlock.jsrScope; int retAddress = scope.nextReturnAddress(); - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forInt(retAddress, currentGraph))), JavaSubroutineMismatch, InvalidateReprofile))); + append(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forInt(retAddress, currentGraph))), JavaSubroutineMismatch, InvalidateReprofile)); if (!successor.jsrScope.equals(scope.pop())) { throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)"); } @@ -1315,12 +1288,11 @@ } double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities); - IntegerSwitchNode switchNode = currentGraph.add(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors)); + IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors)); for (int i = 0; i < actualSuccessors.size(); i++) { switchNode.setBlockSuccessor(i, createBlockTarget(successorProbabilities[i], actualSuccessors.get(i), frameState)); } - append(switchNode); } private static class SuccessorInfo { @@ -1339,26 +1311,37 @@ return ConstantNode.forConstant(constant, runtime, currentGraph); } - private ValueNode append(FixedNode fixed) { - lastInstr.setNext(fixed); + private T append(T fixed) { + assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; + assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; + T added = currentGraph.add(fixed); + lastInstr.setNext(added); lastInstr = null; - return fixed; - } - - protected ValueNode append(FixedWithNextNode x) { - return appendWithBCI(x); + return added; } - private static ValueNode append(ValueNode v) { - return v; + private T append(T fixed) { + assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; + assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; + T added = currentGraph.add(fixed); + lastInstr.setNext(added); + lastInstr = null; + return added; } - protected ValueNode appendWithBCI(FixedWithNextNode x) { - assert x.predecessor() == null : "instruction should not have been appended yet"; + protected T append(T fixed) { + assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - lastInstr.setNext(x); - lastInstr = x; - return x; + T added = currentGraph.add(fixed); + lastInstr.setNext(added); + lastInstr = added; + return added; + } + + private T append(T v) { + assert !(v instanceof ConstantNode); + T added = currentGraph.unique(v); + return added; } private static class Target { @@ -1525,7 +1508,7 @@ private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) { if (isStatic(target.getModifiers())) { - return append(ConstantNode.forConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass), runtime, currentGraph)); + return appendConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass)); } else { return state.loadLocal(0); } @@ -1590,11 +1573,9 @@ private void createUnwind() { assert frameState.stackSize() == 1 : frameState; ValueNode exception = frameState.apop(); - FixedGuardNode guard = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); - append(guard); + append(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); synchronizedEpilogue(FrameState.AFTER_EXCEPTION_BCI); - UnwindNode unwindNode = currentGraph.add(new UnwindNode(exception)); - append(unwindNode); + append(new UnwindNode(exception)); } private void createReturn() { @@ -1603,7 +1584,7 @@ assert frameState.stackSize() == 0; if (Modifier.isSynchronized(method.getModifiers())) { - append(currentGraph.add(new ValueAnchorNode(true, x))); + append(new ValueAnchorNode(true, x)); assert !frameState.rethrowException(); } @@ -1611,15 +1592,13 @@ if (frameState.lockDepth() != 0) { throw new BailoutException("unbalanced monitors"); } - ReturnNode returnNode = currentGraph.add(new ReturnNode(x)); if (graphBuilderConfig.eagerInfopointMode()) { - InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_END)); + InfopointNode ipn = append(new InfopointNode(InfopointReason.METHOD_END)); ipn.setStateAfter(frameState.create(FrameState.AFTER_BCI)); - append(ipn); } - append(returnNode); + append(new ReturnNode(x)); } private void synchronizedEpilogue(int bci) { @@ -1665,8 +1644,7 @@ frameState.push(Kind.Object, exception); FixedNode nextDispatch = createTarget(nextBlock, frameState); checkCast.setNext(catchSuccessor); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), checkCast, nextDispatch, 0.5)); - append(ifNode); + append(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), checkCast, nextDispatch, 0.5)); } } @@ -1732,9 +1710,8 @@ if (graphBuilderConfig.eagerInfopointMode() && lnt != null) { currentLineNumber = lnt.getLineNumber(bci); if (currentLineNumber != previousLineNumber) { - InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.LINE_NUMBER)); + InfopointNode ipn = append(new InfopointNode(InfopointReason.LINE_NUMBER)); ipn.setStateAfter(frameState.create(bci)); - append(ipn); previousLineNumber = currentLineNumber; } } @@ -1747,8 +1724,7 @@ if (block.jsrScope != JsrScope.EMPTY_SCOPE) { throw new BailoutException("OSR into a JSR scope is not supported"); } - EntryMarkerNode x = currentGraph.add(new EntryMarkerNode()); - append(x); + EntryMarkerNode x = append(new EntryMarkerNode()); frameState.insertProxies(x); x.setStateAfter(frameState.create(bci)); } @@ -2037,6 +2013,6 @@ } private void genArrayLength() { - frameState.ipush(append(currentGraph.add(new ArrayLengthNode(frameState.apop())))); + frameState.ipush(append(new ArrayLengthNode(frameState.apop()))); } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Tue May 21 19:51:00 2013 +0200 @@ -102,11 +102,11 @@ } } - public abstract static class RuntimeCallOp extends CallOp { + public abstract static class ForeignCallOp extends CallOp { - protected final RuntimeCallTarget callTarget; + protected final ForeignCallLinkage callTarget; - public RuntimeCallOp(RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + public ForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { super(result, parameters, temps, state); this.callTarget = callTarget; } @@ -117,11 +117,11 @@ } } - @Opcode("CALL_NEAR_RUNTIME") - public static class DirectNearRuntimeCallOp extends RuntimeCallOp { + @Opcode("NEAR_FOREIGN_CALL") + public static class DirectNearForeignCallOp extends ForeignCallOp { - public DirectNearRuntimeCallOp(RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - super(callTarget, result, parameters, temps, state); + public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(linkage, result, parameters, temps, state); } @Override @@ -130,12 +130,12 @@ } } - @Opcode("CALL_FAR_RUNTIME") - public static class DirectFarRuntimeCallOp extends RuntimeCallOp { + @Opcode("FAR_FOREIGN_CALL") + public static class DirectFarForeignCallOp extends ForeignCallOp { @Temp({REG}) protected AllocatableValue callTemp; - public DirectFarRuntimeCallOp(LIRGeneratorTool gen, RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + public DirectFarForeignCallOp(LIRGeneratorTool gen, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { super(callTarget, result, parameters, temps, state); callTemp = gen.newVariable(Kind.Long); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Tue May 21 19:51:00 2013 +0200 @@ -31,7 +31,9 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.LIRInstruction.ValueProcedure; import com.oracle.graal.nodes.cfg.*; public final class LIRVerifier { @@ -230,14 +232,17 @@ return value; } + // @formatter:off private static Value allowed(Object op, Value value, OperandMode mode, EnumSet flags) { - if ((isVariable(value) && flags.contains(OperandFlag.REG)) || (isRegister(value) && flags.contains(OperandFlag.REG)) || (isStackSlot(value) && flags.contains(OperandFlag.STACK)) || - (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) { + if ((isVariable(value) && flags.contains(OperandFlag.REG)) || + (isRegister(value) && flags.contains(OperandFlag.REG)) || + (isStackSlot(value) && flags.contains(OperandFlag.STACK)) || + (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || + (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) { return value; } - TTY.println("instruction %s", op); - TTY.println("mode: %s flags: %s", mode, flags); - TTY.println("Unexpected value: %s %s", value.getClass().getSimpleName(), value); - throw GraalInternalError.shouldNotReachHere(); + throw new GraalInternalError("Invalid LIR%n Instruction: %s%n Mode: %s%n Flags: %s%n Unexpected value: %s %s", + op, mode, flags, value.getClass().getSimpleName(), value); } + // @formatter:on } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java Tue May 21 19:51:00 2013 +0200 @@ -52,7 +52,7 @@ blocks: while (b != loop.lirLoop().header) { assert b != null; for (FixedNode node : b.getNodes()) { - if (node instanceof Invoke || node instanceof RuntimeCallNode) { + if (node instanceof Invoke || node instanceof ForeignCallNode) { loopEnd.disableSafepoint(); break blocks; } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Tue May 21 19:51:00 2013 +0200 @@ -218,7 +218,7 @@ } /** - * Unlinks a node from all its control flow neighbours and then removes it from its graph. The + * Unlinks a node from all its control flow neighbors and then removes it from its graph. The * node must have no {@linkplain Node#usages() usages}. * * @param node the node to be unlinked and removed diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Node for a {@linkplain ForeignCallDescriptor foreign} call. + */ +@NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}") +public class ForeignCallNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint { + + @Input private final NodeInputList arguments; + + private final ForeignCallDescriptor descriptor; + + public ForeignCallNode(ForeignCallDescriptor descriptor, ValueNode... arguments) { + super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); + this.arguments = new NodeInputList<>(this, arguments); + this.descriptor = descriptor; + } + + protected ForeignCallNode(ForeignCallDescriptor descriptor, Stamp stamp) { + super(stamp); + this.arguments = new NodeInputList<>(this); + this.descriptor = descriptor; + } + + public ForeignCallDescriptor getDescriptor() { + return descriptor; + } + + @Override + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; + } + + protected Value[] operands(LIRGeneratorTool gen) { + Value[] operands = new Value[arguments.size()]; + for (int i = 0; i < operands.length; i++) { + operands[i] = gen.operand(arguments.get(i)); + } + return operands; + } + + @Override + public void generate(LIRGeneratorTool gen) { + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(descriptor); + Value[] operands = operands(gen); + Value result = gen.emitForeignCall(linkage, this, operands); + if (result != null) { + gen.setResult(this, result); + } + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(verbosity) + "#" + descriptor; + } + return super.toString(verbosity); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } +} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallStateSplitNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallStateSplitNode.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * A foreign call that is also a state split. + */ +@NodeInfo(nameTemplate = "ForeignCallStateSplit#{p#descriptor/s}") +public class ForeignCallStateSplitNode extends ForeignCallNode implements LIRLowerable, StateSplit, DeoptimizingNode { + + @Input(notDataflow = true) private FrameState stateAfter; + private MetaAccessProvider runtime; + + public ForeignCallStateSplitNode(MetaAccessProvider runtime, ForeignCallDescriptor descriptor, ValueNode... arguments) { + super(descriptor, arguments); + this.runtime = runtime; + } + + public FrameState stateAfter() { + return stateAfter; + } + + public void setStateAfter(FrameState x) { + assert x == null || x.isAlive() : "frame state must be in a graph"; + updateUsages(stateAfter, x); + stateAfter = x; + } + + public boolean hasSideEffect() { + return runtime.hasSideEffect(getDescriptor()); + } + + @Override + public FrameState getDeoptimizationState() { + if (super.getDeoptimizationState() != null) { + return super.getDeoptimizationState(); + } else if (stateAfter() != null) { + FrameState stateDuring = stateAfter(); + if ((stateDuring.stackSize() > 0 && stateDuring.stackAt(stateDuring.stackSize() - 1) == this) || (stateDuring.stackSize() > 1 && stateDuring.stackAt(stateDuring.stackSize() - 2) == this)) { + stateDuring = stateDuring.duplicateModified(stateDuring.bci, stateDuring.rethrowException(), this.kind()); + } + setDeoptimizationState(stateDuring); + return stateDuring; + } + return null; + } + + @Override + public void setDeoptimizationState(FrameState f) { + if (super.getDeoptimizationState() != null) { + throw new IllegalStateException(); + } + super.setDeoptimizationState(f); + } +} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Tue May 21 19:43:53 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -@NodeInfo(nameTemplate = "RuntimeCall#{p#descriptor/s}") -public final class RuntimeCallNode extends AbstractCallNode implements LIRLowerable, DeoptimizingNode { - - private final Descriptor descriptor; - @Input private FrameState deoptState; - - public RuntimeCallNode(Descriptor descriptor, ValueNode... arguments) { - super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())), arguments); - this.descriptor = descriptor; - } - - public Descriptor getDescriptor() { - return descriptor; - } - - @Override - public boolean hasSideEffect() { - return descriptor.hasSideEffect(); - } - - @Override - public LocationIdentity[] getLocationIdentities() { - return new LocationIdentity[]{LocationNode.ANY_LOCATION}; - } - - @Override - public void generate(LIRGeneratorTool gen) { - gen.visitRuntimeCall(this); - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(verbosity) + "#" + descriptor; - } - return super.toString(verbosity); - } - - @Override - public boolean canDeoptimize() { - return true; - } - - @Override - public FrameState getDeoptimizationState() { - if (deoptState != null) { - return deoptState; - } else if (stateAfter() != null) { - FrameState stateDuring = stateAfter(); - if ((stateDuring.stackSize() > 0 && stateDuring.stackAt(stateDuring.stackSize() - 1) == this) || (stateDuring.stackSize() > 1 && stateDuring.stackAt(stateDuring.stackSize() - 2) == this)) { - stateDuring = stateDuring.duplicateModified(stateDuring.bci, stateDuring.rethrowException(), this.kind()); - } - updateUsages(deoptState, stateDuring); - return deoptState = stateDuring; - } - return null; - } - - @Override - public void setDeoptimizationState(FrameState f) { - if (deoptState != null) { - throw new IllegalStateException(); - } - updateUsages(deoptState, f); - deoptState = f; - } - - @Override - public DeoptimizationReason getDeoptimizationReason() { - return null; - } - - @Override - public boolean isCallSiteDeoptimization() { - return stateAfter() != null; - } -} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Tue May 21 19:51:00 2013 +0200 @@ -33,7 +33,7 @@ * The {@code LoadFieldNode} represents a read of a static or instance field. */ @NodeInfo(nameTemplate = "LoadField#{p#field/s}") -public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, Node.IterableNodeType, Virtualizable { +public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, Node.IterableNodeType, VirtualizableRoot { /** * Creates a new LoadFieldNode instance. @@ -79,6 +79,13 @@ if (fieldIndex != -1) { tool.replaceWith(state.getEntry(fieldIndex)); } + } else { + ValueNode cachedValue = tool.getReadCache(object(), field()); + if (cachedValue != null) { + tool.replaceWithValue(cachedValue); + } else { + tool.addReadCache(object(), field(), this); + } } } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Tue May 21 19:51:00 2013 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.nodes.java; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -35,7 +34,7 @@ */ public final class RegisterFinalizerNode extends AbstractStateSplit implements StateSplit, Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode { - public static final Descriptor REGISTER_FINALIZER = new Descriptor("registerFinalizer", true, void.class, Object.class); + public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class); @Input private FrameState deoptState; @Input private ValueNode object; @@ -51,8 +50,8 @@ @Override public void generate(LIRGeneratorTool gen) { - RuntimeCallTarget call = gen.getRuntime().lookupRuntimeCall(REGISTER_FINALIZER); - gen.emitCall(call, call.getCallingConvention(), this, gen.operand(object())); + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(REGISTER_FINALIZER); + gen.emitForeignCall(linkage, this, gen.operand(object())); } @Override diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Tue May 21 19:51:00 2013 +0200 @@ -33,7 +33,7 @@ * The {@code StoreFieldNode} represents a write to a static or instance field. */ @NodeInfo(nameTemplate = "StoreField#{p#field/s}") -public final class StoreFieldNode extends AccessFieldNode implements StateSplit, Virtualizable { +public final class StoreFieldNode extends AccessFieldNode implements StateSplit, VirtualizableRoot { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -77,6 +77,12 @@ tool.setVirtualEntry(state, fieldIndex, value()); tool.delete(); } + } else { + if (value() == tool.getReadCache(object(), field())) { + tool.delete(); + } + tool.killReadCache(field()); + tool.addReadCache(object(), field(), value()); } } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Tue May 21 19:51:00 2013 +0200 @@ -101,7 +101,7 @@ void emitNullCheck(ValueNode v, DeoptimizingNode deopting); - Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args); + Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args); void emitIf(IfNode i); @@ -111,8 +111,6 @@ void emitInvoke(Invoke i); - void visitRuntimeCall(RuntimeCallNode i); - // Handling of block-end nodes still needs to be unified in the LIRGenerator. void visitMerge(MergeNode i); diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java Tue May 21 19:51:00 2013 +0200 @@ -26,12 +26,9 @@ * This interface allows a node to convey information about what its effect would be if some of its * inputs were virtualized. * - * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method - * will be called regardless of whether this node had any interaction with virtualized nodes. This - * interface can therefore be used for object allocations, for which virtualization introduces new - * virtualized objects. - * + * The difference to {@link VirtualizableRoot} is that removing {@link VirtualizableAllocation} + * nodes is not considered progress during the escape analysis iterations. */ -public interface VirtualizableAllocation extends Virtualizable { +public interface VirtualizableAllocation extends VirtualizableRoot { } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java Tue May 21 19:51:00 2013 +0200 @@ -0,0 +1,37 @@ +/* + * 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.nodes.spi; + +/** + * This interface allows a node to convey information about what its effect would be if some of its + * inputs were virtualized. + * + * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method + * will be called regardless of whether this node had any interaction with virtualized nodes. This + * interface can therefore be used for object allocations, for which virtualization introduces new + * virtualized objects. + * + */ +public interface VirtualizableRoot extends Virtualizable { + +} diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Tue May 21 19:51:00 2013 +0200 @@ -152,4 +152,11 @@ * @param value the replacement value */ void replaceWith(ValueNode value); + + void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value); + + ValueNode getReadCache(ValueNode object, ResolvedJavaField identity); + + void killReadCache(ResolvedJavaField identity); + } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Tue May 21 19:51:00 2013 +0200 @@ -34,7 +34,7 @@ public class FrameStateAssignmentPhase extends Phase { - private static class FrameStateAssignementClosure extends NodeIteratorClosure { + private static class FrameStateAssignmentClosure extends NodeIteratorClosure { @Override protected FrameState processNode(FixedNode node, FrameState currentState) { @@ -79,7 +79,7 @@ @Override protected void run(StructuredGraph graph) { assert checkFixedDeopts(graph); - ReentrantNodeIterator.apply(new FrameStateAssignementClosure(), graph.start(), null, null); + ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null); } private static boolean checkFixedDeopts(StructuredGraph graph) { diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Tue May 21 19:51:00 2013 +0200 @@ -99,27 +99,34 @@ @Override protected void run(final StructuredGraph graph) { - InliningData data = new InliningData(); - data.pushGraph(graph, 1.0, 1.0); + InliningData data = new InliningData(graph, compilationAssumptions); while (data.hasUnprocessedGraphs()) { + MethodInvocation currentInvocation = data.currentInvocation(); GraphInfo graphInfo = data.currentGraph(); - if (graphInfo.hasRemainingInvokes() && inliningPolicy.continueInlining(data)) { + if (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(currentInvocation.callee(), data.inliningDepth(), currentInvocation.probability(), currentInvocation.relevance(), false)) { + int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs(); + assert remainingGraphs > 0; + data.popGraphs(remainingGraphs); + data.popInvocation(); + } else if (graphInfo.hasRemainingInvokes() && inliningPolicy.continueInlining(graphInfo.graph())) { processNextInvoke(data, graphInfo); } else { data.popGraph(); - MethodInvocation currentInvocation = data.currentInvocation(); - if (currentInvocation != null) { + if (!currentInvocation.isRoot()) { assert currentInvocation.callee().invoke().asNode().isAlive(); currentInvocation.incrementProcessedGraphs(); - if (currentInvocation.processedAllGraphs()) { + if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) { data.popInvocation(); MethodInvocation parentInvoke = data.currentInvocation(); - tryToInline(data.currentGraph(), currentInvocation, parentInvoke); + tryToInline(data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1); } } } } + + assert data.inliningDepth() == 0; + assert data.graphCount() == 0; } /** @@ -128,32 +135,35 @@ private void processNextInvoke(InliningData data, GraphInfo graphInfo) { Invoke invoke = graphInfo.popInvoke(); MethodInvocation callerInvocation = data.currentInvocation(); - Assumptions parentAssumptions = callerInvocation == null ? compilationAssumptions : callerInvocation.assumptions(); + Assumptions parentAssumptions = callerInvocation.assumptions(); InlineInfo info = InliningUtil.getInlineInfo(data, invoke, maxMethodPerInlining, replacements, parentAssumptions, optimisticOpts); - double invokeProbability = graphInfo.invokeProbability(invoke); - double invokeRelevance = graphInfo.invokeRelevance(invoke); - if (info != null && inliningPolicy.isWorthInlining(info, invokeProbability, invokeRelevance, false)) { - MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance); + if (info != null) { + double invokeProbability = graphInfo.invokeProbability(invoke); + double invokeRelevance = graphInfo.invokeRelevance(invoke); + + if (inliningPolicy.isWorthInlining(info, data.inliningDepth(), invokeProbability, invokeRelevance, false)) { + MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance); - for (int i = 0; i < info.numberOfMethods(); i++) { - InlineableElement elem = getInlineableElement(info.methodAt(i), info.invoke(), calleeInvocation.assumptions()); - info.setInlinableElement(i, elem); - if (elem instanceof StructuredGraph) { - data.pushGraph((StructuredGraph) elem, invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i)); - } else { - assert elem instanceof InlineableMacroNode; - data.pushDummyGraph(); + for (int i = 0; i < info.numberOfMethods(); i++) { + InlineableElement elem = getInlineableElement(info.methodAt(i), info.invoke(), calleeInvocation.assumptions()); + info.setInlinableElement(i, elem); + if (elem instanceof StructuredGraph) { + data.pushGraph((StructuredGraph) elem, invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i)); + } else { + assert elem instanceof InlineableMacroNode; + data.pushDummyGraph(); + } } } } } - private void tryToInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, MethodInvocation parentInvocation) { + private void tryToInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth) { InlineInfo callee = calleeInfo.callee(); - Assumptions callerAssumptions = parentInvocation == null ? compilationAssumptions : parentInvocation.assumptions(); + Assumptions callerAssumptions = parentInvocation.assumptions(); - if (inliningPolicy.isWorthInlining(callee, calleeInfo.probability(), calleeInfo.relevance(), true)) { + if (inliningPolicy.isWorthInlining(callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) { doInline(callerGraphInfo, calleeInfo, callerAssumptions); } else if (optimisticOpts.devirtualizeInvokes()) { callee.tryToDevirtualizeInvoke(runtime, callerAssumptions); @@ -399,32 +409,26 @@ super(replacements, hints); } - public boolean continueInlining(InliningData data) { - if (data.currentGraph().graph().getNodeCount() >= GraalOptions.MaximumDesiredSize) { + public boolean continueInlining(StructuredGraph currentGraph) { + if (currentGraph.getNodeCount() >= GraalOptions.MaximumDesiredSize) { InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize"); metricInliningStoppedByMaxDesiredSize.increment(); return false; } - - MethodInvocation currentInvocation = data.currentInvocation(); - if (currentInvocation == null) { - return true; - } - - return isWorthInlining(currentInvocation.callee(), currentInvocation.probability(), currentInvocation.relevance(), false); + return true; } @Override - public boolean isWorthInlining(InlineInfo info, double probability, double relevance, boolean fullyProcessed) { + public boolean isWorthInlining(InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed) { if (isIntrinsic(info)) { - return InliningUtil.logInlinedMethod(info, fullyProcessed, "intrinsic"); + return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); } double inliningBonus = getInliningBonus(info); int lowLevelGraphSize = previousLowLevelGraphSize(info); if (GraalOptions.SmallCompiledLowLevelGraphSize > 0 && lowLevelGraphSize > GraalOptions.SmallCompiledLowLevelGraphSize * inliningBonus) { - return InliningUtil.logNotInlinedMethod(info, "too large previous low-level graph: %d", lowLevelGraphSize); + return InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph: %d", lowLevelGraphSize); } /* @@ -436,20 +440,20 @@ int nodes = determineNodeCount(info); if (nodes < GraalOptions.TrivialInliningSize * inliningBonus) { - return InliningUtil.logInlinedMethod(info, fullyProcessed, "trivial (nodes=%d)", nodes); + return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (nodes=%d)", nodes); } double invokes = determineInvokeProbability(info); if (GraalOptions.LimitInlinedInvokes > 0 && fullyProcessed && invokes > GraalOptions.LimitInlinedInvokes * inliningBonus) { - return InliningUtil.logNotInlinedMethod(info, "invoke probability is too high (%f)", invokes); + return InliningUtil.logNotInlinedMethod(info, inliningDepth, "invoke probability is too high (%f)", invokes); } double maximumNodes = computeMaximumSize(relevance, (int) (GraalOptions.MaximumInliningSize * inliningBonus)); if (nodes < maximumNodes) { - return InliningUtil.logInlinedMethod(info, fullyProcessed, "relevance-based (relevance=%f, nodes=%d)", relevance, nodes); + return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, nodes=%d)", relevance, nodes); } - return InliningUtil.logNotInlinedMethod(info, "(relevance=%f, probability=%f, bonus=%f)", relevance, probability, inliningBonus); + return InliningUtil.logNotInlinedMethod(info, inliningDepth, "(relevance=%f, probability=%f, bonus=%f)", relevance, probability, inliningBonus); } } @@ -466,8 +470,8 @@ assert start.isAlive(); } - public Stack apply() { - Stack invokes = new Stack<>(); + public LinkedList apply() { + LinkedList invokes = new LinkedList<>(); FixedNode current; forcedQueue(start); @@ -476,7 +480,7 @@ if (current instanceof Invoke) { if (current != start) { - invokes.push((Invoke) current); + invokes.addLast((Invoke) current); } queueSuccessors(current); } else if (current instanceof LoopBeginNode) { @@ -552,22 +556,30 @@ */ static class InliningData { - private static final GraphInfo DummyGraphInfo = new GraphInfo(null, new Stack(), 1.0, 1.0); + private static final GraphInfo DummyGraphInfo = new GraphInfo(null, new LinkedList(), 1.0, 1.0); private final ArrayDeque graphQueue; private final ArrayDeque invocationQueue; - private int maxGraphs = 1; + private int maxGraphs; - public InliningData() { + public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions) { this.graphQueue = new ArrayDeque<>(); this.invocationQueue = new ArrayDeque<>(); + this.maxGraphs = 1; + + invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0)); + pushGraph(rootGraph, 1.0, 1.0); + } + + public int graphCount() { + return graphQueue.size(); } public void pushGraph(StructuredGraph graph, double probability, double relevance) { assert !contains(graph); NodeBitMap visitedFixedNodes = graph.createNodeBitMap(); - Stack invokes = new InliningIterator(graph.start(), visitedFixedNodes).apply(); + LinkedList invokes = new InliningIterator(graph.start(), visitedFixedNodes).apply(); assert invokes.size() == count(graph.getInvokes()); graphQueue.push(new GraphInfo(graph, invokes, probability, relevance)); assert graphQueue.size() <= maxGraphs; @@ -590,6 +602,13 @@ assert graphQueue.size() <= maxGraphs; } + public void popGraphs(int count) { + assert count >= 0; + for (int i = 0; i < count; i++) { + graphQueue.pop(); + } + } + public MethodInvocation currentInvocation() { return invocationQueue.peek(); } @@ -619,7 +638,8 @@ } public int inliningDepth() { - return invocationQueue.size(); + assert invocationQueue.size() > 0; + return invocationQueue.size() - 1; } @Override @@ -683,9 +703,13 @@ assert processedGraphs <= callee.numberOfMethods(); } - public boolean processedAllGraphs() { + public int processedGraphs() { assert processedGraphs <= callee.numberOfMethods(); - return processedGraphs == callee.numberOfMethods(); + return processedGraphs; + } + + public int totalGraphs() { + return callee.numberOfMethods(); } public InlineInfo callee() { @@ -703,19 +727,23 @@ public double relevance() { return relevance; } + + public boolean isRoot() { + return callee == null; + } } private static class GraphInfo { private final StructuredGraph graph; - private final Stack remainingInvokes; + private final LinkedList remainingInvokes; private final double probability; private final double relevance; private NodesToDoubles nodeProbabilities; private NodesToDoubles nodeRelevance; - public GraphInfo(StructuredGraph graph, Stack invokes, double probability, double relevance) { + public GraphInfo(StructuredGraph graph, LinkedList invokes, double probability, double relevance) { this.graph = graph; this.remainingInvokes = invokes; this.probability = probability; @@ -739,7 +767,7 @@ } public Invoke popInvoke() { - return remainingInvokes.pop(); + return remainingInvokes.removeFirst(); } public void pushInvoke(Invoke invoke) { diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue May 21 19:51:00 2013 +0200 @@ -59,9 +59,9 @@ public interface InliningPolicy { - boolean continueInlining(InliningData data); + boolean continueInlining(StructuredGraph graph); - boolean isWorthInlining(InlineInfo info, double probability, double relevance, boolean fullyProcessed); + boolean isWorthInlining(InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed); } public static class InlineableMacroNode implements InlineableElement { @@ -90,14 +90,14 @@ /** * Print a HotSpot-style inlining message to the console. */ - private static void printInlining(final InlineInfo info, final boolean success, final String msg, final Object... args) { - printInlining(info.methodAt(0), info.invoke(), success, msg, args); + private static void printInlining(final InlineInfo info, final int inliningDepth, final boolean success, final String msg, final Object... args) { + printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args); } /** * Print a HotSpot-style inlining message to the console. */ - private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final boolean success, final String msg, final Object... args) { + private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) { if (GraalOptions.HotSpotPrintInlining) { final int mod = method.getModifiers(); // 1234567 @@ -108,25 +108,24 @@ TTY.print("%c%c%c%c%c ", ' ', Modifier.isSynchronized(mod) ? 's' : ' ', ' ', ' ', Modifier.isNative(mod) ? 'n' : ' '); TTY.print(" "); // more indent TTY.print(" "); // initial inlining indent - final int level = computeInliningLevel(invoke); - for (int i = 0; i < level; i++) { + for (int i = 0; i < inliningDepth; i++) { TTY.print(" "); } TTY.println(String.format("@ %d %s %s%s", invoke.bci(), methodName(method, null), success ? "" : "not inlining ", String.format(msg, args))); } } - public static boolean logInlinedMethod(InlineInfo info, boolean allowLogging, String msg, Object... args) { - return logInliningDecision(info, allowLogging, true, msg, args); + public static boolean logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) { + return logInliningDecision(info, inliningDepth, allowLogging, true, msg, args); } - public static boolean logNotInlinedMethod(InlineInfo info, String msg, Object... args) { - return logInliningDecision(info, true, false, msg, args); + public static boolean logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) { + return logInliningDecision(info, inliningDepth, true, false, msg, args); } - public static boolean logInliningDecision(InlineInfo info, boolean allowLogging, boolean success, String msg, final Object... args) { + public static boolean logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) { if (allowLogging) { - printInlining(info, success, msg, args); + printInlining(info, inliningDepth, success, msg, args); if (shouldLogInliningDecision()) { logInliningDecision(methodName(info), success, msg, args); } @@ -151,12 +150,12 @@ return false; } - private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, ResolvedJavaMethod method, String msg) { - return logNotInlinedMethodAndReturnNull(invoke, method, msg, new Object[0]); + private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) { + return logNotInlinedMethodAndReturnNull(invoke, inliningDepth, method, msg, new Object[0]); } - private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, ResolvedJavaMethod method, String msg, Object... args) { - printInlining(method, invoke, false, msg, args); + private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) { + printInlining(method, invoke, inliningDepth, false, msg, args); if (shouldLogInliningDecision()) { String methodString = methodName(method, invoke); logInliningDecision(methodString, false, msg, args); @@ -164,8 +163,8 @@ return null; } - private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, ResolvedJavaMethod method, String msg) { - printInlining(method, invoke, false, msg, new Object[0]); + private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) { + printInlining(method, invoke, inliningDepth, false, msg, new Object[0]); if (shouldLogInliningDecision()) { String methodString = methodName(method, invoke); logInliningDecision(methodString, false, msg, new Object[0]); @@ -1085,18 +1084,18 @@ TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver; typeProfile = typeProfileProxyNode.getProfile(); } else { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists"); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no type profile exists"); } ProfiledType[] ptypes = typeProfile.getTypes(); if (ptypes == null || ptypes.length <= 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types in profile"); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types in profile"); } double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); if (ptypes.length == 1 && notRecordedTypeProbability == 0) { if (!optimisticOpts.inlineMonomorphicCalls()) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled"); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining monomorphic calls is disabled"); } ResolvedJavaType type = ptypes[0].getType(); @@ -1109,12 +1108,12 @@ invoke.setPolymorphic(true); if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); } if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { // due to filtering impossible types, notRecordedTypeProbability can be > 0 although // the number of types is lower than what can be recorded in a type profile - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability * 100); } @@ -1135,7 +1134,7 @@ } if (concreteMethods.size() > maxNumberOfMethods) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods); } // Clear methods that fall below the threshold. @@ -1151,7 +1150,8 @@ if (newConcreteMethods.size() == 0) { // No method left that is worth inlining. - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size()); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", + concreteMethods.size()); } concreteMethods = newConcreteMethods; @@ -1174,12 +1174,12 @@ if (usedTypes.size() == 0) { // No type left that is worth checking for. - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); } for (ResolvedJavaMethod concrete : concreteMethods) { if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); + return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); } } return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability); @@ -1214,34 +1214,24 @@ private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) { if (method == null) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "the method is not resolved"); + return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method is not resolved"); } else if (Modifier.isNative(method.getModifiers()) && (!GraalOptions.Intrinsify || !InliningUtil.canIntrinsify(replacements, method))) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "it is a non-intrinsic native method"); + return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is a non-intrinsic native method"); } else if (Modifier.isAbstract(method.getModifiers())) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "it is an abstract method"); + return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is an abstract method"); } else if (!method.getDeclaringClass().isInitialized()) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "the method's class is not initialized"); + return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method's class is not initialized"); } else if (!method.canBeInlined()) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "it is marked non-inlinable"); + return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is marked non-inlinable"); } else if (data.countRecursiveInlining(method) > GraalOptions.MaximumRecursiveInlining) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "it exceeds the maximum recursive inlining depth"); + return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it exceeds the maximum recursive inlining depth"); } else if (new OptimisticOptimizations(method).lessOptimisticThan(optimisticOpts)) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "the callee uses less optimistic optimizations than caller"); + return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the callee uses less optimistic optimizations than caller"); } else { return true; } } - private static int computeInliningLevel(Invoke invoke) { - int count = -1; - FrameState curState = invoke.stateAfter(); - while (curState != null) { - count++; - curState = curState.outerFrameState(); - } - return count; - } - static MonitorExitNode findPrecedingMonitorExit(UnwindNode unwind) { Node pred = unwind.predecessor(); while (pred != null) { diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Tue May 21 19:51:00 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; diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue May 21 19:51:00 2013 +0200 @@ -95,6 +95,7 @@ FixedNode fixed = (FixedNode) node; if (identity == LocationNode.ANY_LOCATION || read.location().getLocationIdentity() == identity) { addPhantomReference(read, fixed); + iter.remove(); } } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java Tue May 21 19:51:00 2013 +0200 @@ -24,7 +24,6 @@ import java.io.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; @@ -33,28 +32,27 @@ //JaCoCo Exclude /** - * Provides {@link PrintStream}-like logging facility. This should only be used in - * {@linkplain Snippet snippets}. + * Provides {@link PrintStream}-like logging facility. */ public final class Log { - public static final Descriptor LOG_PRIMITIVE = new Descriptor("logPrimitive", false, void.class, int.class, long.class, boolean.class); - public static final Descriptor LOG_OBJECT = new Descriptor("logObject", false, void.class, Object.class, int.class); - public static final Descriptor LOG_PRINTF = new Descriptor("logPrintf", false, void.class, Object.class, long.class, long.class, long.class); + public static final ForeignCallDescriptor LOG_PRIMITIVE = new ForeignCallDescriptor("logPrimitive", void.class, int.class, long.class, boolean.class); + public static final ForeignCallDescriptor LOG_OBJECT = new ForeignCallDescriptor("logObject", void.class, Object.class, int.class); + public static final ForeignCallDescriptor LOG_PRINTF = new ForeignCallDescriptor("logPrintf", void.class, Object.class, long.class, long.class, long.class); - // Note: Must be kept in sync with constants in c1_Runtime1.hpp + // Note: Must be kept in sync with constants in graalRuntime.hpp private static final int LOG_OBJECT_NEWLINE = 0x01; private static final int LOG_OBJECT_STRING = 0x02; private static final int LOG_OBJECT_ADDRESS = 0x04; - @NodeIntrinsic(RuntimeCallNode.class) - private static native void log(@ConstantNodeParameter Descriptor logObject, Object object, int flags); + @NodeIntrinsic(ForeignCallNode.class) + private static native void log(@ConstantNodeParameter ForeignCallDescriptor logObject, Object object, int flags); - @NodeIntrinsic(RuntimeCallNode.class) - private static native void log(@ConstantNodeParameter Descriptor logPrimitive, int typeChar, long value, boolean newline); + @NodeIntrinsic(ForeignCallNode.class) + private static native void log(@ConstantNodeParameter ForeignCallDescriptor logPrimitive, int typeChar, long value, boolean newline); - @NodeIntrinsic(RuntimeCallNode.class) - private static native void printf(@ConstantNodeParameter Descriptor logPrintf, String format, long v1, long v2, long v3); + @NodeIntrinsic(ForeignCallNode.class) + private static native void printf(@ConstantNodeParameter ForeignCallDescriptor logPrintf, String format, long v1, long v2, long v3); public static void print(boolean value) { log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, false); diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java Tue May 21 19:51:00 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.replacements; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; @@ -91,12 +91,12 @@ } } - public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class); - public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class); - public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_SIN = new ForeignCallDescriptor("arithmeticSin", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_COS = new ForeignCallDescriptor("arithmeticCos", double.class, double.class); + public static final ForeignCallDescriptor ARITHMETIC_TAN = new ForeignCallDescriptor("arithmeticTan", double.class, double.class); - @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) - public static double callDouble(@ConstantNodeParameter Descriptor descriptor, double value) { + @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true) + public static double callDouble(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value) { if (descriptor == ARITHMETIC_SIN) { return Math.sin(value); } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Tue May 21 19:51:00 2013 +0200 @@ -26,10 +26,9 @@ import java.util.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; @@ -42,10 +41,10 @@ static class ReadCacheEntry { - public final LocationIdentity identity; + public final ResolvedJavaField identity; public final ValueNode object; - public ReadCacheEntry(LocationIdentity identity, ValueNode object) { + public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) { this.identity = identity; this.object = object; } @@ -83,7 +82,7 @@ readCache = new HashMap<>(other.readCache); } - public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value) { + public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) { ValueNode cacheObject; ObjectState obj = getObjectState(object); if (obj != null) { @@ -95,7 +94,7 @@ readCache.put(new ReadCacheEntry(identity, cacheObject), value); } - public ValueNode getReadCache(ValueNode object, LocationIdentity identity) { + public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) { ValueNode cacheObject; ObjectState obj = getObjectState(object); if (obj != null) { @@ -115,16 +114,16 @@ return cacheValue; } - public void killReadCache(LocationIdentity identity) { - if (identity == LocationNode.ANY_LOCATION) { - readCache.clear(); - } else { - Iterator> iter = readCache.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - if (entry.getKey().identity == identity) { - iter.remove(); - } + public void killReadCache() { + readCache.clear(); + } + + public void killReadCache(ResolvedJavaField identity) { + Iterator> iter = readCache.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + if (entry.getKey().identity == identity) { + iter.remove(); } } } @@ -187,7 +186,7 @@ if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode instance = (VirtualInstanceNode) virtual; for (int i = 0; i < entries.length; i++) { - readCache.put(new ReadCacheEntry((LocationIdentity) instance.field(i), representation), values.get(pos + i)); + readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(pos + i)); } } } else { diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Tue May 21 19:51:00 2013 +0200 @@ -75,7 +75,7 @@ if (!readElimination) { boolean analyzableNodes = false; for (Node node : graph.getNodes()) { - if (node instanceof VirtualizableAllocation) { + if (node instanceof VirtualizableRoot) { analyzableNodes = true; break; } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue May 21 19:51:00 2013 +0200 @@ -59,9 +59,6 @@ public static final DebugMetric METRIC_MATERIALIZATIONS_LOOP_END = Debug.metric("MaterializationsLoopEnd"); public static final DebugMetric METRIC_ALLOCATION_REMOVED = Debug.metric("AllocationsRemoved"); - public static final DebugMetric METRIC_STOREFIELD_RECORDED = Debug.metric("StoreFieldRecorded"); - public static final DebugMetric METRIC_LOADFIELD_ELIMINATED = Debug.metric("LoadFieldEliminated"); - public static final DebugMetric METRIC_LOADFIELD_NOT_ELIMINATED = Debug.metric("LoadFieldNotEliminated"); public static final DebugMetric METRIC_MEMORYCHECKOINT = Debug.metric("MemoryCheckpoint"); private final NodeBitMap usages; @@ -148,44 +145,24 @@ FixedWithNextNode lastFixedNode = null; for (Node node : nodeList) { boolean deleted; - if (usages.isMarked(node) || node instanceof VirtualizableAllocation) { + boolean isMarked = usages.isMarked(node); + if (isMarked || node instanceof VirtualizableRoot) { trace("[[%s]] ", node); - deleted = processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state, effects); + FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next(); + deleted = processNode((ValueNode) node, nextFixedNode, state, effects, isMarked); } else { trace("%s ", node); deleted = false; } if (GraalOptions.OptEarlyReadElimination) { - if (!deleted) { - if (node instanceof StoreFieldNode) { - METRIC_STOREFIELD_RECORDED.increment(); - StoreFieldNode store = (StoreFieldNode) node; - ValueNode cachedValue = state.getReadCache(store.object(), (LocationIdentity) store.field()); - state.killReadCache((LocationIdentity) store.field()); - - if (cachedValue == store.value()) { - effects.deleteFixedNode(store); - changed = true; - } else { - state.addReadCache(store.object(), (LocationIdentity) store.field(), store.value()); - } - } else if (node instanceof LoadFieldNode) { - LoadFieldNode load = (LoadFieldNode) node; - ValueNode cachedValue = state.getReadCache(load.object(), (LocationIdentity) load.field()); - if (cachedValue != null) { - METRIC_LOADFIELD_ELIMINATED.increment(); - effects.replaceAtUsages(load, cachedValue); - state.addScalarAlias(load, cachedValue); - changed = true; - } else { - METRIC_LOADFIELD_NOT_ELIMINATED.increment(); - state.addReadCache(load.object(), (LocationIdentity) load.field(), load); - } - } else if (node instanceof MemoryCheckpoint) { - METRIC_MEMORYCHECKOINT.increment(); - MemoryCheckpoint checkpoint = (MemoryCheckpoint) node; - for (LocationIdentity identity : checkpoint.getLocationIdentities()) { - state.killReadCache(identity); + if (!deleted && node instanceof MemoryCheckpoint) { + METRIC_MEMORYCHECKOINT.increment(); + MemoryCheckpoint checkpoint = (MemoryCheckpoint) node; + for (LocationIdentity identity : checkpoint.getLocationIdentities()) { + if (identity instanceof ResolvedJavaField) { + state.killReadCache((ResolvedJavaField) identity); + } else if (identity == LocationNode.ANY_LOCATION) { + state.killReadCache(); } } } @@ -198,7 +175,7 @@ return state; } - private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects) { + private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects, boolean isMarked) { tool.reset(state, node, insertBefore); if (node instanceof Virtualizable) { ((Virtualizable) node).virtualize(tool); @@ -209,89 +186,91 @@ } return true; } - if (node instanceof StateSplit) { - StateSplit split = (StateSplit) node; - FrameState stateAfter = split.stateAfter(); - if (stateAfter != null) { - if (stateAfter.usages().count() > 1) { - stateAfter = (FrameState) stateAfter.copyWithInputs(); - split.setStateAfter(stateAfter); - } - final HashSet virtual = new HashSet<>(); - stateAfter.applyToNonVirtual(new NodeClosure() { + if (isMarked) { + if (node instanceof StateSplit) { + StateSplit split = (StateSplit) node; + FrameState stateAfter = split.stateAfter(); + if (stateAfter != null) { + if (stateAfter.usages().count() > 1) { + stateAfter = (FrameState) stateAfter.copyWithInputs(); + split.setStateAfter(stateAfter); + } + final HashSet virtual = new HashSet<>(); + stateAfter.applyToNonVirtual(new NodeClosure() { - @Override - public void apply(Node usage, ValueNode value) { - ObjectState valueObj = state.getObjectState(value); - if (valueObj != null) { - virtual.add(valueObj); - effects.replaceFirstInput(usage, value, valueObj.virtual); - } else if (value instanceof VirtualObjectNode) { - ObjectState virtualObj = null; - for (ObjectState obj : state.getStates()) { - if (value == obj.virtual) { - virtualObj = obj; - break; + @Override + public void apply(Node usage, ValueNode value) { + ObjectState valueObj = state.getObjectState(value); + if (valueObj != null) { + virtual.add(valueObj); + effects.replaceFirstInput(usage, value, valueObj.virtual); + } else if (value instanceof VirtualObjectNode) { + ObjectState virtualObj = null; + for (ObjectState obj : state.getStates()) { + if (value == obj.virtual) { + virtualObj = obj; + break; + } + } + if (virtualObj != null) { + virtual.add(virtualObj); } } - if (virtualObj != null) { - virtual.add(virtualObj); - } + } + }); + for (ObjectState obj : state.getStates()) { + if (obj.isVirtual() && obj.hasLocks()) { + virtual.add(obj); } } - }); - for (ObjectState obj : state.getStates()) { - if (obj.isVirtual() && obj.hasLocks()) { - virtual.add(obj); - } - } - ArrayDeque queue = new ArrayDeque<>(virtual); - while (!queue.isEmpty()) { - ObjectState obj = queue.removeLast(); - if (obj.isVirtual()) { - for (ValueNode field : obj.getEntries()) { - ObjectState fieldObj = state.getObjectState(field); - if (fieldObj != null) { - if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) { - virtual.add(fieldObj); - queue.addLast(fieldObj); + ArrayDeque queue = new ArrayDeque<>(virtual); + while (!queue.isEmpty()) { + ObjectState obj = queue.removeLast(); + if (obj.isVirtual()) { + for (ValueNode field : obj.getEntries()) { + ObjectState fieldObj = state.getObjectState(field); + if (fieldObj != null) { + if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) { + virtual.add(fieldObj); + queue.addLast(fieldObj); + } } } } } - } - for (ObjectState obj : virtual) { - EscapeObjectState v; - if (obj.isVirtual()) { - ValueNode[] fieldState = obj.getEntries().clone(); - for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = state.getObjectState(fieldState[i]); - if (valueObj != null) { - if (valueObj.isVirtual()) { - fieldState[i] = valueObj.virtual; - } else { - fieldState[i] = valueObj.getMaterializedValue(); + for (ObjectState obj : virtual) { + EscapeObjectState v; + if (obj.isVirtual()) { + ValueNode[] fieldState = obj.getEntries().clone(); + for (int i = 0; i < fieldState.length; i++) { + ObjectState valueObj = state.getObjectState(fieldState[i]); + if (valueObj != null) { + if (valueObj.isVirtual()) { + fieldState[i] = valueObj.virtual; + } else { + fieldState[i] = valueObj.getMaterializedValue(); + } } } + v = new VirtualObjectState(obj.virtual, fieldState); + } else { + v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue()); } - v = new VirtualObjectState(obj.virtual, fieldState); - } else { - v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue()); + effects.addVirtualMapping(stateAfter, v); } - effects.addVirtualMapping(stateAfter, v); } } - } - for (ValueNode input : node.inputs().filter(ValueNode.class)) { - ObjectState obj = state.getObjectState(input); - if (obj != null) { - if (obj.isVirtual() && node instanceof MethodCallTargetNode) { - Invoke invoke = ((MethodCallTargetNode) node).invoke(); - hints.put(invoke, 5d); + for (ValueNode input : node.inputs().filter(ValueNode.class)) { + ObjectState obj = state.getObjectState(input); + if (obj != null) { + if (obj.isVirtual() && node instanceof MethodCallTargetNode) { + Invoke invoke = ((MethodCallTargetNode) node).invoke(); + hints.put(invoke, 5d); + } + trace("replacing input %s at %s: %s", input, node, obj); + replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED); } - trace("replacing input %s at %s: %s", input, node, obj); - replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED); } } return false; @@ -703,7 +682,7 @@ } } - private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List states) { + private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List states) { ValueNode[] values = new ValueNode[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity); diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Tue May 21 19:51:00 2013 +0200 @@ -181,4 +181,26 @@ } } } + + @Override + public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) { + if (GraalOptions.OptEarlyReadElimination) { + state.addReadCache(object, identity, value); + } + } + + @Override + public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) { + if (GraalOptions.OptEarlyReadElimination) { + return state.getReadCache(object, identity); + } + return null; + } + + @Override + public void killReadCache(ResolvedJavaField identity) { + if (GraalOptions.OptEarlyReadElimination) { + state.killReadCache(identity); + } + } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue May 21 19:51:00 2013 +0200 @@ -115,7 +115,7 @@ * @return the code as a String object */ public final String getCode() { - return getSource().getCode().substring(charIndex, charLength); + return getSource().getCode().substring(charIndex, charIndex + charLength); } @Override diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Tue May 21 19:51:00 2013 +0200 @@ -24,7 +24,6 @@ import java.io.*; import java.lang.annotation.*; -import java.lang.reflect.*; import java.net.*; import java.util.*; @@ -35,6 +34,10 @@ import org.w3c.dom.*; +import com.oracle.truffle.api.nodes.NodeUtil.NodeClass; +import com.oracle.truffle.api.nodes.NodeUtil.NodeField; +import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind; + /** * Utility class for creating output for the ideal graph visualizer. */ @@ -212,7 +215,7 @@ setNodeProperty(node, "nodeType", (Node.class.isAssignableFrom(node.getClass()) ? Node.class.getSimpleName() : "other")); setNodeProperty(node, "nodeClass", node.getClass().getSimpleName()); copyDebugProperties(node); // TODO: may overwrite property "name"? (currently allowed) - readNodeProperties(node); + readNodeProperties((Node) node); } } @@ -254,23 +257,14 @@ } } - private void readNodeProperties(Object node) { - Field[] fields = NodeUtil.getAllFields(node.getClass()); - for (Field field : fields) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Node.class.isAssignableFrom(field.getType()) || (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType()))) { - continue; - } - String key = field.getName(); - if (field.getAnnotation(HiddenField.class) == null && getPropertyElement(node, key) == null) { - try { - field.setAccessible(true); - Object value = field.get(node); + private void readNodeProperties(Node node) { + NodeField[] fields = NodeClass.get(node.getClass()).getFields(); + for (NodeField field : fields) { + if (field.getKind() == NodeFieldKind.DATA) { + String key = field.getName(); + if (getPropertyElement(node, key) == null) { + Object value = field.loadValue(node); setNodeProperty(node, key, value); - } catch (IllegalArgumentException | IllegalAccessException e) { - assert false : e; } } } diff -r ba02d19dd3cc -r 5402504894fe graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Tue May 21 19:43:53 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Tue May 21 19:51:00 2013 +0200 @@ -37,104 +37,181 @@ */ public class NodeUtil { - public static final class NodeClass { + /** + * Interface that allows the customization of field offsets used for {@link Unsafe} field + * accesses. + */ + public interface FieldOffsetProvider { + + long objectFieldOffset(Field field); + } + + private static final FieldOffsetProvider unsafeFieldOffsetProvider = new FieldOffsetProvider() { + + @Override + public long objectFieldOffset(Field field) { + return unsafe.objectFieldOffset(field); + } + }; + + public static enum NodeFieldKind { + /** The single {@link Node#getParent() parent} field. */ + PARENT, + /** A field annotated with {@link Child}. */ + CHILD, + /** A field annotated with {@link Children}. */ + CHILDREN, + /** A normal non-child data field of the node. */ + DATA + } + + /** + * Information about a field in a {@link Node} class. + */ + public static final class NodeField { + + private final NodeFieldKind kind; + private final Class type; + private final String name; + private long offset; + + protected NodeField(NodeFieldKind kind, Class type, String name, long offset) { + this.kind = kind; + this.type = type; + this.name = name; + this.offset = offset; + } - private final Class parentClass; - private final long[] nodeFieldOffsets; - private final Class[] nodeFieldClasses; - private final long[] nodeArrayFieldOffsets; - private final Class[] nodeArrayFieldClasses; - private final long parentOffset; - private final long[] nodeDataFieldOffsets; - private final Class[] nodeDataFieldClasses; + public NodeFieldKind getKind() { + return kind; + } + + public Class getType() { + return type; + } + + public String getName() { + return name; + } + + public long getOffset() { + return offset; + } + + public Object loadValue(Node node) { + if (type == boolean.class) { + return unsafe.getBoolean(node, offset); + } else if (type == byte.class) { + return unsafe.getByte(node, offset); + } else if (type == short.class) { + return unsafe.getShort(node, offset); + } else if (type == char.class) { + return unsafe.getChar(node, offset); + } else if (type == int.class) { + return unsafe.getInt(node, offset); + } else if (type == long.class) { + return unsafe.getLong(node, offset); + } else if (type == float.class) { + return unsafe.getFloat(node, offset); + } else if (type == double.class) { + return unsafe.getDouble(node, offset); + } else { + return unsafe.getObject(node, offset); + } + } + } + + /** + * Information about a {@link Node} class. A single instance of this class is allocated for + * every subclass of {@link Node} that is used. + */ + public static final class NodeClass { private static final Map, NodeClass> nodeClasses = new IdentityHashMap<>(); - public static NodeClass get(Class clazz) { + // The comprehensive list of all fields. + private final NodeField[] fields; + // Separate arrays for the frequently accessed field offsets. + private final long parentOffset; + private final long[] childOffsets; + private final long[] childrenOffsets; + + public static NodeClass get(Class clazz) { NodeClass nodeClass = nodeClasses.get(clazz); if (nodeClass == null) { - nodeClass = new NodeClass(clazz); + nodeClass = new NodeClass(clazz, unsafeFieldOffsetProvider); nodeClasses.put(clazz, nodeClass); } return nodeClass; } - private NodeClass(Class clazz) { - // scan object fields - Class parentClassTmp = null; - List nodeFieldOffsetsList = new ArrayList<>(); - List> nodeFieldClassesList = new ArrayList<>(); - List nodeArrayFieldOffsetsList = new ArrayList<>(); - List> nodeArrayFieldClassesList = new ArrayList<>(); - List nodeDataFieldOffsetList = new ArrayList<>(); - List> nodeDataFieldClassList = new ArrayList<>(); - Field[] fields = getAllFields(clazz); - long parentOffsetTemp = -1; - for (Field field : fields) { + public NodeClass(Class clazz, FieldOffsetProvider fieldOffsetProvider) { + List fieldsList = new ArrayList<>(); + List parentOffsetsList = new ArrayList<>(); + List childOffsetsList = new ArrayList<>(); + List childrenOffsetsList = new ArrayList<>(); + + for (Field field : getAllFields(clazz)) { if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { continue; } - // Node fields - if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent")) { - parentOffsetTemp = unsafe.objectFieldOffset(field); - parentClassTmp = field.getType(); + NodeFieldKind kind; + if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent") && field.getDeclaringClass() == Node.class) { + kind = NodeFieldKind.PARENT; + parentOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) { - nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field)); - nodeFieldClassesList.add(field.getType()); - } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { - nodeArrayFieldOffsetsList.add(unsafe.objectFieldOffset(field)); - nodeArrayFieldClassesList.add(field.getType()); + kind = NodeFieldKind.CHILD; + childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); + } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { + kind = NodeFieldKind.CHILDREN; + childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); } else { - nodeDataFieldOffsetList.add(unsafe.objectFieldOffset(field)); - nodeDataFieldClassList.add(field.getType()); + kind = NodeFieldKind.DATA; } + fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field))); } - this.parentClass = parentClassTmp; - this.nodeFieldOffsets = toLongArray(nodeFieldOffsetsList); - this.nodeFieldClasses = nodeFieldClassesList.toArray(new Class[nodeFieldClassesList.size()]); - this.nodeArrayFieldOffsets = toLongArray(nodeArrayFieldOffsetsList); - this.nodeArrayFieldClasses = nodeArrayFieldClassesList.toArray(new Class[nodeArrayFieldClassesList.size()]); - this.nodeDataFieldOffsets = toLongArray(nodeDataFieldOffsetList); - this.nodeDataFieldClasses = nodeDataFieldClassList.toArray(new Class[nodeDataFieldClassList.size()]); + this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]); + assert parentOffsetsList.size() == 1 : "must have exactly one parent field"; + this.parentOffset = parentOffsetsList.get(0); + this.childOffsets = toLongArray(childOffsetsList); + this.childrenOffsets = toLongArray(childrenOffsetsList); + } - this.parentOffset = parentOffsetTemp; + public NodeField[] getFields() { + return fields; } public long getParentOffset() { return parentOffset; } - public long[] getNodeFieldOffsets() { - return nodeFieldOffsets; + public long[] getChildOffsets() { + return childOffsets; } - public long[] getNodeArrayFieldOffsets() { - return nodeArrayFieldOffsets; + public long[] getChildrenOffsets() { + return childrenOffsets; } } - public static class NodeIterator implements Iterator { + static class NodeIterator implements Iterator { private final Node node; private final NodeClass nodeClass; private final int childrenCount; private int index; - public NodeIterator(Node node) { - this(node, 0); - } - - public NodeIterator(Node node, int index) { + protected NodeIterator(Node node) { this.node = node; - this.index = index; + this.index = 0; this.nodeClass = NodeClass.get(node.getClass()); this.childrenCount = childrenCount(); } private int childrenCount() { - int nodeCount = nodeClass.nodeFieldOffsets.length; - for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + int nodeCount = nodeClass.childOffsets.length; + for (long fieldOffset : nodeClass.childrenOffsets) { Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset)); if (children != null) { nodeCount += children.length; @@ -144,11 +221,11 @@ } private Node nodeAt(int idx) { - int nodeCount = nodeClass.nodeFieldOffsets.length; + int nodeCount = nodeClass.childOffsets.length; if (idx < nodeCount) { - return (Node) unsafe.getObject(node, nodeClass.nodeFieldOffsets[idx]); + return (Node) unsafe.getObject(node, nodeClass.childOffsets[idx]); } else { - for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + for (long fieldOffset : nodeClass.childrenOffsets) { Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset); if (idx < nodeCount + nodeArray.length) { return nodeArray[idx - nodeCount]; @@ -220,7 +297,7 @@ unsafe.putObject(clone, nodeClass.parentOffset, null); - for (long fieldOffset : nodeClass.nodeFieldOffsets) { + for (long fieldOffset : nodeClass.childOffsets) { Node child = (Node) unsafe.getObject(orig, fieldOffset); if (child != null) { Node clonedChild = cloneNode(child); @@ -232,7 +309,7 @@ unsafe.putObject(clone, fieldOffset, clonedChild); } } - for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + for (long fieldOffset : nodeClass.childrenOffsets) { Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset); if (children != null) { Node[] clonedChildren = children.clone(); @@ -256,13 +333,13 @@ List nodes = new ArrayList<>(); NodeClass nodeClass = NodeClass.get(node.getClass()); - for (long fieldOffset : nodeClass.nodeFieldOffsets) { + for (long fieldOffset : nodeClass.childOffsets) { Object child = unsafe.getObject(node, fieldOffset); if (child != null) { nodes.add((Node) child); } } - for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + for (long fieldOffset : nodeClass.childrenOffsets) { Node[] children = (Node[]) unsafe.getObject(node, fieldOffset); if (children != null) { nodes.addAll(Arrays.asList(children)); @@ -275,12 +352,12 @@ public static void replaceChild(Node parent, Node oldChild, Node newChild) { NodeClass nodeClass = NodeClass.get(parent.getClass()); - for (long fieldOffset : nodeClass.nodeFieldOffsets) { + for (long fieldOffset : nodeClass.childOffsets) { if (unsafe.getObject(parent, fieldOffset) == oldChild) { unsafe.putObject(parent, fieldOffset, newChild); } } - for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + for (long fieldOffset : nodeClass.childrenOffsets) { Node[] array = (Node[]) unsafe.getObject(parent, fieldOffset); if (array != null) { for (int i = 0; i < array.length; i++) { @@ -293,49 +370,8 @@ } } - public static long[] getNodeDataFieldOffsets(Class nodeClass) { - NodeClass clazz = NodeClass.get(nodeClass); - return Arrays.copyOf(clazz.nodeDataFieldOffsets, clazz.nodeDataFieldClasses.length); - } - - public static Class[] getNodeDataFieldClasses(Class nodeClass) { - NodeClass clazz = NodeClass.get(nodeClass); - return Arrays.copyOf(clazz.nodeDataFieldClasses, clazz.nodeDataFieldClasses.length); - } - - public static long getNodeParentOffset(Class nodeClass) { - NodeClass clazz = NodeClass.get(nodeClass); - return clazz.parentOffset; - } - - /** Returns the number of Node field declarations in the class hierarchy. */ - public static long[] getNodeFieldOffsets(Class nodeClass) { - NodeClass clazz = NodeClass.get(nodeClass); - return Arrays.copyOf(clazz.nodeFieldOffsets, clazz.nodeFieldOffsets.length); - } - - /** Returns the number of Node[] declaration in the class hierarchy. */ - public static long[] getNodeFieldArrayOffsets(Class nodeClass) { - NodeClass clazz = NodeClass.get(nodeClass); - return Arrays.copyOf(clazz.nodeArrayFieldOffsets, clazz.nodeArrayFieldOffsets.length); - } - - public static Class[] getNodeFieldArrayClasses(Class nodeClass) { - NodeClass clazz = NodeClass.get(nodeClass); - return Arrays.copyOf(clazz.nodeArrayFieldClasses, clazz.nodeArrayFieldClasses.length); - } - - public static Class getNodeParentClass(Class nodeClass) { - return NodeClass.get(nodeClass).parentClass; - } - - public static Class[] getNodeFieldClasses(Class nodeClass) { - NodeClass clazz = NodeClass.get(nodeClass); - return Arrays.copyOf(clazz.nodeFieldClasses, clazz.nodeFieldClasses.length); - } - /** Returns all declared fields in the class hierarchy. */ - public static Field[] getAllFields(Class clazz) { + private static Field[] getAllFields(Class clazz) { Field[] declaredFields = clazz.getDeclaredFields(); if (clazz.getSuperclass() != null) { return concat(getAllFields(clazz.getSuperclass()), declaredFields); @@ -472,44 +508,17 @@ return nodeList; } - public static String printTreeToString(Node node) { - return printTreeToString(node, false); - } - - private static String printTreeToString(Node node, boolean compact) { - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - if (compact) { - printCompactTree(new PrintStream(byteOut), node); - } else { - printTree(new PrintStream(byteOut), node); - } - try { - byteOut.flush(); - } catch (IOException e) { - } - return new String(byteOut.toByteArray()); + public static String printCompactTreeToString(Node node) { + StringWriter out = new StringWriter(); + printCompactTree(new PrintWriter(out), null, node, 1); + return out.toString(); } - /** - * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This - * print method does not check for cycles in the node structure. - * - * @param p the {@link PrintStream} to print to. - * @param node the root node to write - */ - public static void printTree(PrintStream p, Node node) { - printTree(p, node, new NodeTreeResolver()); + public static void printCompactTree(OutputStream out, Node node) { + printCompactTree(new PrintWriter(out), null, node, 1); } - public static String printCompactTreeToString(Node node) { - return printTreeToString(node, true); - } - - public static void printCompactTree(PrintStream p, Node node) { - printCompactTree(p, null, node, 1); - } - - private static void printCompactTree(PrintStream p, Node parent, Node node, int level) { + private static void printCompactTree(PrintWriter p, Node parent, Node node, int level) { if (node == null) { return; } @@ -519,32 +528,23 @@ if (parent == null) { p.println(node.getClass().getSimpleName()); } else { - String fieldName = null; - Field[] fields = NodeUtil.getAllFields(parent.getClass()); - try { - for (Field field : fields) { - field.setAccessible(true); - Object value = field.get(parent); - if (value == node) { - fieldName = field.getName(); - break; - } else if (value instanceof Node[]) { - int index = 0; - for (Node arrayNode : (Node[]) value) { - if (arrayNode == node) { - fieldName = field.getName() + "[" + index + "]"; - break; - } - index++; + String fieldName = "unknownField"; + NodeField[] fields = NodeClass.get(parent.getClass()).fields; + for (NodeField field : fields) { + Object value = field.loadValue(parent); + if (value == node) { + fieldName = field.getName(); + break; + } else if (value instanceof Node[]) { + int index = 0; + for (Node arrayNode : (Node[]) value) { + if (arrayNode == node) { + fieldName = field.getName() + "[" + index + "]"; + break; } + index++; } } - } catch (Exception e) { - e.printStackTrace(); - } - - if (fieldName == null) { - fieldName = "unknownField"; } p.print(fieldName); p.print(" = "); @@ -554,23 +554,33 @@ for (Node child : node.getChildren()) { printCompactTree(p, node, child, level + 1); } + p.flush(); } /** - * Prints a human readable form of a tree to the given {@link PrintStream}. The - * {@link TreeResolver} interface needs to be implemented to specify how the method can read the - * tree from plain a object. + * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This + * print method does not check for cycles in the node structure. * - * @param p the {@link PrintStream} to print to. - * @param o the root object to be printed. - * @param resolver an implementation of a tree resolver + * @param out the stream to print to. + * @param node the root node to write */ - public static void printTree(PrintStream p, Object o, TreeResolver resolver) { - printTree(p, o, resolver, 1); - p.println(); + public static void printTree(OutputStream out, Node node) { + printTree(new PrintWriter(out), node); } - private static void printTree(PrintStream p, Object node, TreeResolver resolver, int level) { + public static String printTreeToString(Node node) { + StringWriter out = new StringWriter(); + printTree(new PrintWriter(out), node); + return out.toString(); + } + + public static void printTree(PrintWriter p, Node node) { + printTree(p, node, 1); + p.println(); + p.flush(); + } + + private static void printTree(PrintWriter p, Node node, int level) { if (node == null) { p.print("null"); return; @@ -578,204 +588,56 @@ p.print(node.getClass().getSimpleName()); - Field[] fields = NodeUtil.getAllFields(node.getClass()); + ArrayList childFields = new ArrayList<>(); + String sep = ""; p.print("("); - - ArrayList childFields = new ArrayList<>(); + for (NodeField field : NodeClass.get(node.getClass()).fields) { + if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) { + childFields.add(field); + } else if (field.getKind() == NodeFieldKind.DATA) { + p.print(sep); + sep = ", "; - boolean first = true; - for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; - if (Modifier.isStatic(field.getModifiers()) || resolver.isFiltered(field)) { - continue; - } - if (resolver.isChildObject(field) || resolver.isChildArrayObject(field)) { - childFields.add(field); + p.print(field.getName()); + p.print(" = "); + p.print(field.loadValue(node)); } - if (!resolver.isDataField(field)) { - continue; - } - if (!first) { - p.print(", "); - } else { - first = false; - } - - Object value = getObjectValue(node, field.getType(), unsafe.objectFieldOffset(field)); - - p.print(field.getName()); - p.print(" = "); - p.print(resolver.toString(value)); } p.print(")"); if (childFields.size() != 0) { p.print(" {"); - } - - // I refetch the fields to get declaration order. - for (int i = 0; i < childFields.size(); i++) { - Field field = childFields.get(i); - Class fieldClass = field.getType(); - String name = field.getName(); - - long offset = unsafe.objectFieldOffset(field); - - Object value = getObjectValue(node, fieldClass, offset); + for (NodeField field : childFields) { + printNewLine(p, level); + p.print(field.getName()); - printNewLine(p, level); - p.print(name); - if (value == null) { - p.print(" = null "); - } else if (resolver.isChildObject(field)) { - p.print(" = "); - printTree(p, value, resolver, level + 1); - } else if (resolver.isChildArrayObject(field)) { - Object[] objectArray = resolver.convertToArray(field, value); - if (objectArray.length == 0) { - p.print(" = []"); - } else { + Object value = field.loadValue(node); + if (value == null) { + p.print(" = null "); + } else if (field.getKind() == NodeFieldKind.CHILD) { + p.print(" = "); + printTree(p, (Node) value, level + 1); + } else if (field.getKind() == NodeFieldKind.CHILDREN) { + Node[] children = (Node[]) value; p.print(" = ["); - for (int j = 0; j < objectArray.length; j++) { - printTree(p, objectArray[j], resolver, level + 1); - if (j < objectArray.length - 1) { - p.print(", "); - } + sep = ""; + for (Node child : children) { + p.print(sep); + sep = ", "; + printTree(p, child, level + 1); } p.print("]"); } - } else { - assert false; } - } - - if (childFields.size() != 0) { printNewLine(p, level - 1); p.print("}"); } } - private static Object getObjectValue(Object base, Class fieldClass, long offset) { - if (fieldClass == boolean.class) { - return unsafe.getBoolean(base, offset); - } else if (fieldClass == byte.class) { - return unsafe.getByte(base, offset); - } else if (fieldClass == short.class) { - return unsafe.getShort(base, offset); - } else if (fieldClass == char.class) { - return unsafe.getChar(base, offset); - } else if (fieldClass == int.class) { - return unsafe.getInt(base, offset); - } else if (fieldClass == long.class) { - return unsafe.getLong(base, offset); - } else if (fieldClass == float.class) { - return unsafe.getFloat(base, offset); - } else if (fieldClass == double.class) { - return unsafe.getDouble(base, offset); - } else { - return unsafe.getObject(base, offset); - } - } - - private static void printNewLine(PrintStream p, int level) { + private static void printNewLine(PrintWriter p, int level) { p.println(); for (int i = 0; i < level; i++) { p.print(" "); } } - - private static class NodeTreeResolver implements TreeResolver { - - @Override - public boolean isFiltered(Field f) { - if (f.getName().equals("parent")) { - return true; - } - return f.isSynthetic(); - } - - @Override - public boolean isDataField(Field f) { - return !isChildArrayObject(f) && !isChildObject(f); - } - - @Override - public boolean isChildObject(Field f) { - return Node.class.isAssignableFrom(f.getType()) && f.getAnnotation(Child.class) != null; - } - - @Override - public boolean isChildArrayObject(Field f) { - return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType()) && f.getAnnotation(Children.class) != null; - } - - @Override - public Object[] convertToArray(Field f, Object data) { - return (Object[]) data; - } - - @Override - public String toString(Object o) { - return o == null ? "null" : o.toString(); - } - } - - /** - * Specifies how a tree can be built from plain objects. - */ - public interface TreeResolver { - - /** - * Returns true if a {@link Field} is filtered from the tree. - * - * @param f the field to check - */ - boolean isFiltered(Field f); - - /** - * Returns true if a {@link Field} is a field that contains a data value which should not be - * traversed recursively. - * - * @param f the field to check - * @return true if a the given field is a data field else false. - */ - boolean isDataField(Field f); - - /** - * Returns true if a {@link Field} is a field that contains an {@link Object} which should - * be recursively visited. - * - * @param f the field to check - * @return true if a the given field is a child field else false. - */ - boolean isChildObject(Field f); - - /** - * Returns true if a {@link Field} is a field that contains any kind of list/array structure - * which itself holds values that should be recursively visited. - * - * @param f the field to check - * @return true if a the given field is a child array/list field else false. - */ - boolean isChildArrayObject(Field f); - - /** - * Converts an given child array object to array which can be traversed. This is especially - * useful to convert any kind of list structure to a traversable array. - * - * @param f the field for meta data needed to convert the data {@link Object}. - * @param value the actual value of the child array/list object. - * @return the converted {@link Object} array. - */ - Object[] convertToArray(Field f, Object value); - - /** - * Returns a human readable string for any data field object in the tree. - * - * @param o the object to convert to string. - * @return the converted string - */ - String toString(Object o); - } - } diff -r ba02d19dd3cc -r 5402504894fe src/cpu/sparc/vm/c2_globals_sparc.hpp --- a/src/cpu/sparc/vm/c2_globals_sparc.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/cpu/x86/vm/c1_globals_x86.hpp --- a/src/cpu/x86/vm/c1_globals_x86.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/cpu/x86/vm/c1_globals_x86.hpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/cpu/x86/vm/c2_globals_x86.hpp --- a/src/cpu/x86/vm/c2_globals_x86.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/cpu/x86/vm/c2_globals_x86.hpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/cpu/x86/vm/graalGlobals_x86.hpp --- a/src/cpu/x86/vm/graalGlobals_x86.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/cpu/x86/vm/graalGlobals_x86.hpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue May 21 19:43:53 2013 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/cpu/x86/vm/interp_masm_x86_64.hpp --- a/src/cpu/x86/vm/interp_masm_x86_64.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Tue May 21 19:43:53 2013 +0200 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Tue May 21 19:51:00 2013 +0200 @@ -188,7 +188,7 @@ do_klass(HotSpotCompiledCode_klass, com_oracle_graal_hotspot_HotSpotCompiledCode, Opt) \ do_klass(HotSpotCompiledNmethod_klass, com_oracle_graal_hotspot_HotSpotCompiledNmethod, Opt) \ do_klass(HotSpotCompiledRuntimeStub_klass, com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub, Opt) \ - do_klass(HotSpotRuntimeCallTarget_klass, com_oracle_graal_hotspot_HotSpotRuntimeCallTarget, Opt) \ + do_klass(HotSpotForeignCallLinkage_klass, com_oracle_graal_hotspot_HotSpotForeignCallLinkage, Opt) \ do_klass(HotSpotCodeInfo_klass, com_oracle_graal_hotspot_meta_HotSpotCodeInfo, Opt) \ do_klass(HotSpotInstalledCode_klass, com_oracle_graal_hotspot_meta_HotSpotInstalledCode, Opt) \ do_klass(HotSpotNmethod_klass, com_oracle_graal_hotspot_meta_HotSpotNmethod, Opt) \ diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue May 21 19:51:00 2013 +0200 @@ -299,7 +299,7 @@ template(com_oracle_graal_hotspot_HotSpotCompiledCode, "com/oracle/graal/hotspot/HotSpotCompiledCode") \ template(com_oracle_graal_hotspot_HotSpotCompiledNmethod, "com/oracle/graal/hotspot/HotSpotCompiledNmethod") \ template(com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub, "com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub") \ - template(com_oracle_graal_hotspot_HotSpotRuntimeCallTarget, "com/oracle/graal/hotspot/HotSpotRuntimeCallTarget") \ + template(com_oracle_graal_hotspot_HotSpotForeignCallLinkage, "com/oracle/graal/hotspot/HotSpotForeignCallLinkage") \ template(com_oracle_graal_hotspot_bridge_VMToCompiler, "com/oracle/graal/hotspot/bridge/VMToCompiler") \ template(com_oracle_graal_hotspot_bridge_CompilerToVMImpl, "com/oracle/graal/hotspot/bridge/CompilerToVMImpl") \ template(com_oracle_graal_hotspot_meta_HotSpotCodeInfo, "com/oracle/graal/hotspot/meta/HotSpotCodeInfo") \ diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Tue May 21 19:51:00 2013 +0200 @@ -647,17 +647,17 @@ InstanceKlass* target_klass = InstanceKlass::cast(target->klass()); oop hotspot_method = NULL; // JavaMethod - oop global_stub = NULL; + oop foreign_call = NULL; - if (target_klass->is_subclass_of(SystemDictionary::HotSpotRuntimeCallTarget_klass())) { - global_stub = target; + if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallLinkage_klass())) { + foreign_call = target; } else { hotspot_method = target; } oop debug_info = CompilationResult_Call::debugInfo(site); - assert((hotspot_method ? 1 : 0) + (global_stub ? 1 : 0) == 1, "Call site needs exactly one type"); + assert((hotspot_method ? 1 : 0) + (foreign_call ? 1 : 0) == 1, "Call site needs exactly one type"); NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); jint next_pc_offset = 0x0; @@ -704,24 +704,24 @@ } } - if (global_stub != NULL) { - jlong global_stub_destination = HotSpotRuntimeCallTarget::address(global_stub); + if (foreign_call != NULL) { + jlong foreign_call_destination = HotSpotForeignCallLinkage::address(foreign_call); if (inst->is_call()) { // NOTE: for call without a mov, the offset must fit a 32-bit immediate // see also CompilerToVM.getMaxCallTargetOffset() NativeCall* call = nativeCall_at((address) (inst)); - call->set_destination((address) global_stub_destination); + call->set_destination((address) foreign_call_destination); _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); } else if (inst->is_mov_literal64()) { NativeMovConstReg* mov = nativeMovConstReg_at((address) (inst)); - mov->set_data((intptr_t) global_stub_destination); + mov->set_data((intptr_t) foreign_call_destination); _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand); } else { NativeJump* jump = nativeJump_at((address) (inst)); - jump->set_jump_destination((address) global_stub_destination); + jump->set_jump_destination((address) foreign_call_destination); _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand); } - TRACE_graal_3("relocating (stub) at %p", inst); + TRACE_graal_3("relocating (foreign call) at %p", inst); } else { // method != NULL assert(hotspot_method != NULL, "unexpected JavaMethod"); #ifdef ASSERT diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Tue May 21 19:51:00 2013 +0200 @@ -95,7 +95,7 @@ } } if (UseCompiler) { - VMToCompiler::startCompiler(); + VMToCompiler::startCompiler(BootstrapGraal); _initialized = true; if (BootstrapGraal) { // We turn off CompileTheWorld and complete the VM startup so that diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Tue May 21 19:51:00 2013 +0200 @@ -95,8 +95,8 @@ start_class(HotSpotCompiledRuntimeStub) \ oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;") \ end_class \ - start_class(HotSpotRuntimeCallTarget) \ - long_field(HotSpotRuntimeCallTarget, address) \ + start_class(HotSpotForeignCallLinkage) \ + long_field(HotSpotForeignCallLinkage, address) \ end_class \ start_class(ExceptionHandler) \ int_field(ExceptionHandler, startBCI) \ diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/graal/graalVMToCompiler.cpp --- a/src/share/vm/graal/graalVMToCompiler.cpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/graal/graalVMToCompiler.cpp Tue May 21 19:51:00 2013 +0200 @@ -123,12 +123,13 @@ } } -void VMToCompiler::startCompiler() { +void VMToCompiler::startCompiler(jboolean bootstrap_enabled) { JavaThread* THREAD = JavaThread::current(); JavaValue result(T_VOID); JavaCallArguments args; args.push_oop(instance()); - JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::void_method_signature(), &args, THREAD); + args.push_int(bootstrap_enabled); + JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::bool_void_signature(), &args, THREAD); check_pending_exception("Error while calling startCompiler"); } diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/graal/graalVMToCompiler.hpp --- a/src/share/vm/graal/graalVMToCompiler.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/graal/graalVMToCompiler.hpp Tue May 21 19:51:00 2013 +0200 @@ -59,8 +59,8 @@ // public abstract void shutdownCompiler(); static void shutdownCompiler(); - // public abstract void startCompiler(); - static void startCompiler(); + // public abstract void startCompiler(boolean bootstrapEnabled); + static void startCompiler(jboolean bootstrap_enabled); // public abstract void bootstrap(); static void bootstrap(); diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/oops/methodData.cpp Tue May 21 19:51:00 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; diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/oops/methodData.hpp Tue May 21 19:51:00 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 diff -r ba02d19dd3cc -r 5402504894fe src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/runtime/globals.hpp Tue May 21 19:51:00 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 ba02d19dd3cc -r 5402504894fe src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Tue May 21 19:43:53 2013 +0200 +++ b/src/share/vm/utilities/macros.hpp Tue May 21 19:51:00 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