# HG changeset patch # User Christos Kotselidis # Date 1367182332 -7200 # Node ID 16a10b48e526eb7ab28701c83e8555301db8eb19 # Parent c21b1e5b515ccdca81acda3dc38304e7b4358641# Parent 5a74cbafe5b9cf7acf0804ef16dd0ecfee0e62e4 Merge diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java Sun Apr 28 22:34:46 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * 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.code; - -import com.oracle.graal.api.meta.*; - -/** - * Common base class for values that can be manipulated by the register allocator. - */ -public abstract class AllocatableValue extends Value { - - private static final long serialVersionUID = 153019506717492133L; - - /** - * Marker to tell the register allocator that no storage location needs to be allocated for this - * value. - */ - @SuppressWarnings("serial") public static final AllocatableValue UNUSED = new AllocatableValue(Kind.Illegal) { - - @Override - public String toString() { - return "-"; - } - }; - - public AllocatableValue(Kind kind) { - super(kind); - } - -} diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java Sun Apr 28 22:52:12 2013 +0200 @@ -76,17 +76,17 @@ */ private final int stackSize; - private final Value returnLocation; + private final AllocatableValue returnLocation; /** * The ordered locations in which the arguments are placed. */ - private final Value[] argumentLocations; + private final AllocatableValue[] argumentLocations; /** * The locations used (and killed) by the call in addition to the arguments. */ - private final Value[] temporaryLocations; + private final AllocatableValue[] temporaryLocations; /** * Creates a description of the registers and stack locations used by a call. @@ -97,8 +97,8 @@ * call * @param argumentLocations the ordered locations in which the arguments are placed */ - public CallingConvention(int stackSize, Value returnLocation, Value... argumentLocations) { - this(Value.NONE, stackSize, returnLocation, argumentLocations); + public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) { + this(AllocatableValue.NONE, stackSize, returnLocation, argumentLocations); } /** @@ -112,7 +112,7 @@ * call * @param argumentLocations the ordered locations in which the arguments are placed */ - public CallingConvention(Value[] temporaryLocations, int stackSize, Value returnLocation, Value... argumentLocations) { + public CallingConvention(AllocatableValue[] temporaryLocations, int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) { assert argumentLocations != null; assert temporaryLocations != null; assert returnLocation != null; @@ -126,14 +126,14 @@ /** * Gets the location for the return value or {@link Value#ILLEGAL} if a void call. */ - public Value getReturn() { + public AllocatableValue getReturn() { return returnLocation; } /** * Gets the location for the {@code index}'th argument. */ - public Value getArgument(int index) { + public AllocatableValue getArgument(int index) { return argumentLocations[index]; } @@ -155,7 +155,7 @@ * Gets the locations used (and killed) by the call apart from the * {@linkplain #getArgument(int) arguments}. */ - public Value[] getTemporaries() { + public AllocatableValue[] getTemporaries() { if (temporaryLocations.length == 0) { return temporaryLocations; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Sun Apr 28 22:52:12 2013 +0200 @@ -303,6 +303,14 @@ } sb.append(' ').append(bm).append(nl); } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append("callee-save-info:").append(nl); + Map map = calleeSaveInfo.slotsToRegisters(true); + for (Map.Entry e : map.entrySet()) { + sb.append(" ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl); + } + } BytecodeFrame frame = info.frame(); if (frame != null) { append(sb, frame); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.api.code; +import static java.util.Collections.*; + import java.io.*; import java.util.*; @@ -366,7 +368,7 @@ */ public void recordDataReference(int codePos, Constant data, int alignment, boolean inlined) { assert codePos >= 0 && data != null; - getDataReferences().add(new DataPatch(codePos, data, alignment, inlined)); + dataReferences.add(new DataPatch(codePos, data, alignment, inlined)); } /** @@ -390,7 +392,7 @@ * @param handlerPos the position of the handler */ public void recordExceptionHandler(int codePos, int handlerPos) { - getExceptionHandlers().add(new ExceptionHandler(codePos, handlerPos)); + exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos)); } /** @@ -405,11 +407,11 @@ private void addInfopoint(Infopoint infopoint) { // The infopoints list must always be sorted - if (!getInfopoints().isEmpty() && getInfopoints().get(getInfopoints().size() - 1).pcOffset >= infopoint.pcOffset) { + if (!infopoints.isEmpty() && infopoints.get(infopoints.size() - 1).pcOffset >= infopoint.pcOffset) { // This re-sorting should be very rare - Collections.sort(getInfopoints()); + Collections.sort(infopoints); } - getInfopoints().add(infopoint); + infopoints.add(infopoint); } /** @@ -421,7 +423,7 @@ */ public Mark recordMark(int codePos, Object id, Mark[] references) { Mark mark = new Mark(codePos, id, references); - getMarks().add(mark); + marks.add(mark); return mark; } @@ -505,6 +507,16 @@ if (info != null) { appendRefMap(sb, "stackMap", info.getFrameRefMap()); appendRefMap(sb, "registerMap", info.getRegisterRefMap()); + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append(" callee-save-info["); + String sep = ""; + for (Map.Entry e : calleeSaveInfo.registersToSlots(true).entrySet()) { + sb.append(sep).append(e.getKey()).append("->").append(e.getValue()); + sep = ", "; + } + sb.append(']'); + } BytecodePosition codePos = info.getBytecodePosition(); if (codePos != null) { MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI()); @@ -528,27 +540,39 @@ * @return the list of infopoints, sorted by {@link Site#pcOffset} */ public List getInfopoints() { - return infopoints; + if (infopoints.isEmpty()) { + return emptyList(); + } + return unmodifiableList(infopoints); } /** * @return the list of data references */ public List getDataReferences() { - return dataReferences; + if (dataReferences.isEmpty()) { + return emptyList(); + } + return unmodifiableList(dataReferences); } /** * @return the list of exception handlers */ public List getExceptionHandlers() { - return exceptionHandlers; + if (exceptionHandlers.isEmpty()) { + return emptyList(); + } + return unmodifiableList(exceptionHandlers); } /** * @return the list of marks */ public List getMarks() { - return marks; + if (marks.isEmpty()) { + return emptyList(); + } + return unmodifiableList(marks); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java Sun Apr 28 22:52:12 2013 +0200 @@ -26,8 +26,16 @@ import java.util.*; /** - * Represents the debugging information for a particular place in the code, which includes the code - * position, a reference map, and deoptimization information. + * Represents the debugging information for a particular point of execution. This information + * includes: + *
    + *
  • a {@linkplain #getBytecodePosition() bytecode position}
  • + *
  • a reference map for {@linkplain #getRegisterRefMap() registers}
  • + *
  • a reference map for {@linkplain #getRegisterRefMap() stack slots} in the current frame
  • + *
  • a map from bytecode locals and operand stack slots to their values or locations from which + * their values can be read
  • + *
  • a map from the registers (in the caller's frame) to the slots where they are saved in the + * current frame
  • */ public class DebugInfo implements Serializable { @@ -37,6 +45,7 @@ private final BitSet registerRefMap; private final BitSet frameRefMap; private final short deoptimizationReason; + private RegisterSaveLayout calleeSaveInfo; /** * Creates a new {@link DebugInfo} from the given values. @@ -125,4 +134,20 @@ public short getDeoptimizationReason() { return deoptimizationReason; } + + /** + * Sets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. + */ + public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) { + this.calleeSaveInfo = calleeSaveInfo; + } + + /** + * Gets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. If no such information is available, {@code null} is returned. + */ + public RegisterSaveLayout getCalleeSaveInfo() { + return calleeSaveInfo; + } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,93 @@ +/* + * 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.code; + +import java.util.*; + +/** + * A map from registers to frame slots. This can be used to describe where callee saved registers + * are saved in a callee's frame. + */ +public class RegisterSaveLayout { + + /** + * Keys. + */ + private Register[] registers; + + /** + * Slot indexes relative to stack pointer. + */ + private int[] slots; + + /** + * Creates a map from registers to frame slots. + * + * @param registers the keys in the map + * @param slots frame slot index for each register in {@code registers} + */ + public RegisterSaveLayout(Register[] registers, int[] slots) { + assert registers.length == slots.length; + this.registers = registers; + this.slots = slots; + assert registersToSlots(false).size() == registers.length : "non-unique registers"; + assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots"; + } + + /** + * Gets this layout information as a {@link Map} from registers to slots. + */ + public Map registersToSlots(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(registers[i], slots[i]); + } + return result; + } + + /** + * Gets this layout information as a {@link Map} from slots to registers. + */ + public Map slotsToRegisters(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(slots[i], registers[i]); + } + return result; + } + + @Override + public String toString() { + return registersToSlots(true).toString(); + } +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,39 @@ +/* + * 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; + +/** + * Common base class for values that are stored in some location that's managed by the register + * allocator (e.g. register, stack slot). + */ +public abstract class AllocatableValue extends Value { + + private static final long serialVersionUID = 153019506717492133L; + + public static final AllocatableValue[] NONE = {}; + + public AllocatableValue(Kind kind) { + super(kind); + } + +} diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Sun Apr 28 22:52:12 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.api.meta; import java.io.*; +import java.util.*; import com.oracle.graal.api.meta.ProfilingInfo.*; @@ -43,6 +44,8 @@ private static final long serialVersionUID = 7838575753661305744L; + public static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0]; + private final ResolvedJavaType type; private final double probability; @@ -78,6 +81,40 @@ } 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 final TriState nullSeen; @@ -100,6 +137,7 @@ public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType... ptypes) { this.nullSeen = nullSeen; this.ptypes = ptypes; + assert notRecordedProbability != Double.NaN; this.notRecordedProbability = notRecordedProbability; assert isSorted(ptypes); } @@ -129,4 +167,154 @@ 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(); + } + + public JavaTypeProfile restrict(JavaTypeProfile otherProfile) { + if (otherProfile.getNotRecordedProbability() > 0.0) { + // Not useful for restricting since there is an unknown set of types occuring. + return this; + } + + if (this.getNotRecordedProbability() > 0.0) { + // We are unrestricted, so the other profile is always a better estimate. + return otherProfile; + } + + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getTypes().length; i++) { + ProfiledType ptype = getTypes()[i]; + ResolvedJavaType type = ptype.getType(); + if (otherProfile.isIncluded(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : this.nullSeen; + double newNotRecorded = this.notRecordedProbability; + 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(); + if (declaredType.isAssignableFrom(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (nonNull) ? TriState.FALSE : this.nullSeen; + 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); + } + 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() == 0) { + return new JavaTypeProfile(newNullSeen, 1.0, ProfiledType.EMPTY_ARRAY); + } + double probabilitySum = 0.0; + for (int i = 0; i < result.size(); i++) { + probabilitySum += result.get(i).getProbability(); + } + probabilitySum += newNotRecorded; + + double factor = 1.0 / probabilitySum; // Normalize to 1.0 + assert factor > 1.0; + 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)); + } + double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor); + return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult); + } + return this; + } + + @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; + } + + @Override + public int hashCode() { + return nullSeen.hashCode() + (int) Double.doubleToLongBits(notRecordedProbability) + ptypes.length * 13; + } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,7 +24,6 @@ import java.lang.annotation.*; import java.lang.reflect.*; -import java.lang.reflect.Method; import java.util.*; /** @@ -202,4 +201,11 @@ * @return The newly created and initialized object. */ Constant newInstance(Constant[] arguments); + + /** + * Gets the encoding of (that is, a constant representing the value of) this method. + * + * @return a constant representing a reference to this method + */ + Constant getEncoding(); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Sun Apr 28 22:52:12 2013 +0200 @@ -32,9 +32,7 @@ private static final long serialVersionUID = -6909397188697766469L; - public static final Value[] NONE = {}; - - @SuppressWarnings("serial") public static final Value ILLEGAL = new Value(Kind.Illegal) { + @SuppressWarnings("serial") public static final AllocatableValue ILLEGAL = new AllocatableValue(Kind.Illegal) { @Override public String toString() { diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Sun Apr 28 22:52:12 2013 +0200 @@ -90,7 +90,7 @@ public static class AMD64SpillMoveFactory implements LIR.SpillMoveFactory { @Override - public LIRInstruction createMove(Value result, Value input) { + public LIRInstruction createMove(AllocatableValue result, Value input) { return AMD64LIRGenerator.createMove(result, input); } } @@ -143,8 +143,10 @@ return result; } - private static AMD64LIRInstruction createMove(Value dst, Value src) { - if (isRegister(src) || isStackSlot(dst)) { + private static AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { + if (src instanceof AMD64AddressValue) { + return new LeaOp(dst, (AMD64AddressValue) src); + } else if (isRegister(src) || isStackSlot(dst)) { return new MoveFromRegOp(dst, src); } else { return new MoveToRegOp(dst, src); @@ -152,24 +154,23 @@ } @Override - public void emitMove(Value dst, Value src) { + public void emitMove(AllocatableValue dst, Value src) { append(createMove(dst, src)); } - private AMD64AddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) { + @Override + public AMD64AddressValue emitAddress(Value base, long displacement, Value index, int scale) { AllocatableValue baseRegister; long finalDisp = displacement; if (isConstant(base)) { if (asConstant(base).isNull()) { - baseRegister = AllocatableValue.UNUSED; + baseRegister = Value.ILLEGAL; } else if (asConstant(base).getKind() != Kind.Object && !runtime.needsDataPatch(asConstant(base))) { finalDisp += asConstant(base).asLong(); - baseRegister = AllocatableValue.UNUSED; + baseRegister = Value.ILLEGAL; } else { baseRegister = load(base); } - } else if (base == Value.ILLEGAL) { - baseRegister = AllocatableValue.UNUSED; } else { baseRegister = asAllocatable(base); } @@ -180,12 +181,12 @@ scaleEnum = Scale.fromInt(scale); if (isConstant(index)) { finalDisp += asConstant(index).asLong() * scale; - indexRegister = AllocatableValue.UNUSED; + indexRegister = Value.ILLEGAL; } else { indexRegister = asAllocatable(index); } } else { - indexRegister = AllocatableValue.UNUSED; + indexRegister = Value.ILLEGAL; scaleEnum = Scale.Times1; } @@ -195,9 +196,9 @@ } else { displacementInt = 0; AllocatableValue displacementRegister = load(Constant.forLong(finalDisp)); - if (baseRegister == AllocatableValue.UNUSED) { + if (baseRegister == Value.ILLEGAL) { baseRegister = displacementRegister; - } else if (indexRegister == AllocatableValue.UNUSED) { + } else if (indexRegister == Value.ILLEGAL) { indexRegister = displacementRegister; scaleEnum = Scale.Times1; } else { @@ -205,44 +206,44 @@ } } - return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, displacementInt); + return new AMD64AddressValue(target().wordKind, baseRegister, indexRegister, scaleEnum, displacementInt); + } + + private AMD64AddressValue asAddress(Value address) { + if (address instanceof AMD64AddressValue) { + return (AMD64AddressValue) address; + } else { + return emitAddress(address, 0, Value.ILLEGAL, 0); + } } @Override - public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) { - AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale); - Variable result = newVariable(loadAddress.getKind()); - append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null)); + public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) { + AMD64AddressValue loadAddress = asAddress(address); + Variable result = newVariable(kind); + append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null)); return result; } @Override - public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) { - AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale); + public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) { + AMD64AddressValue storeAddress = asAddress(address); LIRFrameState state = deopting != null ? state(deopting) : null; if (isConstant(inputVal)) { Constant c = asConstant(inputVal); if (canStoreConstant(c)) { - append(new StoreConstantOp(storeAddress, c, state)); + append(new StoreConstantOp(kind, storeAddress, c, state)); return; } } Variable input = load(inputVal); - append(new StoreOp(storeAddress, input, state)); + append(new StoreOp(kind, storeAddress, input, state)); } @Override - public Variable emitLea(Value base, long displacement, Value index, int scale) { - Variable result = newVariable(target().wordKind); - AMD64AddressValue address = prepareAddress(result.getKind(), base, displacement, index, scale); - append(new LeaOp(result, address)); - return result; - } - - @Override - public Variable emitLea(StackSlot address) { + public Variable emitAddress(StackSlot address) { Variable result = newVariable(target().wordKind); append(new StackLeaOp(result, address)); return result; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,23 +22,19 @@ */ package com.oracle.graal.compiler.ptx.test; -import com.oracle.graal.api.code.CodeCacheProvider; -import com.oracle.graal.api.code.CompilationResult; -import com.oracle.graal.api.code.SpeculationLog; -import com.oracle.graal.api.code.TargetDescription; -import com.oracle.graal.api.runtime.Graal; -import com.oracle.graal.compiler.GraalCompiler; -import com.oracle.graal.compiler.ptx.PTXBackend; -import com.oracle.graal.compiler.test.GraalCompilerTest; -import com.oracle.graal.debug.Debug; -import com.oracle.graal.java.GraphBuilderConfiguration; -import com.oracle.graal.java.GraphBuilderPhase; -import com.oracle.graal.hotspot.HotSpotGraalRuntime; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.phases.OptimisticOptimizations; -import com.oracle.graal.phases.PhasePlan; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.ptx.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; -import com.oracle.graal.ptx.PTX; +import com.oracle.graal.ptx.*; public abstract class PTXTestBase extends GraalCompilerTest { @@ -48,14 +44,12 @@ TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true); PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(CodeCacheProvider.class), target); PhasePlan phasePlan = new PhasePlan(); - GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), - OptimisticOptimizations.NONE); + GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE); phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase()); new PTXPhase().apply(graph); - CompilationResult result = GraalCompiler.compileMethod(runtime, HotSpotGraalRuntime.getInstance().getReplacements(), - ptxBackend, target, graph.method(), graph, null, phasePlan, - OptimisticOptimizations.NONE, new SpeculationLog()); + CompilationResult result = GraalCompiler.compileMethod(runtime, graalRuntime().getReplacements(), ptxBackend, target, graph.method(), graph, null, phasePlan, OptimisticOptimizations.NONE, + new SpeculationLog()); return result; } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Sun Apr 28 22:52:12 2013 +0200 @@ -28,17 +28,13 @@ import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.ptx.PTXCompare.*; -import com.oracle.graal.api.code.AllocatableValue; import com.oracle.graal.api.code.CodeCacheProvider; import com.oracle.graal.api.code.DeoptimizationAction; import com.oracle.graal.api.code.RuntimeCallTarget; import com.oracle.graal.api.code.StackSlot; import com.oracle.graal.api.code.TargetDescription; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.Constant; -import com.oracle.graal.api.meta.Kind; -import com.oracle.graal.api.meta.ResolvedJavaMethod; -import com.oracle.graal.api.meta.Value; +import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.NumUtil; import com.oracle.graal.compiler.gen.LIRGenerator; import com.oracle.graal.compiler.target.LIRGenLowerable; @@ -84,7 +80,7 @@ public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory { @Override - public LIRInstruction createMove(Value result, Value input) { + public LIRInstruction createMove(AllocatableValue result, Value input) { throw new InternalError("NYI"); } } @@ -129,7 +125,7 @@ } @Override - public void emitMove(Value dst, Value src) { + public void emitMove(AllocatableValue dst, Value src) { if (isRegister(src) || isStackSlot(dst)) { append(new MoveFromRegOp(dst, src)); } else { @@ -137,20 +133,19 @@ } } - private PTXAddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) { + @Override + public PTXAddressValue emitAddress(Value base, long displacement, Value index, int scale) { AllocatableValue baseRegister; long finalDisp = displacement; if (isConstant(base)) { if (asConstant(base).isNull()) { - baseRegister = AllocatableValue.UNUSED; + baseRegister = Value.ILLEGAL; } else if (asConstant(base).getKind() != Kind.Object) { finalDisp += asConstant(base).asLong(); - baseRegister = AllocatableValue.UNUSED; + baseRegister = Value.ILLEGAL; } else { baseRegister = load(base); } - } else if (base == Value.ILLEGAL) { - baseRegister = AllocatableValue.UNUSED; } else { baseRegister = asAllocatable(base); } @@ -166,7 +161,7 @@ indexRegister = index; } - if (baseRegister == AllocatableValue.UNUSED) { + if (baseRegister == Value.ILLEGAL) { baseRegister = asAllocatable(indexRegister); } else { Variable newBase = newVariable(Kind.Int); @@ -177,31 +172,34 @@ } } - return new PTXAddressValue(kind, baseRegister, finalDisp); + return new PTXAddressValue(target().wordKind, baseRegister, finalDisp); + } + + private PTXAddressValue asAddress(Value address) { + if (address instanceof PTXAddressValue) { + return (PTXAddressValue) address; + } else { + return emitAddress(address, 0, Value.ILLEGAL, 0); + } } @Override - public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) { - PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale); - Variable result = newVariable(loadAddress.getKind()); - append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null)); + public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) { + PTXAddressValue loadAddress = asAddress(address); + Variable result = newVariable(kind); + append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null)); return result; } @Override - public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) { - PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale); + public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) { + PTXAddressValue storeAddress = asAddress(address); Variable input = load(inputVal); - append(new StoreOp(storeAddress, input, deopting != null ? state(deopting) : null)); + append(new StoreOp(kind, storeAddress, input, deopting != null ? state(deopting) : null)); } @Override - public Variable emitLea(Value base, long displacement, Value index, int scale) { - throw new InternalError("NYI"); - } - - @Override - public Variable emitLea(StackSlot address) { + public Variable emitAddress(StackSlot address) { throw new InternalError("NYI"); } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Sun Apr 28 22:52:12 2013 +0200 @@ -208,31 +208,31 @@ } @Override - public void emitMove(Value dst, Value src) { + public void emitMove(AllocatableValue dst, Value src) { // SPARC: Auto-generated method stub } @Override - public Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode canTrap) { + public Value emitAddress(Value base, long displacement, Value index, int scale) { // SPARC: Auto-generated method stub return null; } @Override - public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode canTrap) { + public Value emitLoad(Kind kind, Value address, DeoptimizingNode canTrap) { + // SPARC: Auto-generated method stub + return null; + } + + @Override + public void emitStore(Kind kind, Value address, Value input, DeoptimizingNode canTrap) { // SPARC: Auto-generated method stub } @Override - public Value emitLea(Value base, long displacement, Value index, int scale) { - // SPARC: Auto-generated method stub - return null; - } - - @Override - public Value emitLea(StackSlot address) { + public Value emitAddress(StackSlot address) { // SPARC: Auto-generated method stub return null; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,15 +22,11 @@ */ package com.oracle.graal.compiler.test; -import java.util.*; - import org.junit.*; import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.Lowerable.*; import com.oracle.graal.phases.common.*; @@ -96,36 +92,10 @@ Debug.dump(graph, "After lowering"); - ArrayList merges = new ArrayList<>(); - ArrayList reads = new ArrayList<>(); - for (Node n : graph.getNodes()) { - if (n instanceof MergeNode) { - // check shape - MergeNode merge = (MergeNode) n; - - if (merge.inputs().count() == 2) { - for (EndNode m : merge.forwardEnds()) { - if (m.predecessor() != null && m.predecessor() instanceof BeginNode && m.predecessor().predecessor() instanceof IfNode) { - IfNode o = (IfNode) m.predecessor().predecessor(); - if (o.falseSuccessor().next() instanceof DeoptimizeNode) { - merges.add(merge); - } - } - } - } - } - if (n instanceof IntegerAddNode) { - IntegerAddNode ian = (IntegerAddNode) n; - - Assert.assertTrue(ian.y() instanceof ConstantNode); - Assert.assertTrue(ian.x() instanceof FloatingReadNode); - reads.add((FloatingReadNode) ian.x()); - } - } - - Assert.assertTrue(merges.size() >= reads.size()); - for (int i = 0; i < reads.size(); i++) { - assertOrderedAfterSchedule(graph, merges.get(i), reads.get(i)); + for (FloatingReadNode node : graph.getNodes(LocalNode.class).first().usages().filter(FloatingReadNode.class)) { + // Checking that the parameter a is not directly used for the access to field + // x10 (because x10 must be guarded by the checkcast). + Assert.assertTrue(node.location().locationIdentity() == LocationNode.FINAL_LOCATION); } } }); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Sun Apr 28 22:52:12 2013 +0200 @@ -133,6 +133,8 @@ new IterativeConditionalEliminationPhase().apply(graph, highTierContext); } } + } else { + TypeProfileProxyNode.cleanFromGraph(graph); } plan.runPhases(PhasePosition.HIGH_LEVEL, graph); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Sun Apr 28 22:52:12 2013 +0200 @@ -409,7 +409,7 @@ * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval * prior to register allocation. */ - public final Value operand; + public final AllocatableValue operand; /** * The operand number for this interval's {@linkplain #operand operand}. @@ -420,7 +420,7 @@ * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this * interval. */ - private Value location; + private AllocatableValue location; /** * The stack slot to which all splits of this interval are spilled if necessary. @@ -498,7 +498,7 @@ */ private Interval locationHint; - void assignLocation(Value newLocation) { + void assignLocation(AllocatableValue newLocation) { if (isRegister(newLocation)) { assert this.location == null : "cannot re-assign location for " + this; if (newLocation.getKind() == Kind.Illegal && kind != Kind.Illegal) { @@ -518,7 +518,7 @@ * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to * this interval. */ - public Value location() { + public AllocatableValue location() { return location; } @@ -673,7 +673,7 @@ */ static final Interval EndMarker = new Interval(Value.ILLEGAL, -1); - Interval(Value operand, int operandNumber) { + Interval(AllocatableValue operand, int operandNumber) { assert operand != null; this.operand = operand; this.operandNumber = operandNumber; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Sun Apr 28 22:52:12 2013 +0200 @@ -206,7 +206,7 @@ /** * Gets the operand denoted by a given operand number. */ - private Value operandFor(int operandNumber) { + private AllocatableValue operandFor(int operandNumber) { if (operandNumber < firstVariableNumber) { assert operandNumber >= 0; return registers[operandNumber].asValue(); @@ -281,7 +281,7 @@ * @param operand the operand for the interval * @return the created interval */ - Interval createInterval(Value operand) { + Interval createInterval(AllocatableValue operand) { assert isLegal(operand); int operandNumber = operandNumber(operand); Interval interval = new Interval(operand, operandNumber); @@ -346,7 +346,7 @@ return intervals[operandNumber]; } - Interval getOrCreateInterval(Value operand) { + Interval getOrCreateInterval(AllocatableValue operand) { Interval ret = intervalFor(operand); if (ret == null) { return createInterval(operand); @@ -555,8 +555,8 @@ insertionBuffer.init(instructions); } - Value fromLocation = interval.location(); - Value toLocation = canonicalSpillOpr(interval); + AllocatableValue fromLocation = interval.location(); + AllocatableValue toLocation = canonicalSpillOpr(interval); assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); assert isStackSlot(toLocation) : "to operand must be a stack slot"; @@ -968,7 +968,7 @@ TTY.println(blockData.get(block).liveOut.toString()); } - void addUse(Value operand, int from, int to, RegisterPriority registerPriority, Kind kind) { + void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, Kind kind) { if (!isProcessed(operand)) { return; } @@ -987,7 +987,7 @@ interval.addUsePos(to & ~1, registerPriority); } - void addTemp(Value operand, int tempPos, RegisterPriority registerPriority, Kind kind) { + void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, Kind kind) { if (!isProcessed(operand)) { return; } @@ -1008,7 +1008,7 @@ return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable(); } - void addDef(Value operand, int defPos, RegisterPriority registerPriority, Kind kind) { + void addDef(AllocatableValue operand, int defPos, RegisterPriority registerPriority, Kind kind) { if (!isProcessed(operand)) { return; } @@ -1114,8 +1114,8 @@ @Override protected Value doValue(Value registerHint) { if (isVariableOrRegister(registerHint)) { - Interval from = getOrCreateInterval(registerHint); - Interval to = getOrCreateInterval(targetValue); + Interval from = getOrCreateInterval((AllocatableValue) registerHint); + Interval to = getOrCreateInterval((AllocatableValue) targetValue); // hints always point from def to use if (hintAtDef) { @@ -1156,7 +1156,7 @@ BitSet live = blockData.get(block).liveOut; for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { assert live.get(operandNum) : "should not stop here otherwise"; - Value operand = operandFor(operandNum); + AllocatableValue operand = operandFor(operandNum); if (GraalOptions.TraceLinearScanLevel >= 2) { TTY.println("live in %s to %d", operand, blockTo + 2); } @@ -1197,7 +1197,7 @@ @Override public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { - addDef(operand, opId, registerPriorityOfOutputOperand(op), operand.getKind().getStackKind()); + addDef((AllocatableValue) operand, opId, registerPriorityOfOutputOperand(op), operand.getKind().getStackKind()); addRegisterHint(op, operand, mode, flags, true); } return operand; @@ -1208,7 +1208,7 @@ @Override public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { - addTemp(operand, opId, RegisterPriority.MustHaveRegister, operand.getKind().getStackKind()); + addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getKind().getStackKind()); addRegisterHint(op, operand, mode, flags, false); } return operand; @@ -1220,7 +1220,7 @@ public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse(operand, blockFrom, opId + 1, p, operand.getKind().getStackKind()); + addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getKind().getStackKind()); addRegisterHint(op, operand, mode, flags, false); } return operand; @@ -1232,7 +1232,7 @@ public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse(operand, blockFrom, opId, p, operand.getKind().getStackKind()); + addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getKind().getStackKind()); addRegisterHint(op, operand, mode, flags, false); } return operand; @@ -1247,7 +1247,7 @@ @Override public Value doValue(Value operand) { - addUse(operand, blockFrom, opId + 1, RegisterPriority.None, operand.getKind().getStackKind()); + addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getKind().getStackKind()); return operand; } }); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Sun Apr 28 22:52:12 2013 +0200 @@ -196,8 +196,8 @@ assert fromInterval.kind() == toInterval.kind() : "move between different types"; assert insertIdx != -1 : "must setup insert position first"; - Value fromOpr = fromInterval.operand; - Value toOpr = toInterval.operand; + AllocatableValue fromOpr = fromInterval.operand; + AllocatableValue toOpr = toInterval.operand; insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr)); @@ -210,7 +210,7 @@ assert fromOpr.getKind() == toInterval.kind() : "move between different types"; assert insertIdx != -1 : "must setup insert position first"; - Value toOpr = toInterval.operand; + AllocatableValue toOpr = toInterval.operand; insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr)); if (GraalOptions.TraceLinearScanLevel >= 4) { diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Sun Apr 28 22:52:12 2013 +0200 @@ -52,7 +52,7 @@ /** * This class traverses the HIR instructions and generates LIR instructions from them. */ -public abstract class LIRGenerator extends LIRGeneratorTool { +public abstract class LIRGenerator implements LIRGeneratorTool { public final FrameMap frameMap; public final NodeMap nodeOperands; @@ -168,8 +168,8 @@ @Override public Value setResult(ValueNode x, Value operand) { - assert (isVariable(operand) && x.kind() == operand.getKind()) || (isRegister(operand) && !attributes(asRegister(operand)).isAllocatable()) || - (isConstant(operand) && x.kind() == operand.getKind().getStackKind()) : operand.getKind() + " for node " + x; + assert (!isVariable(operand) || x.kind() == operand.getKind()) : operand.getKind() + " for node " + x; + assert (!isRegister(operand) || !attributes(asRegister(operand)).isAllocatable()); assert operand(x) == null : "operand cannot be set twice"; assert operand != null && isLegal(operand) : "operand must be legal"; assert operand.getKind().getStackKind() == x.kind() : operand.getKind().getStackKind() + " must match " + x.kind(); @@ -251,7 +251,7 @@ * @return the operand representing the ABI defined location used return a value of kind * {@code kind} */ - public Value resultOperandFor(Kind kind) { + public AllocatableValue resultOperandFor(Kind kind) { if (kind == Kind.Void) { return ILLEGAL; } @@ -461,7 +461,7 @@ @Override public void visitReturn(ReturnNode x) { - Value operand = Value.ILLEGAL; + AllocatableValue operand = ILLEGAL; if (x.result() != null) { operand = resultOperandFor(x.result().kind()); emitMove(operand, operand(x.result())); @@ -630,7 +630,7 @@ protected abstract void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info); - protected static Value toStackKind(Value value) { + protected static AllocatableValue toStackKind(AllocatableValue value) { if (value.getKind().getStackKind() != value.getKind()) { // We only have stack-kinds in the LIR, so convert the operand kind for values from the // calling convention. @@ -651,7 +651,7 @@ int j = 0; for (ValueNode arg : arguments) { if (arg != null) { - Value operand = toStackKind(cc.getArgument(j)); + AllocatableValue operand = toStackKind(cc.getArgument(j)); emitMove(operand, operand(arg)); result[j] = operand; j++; @@ -672,7 +672,7 @@ Value[] argLocations = new Value[args.length]; for (int i = 0; i < args.length; i++) { Value arg = args[i]; - Value loc = cc.getArgument(i); + AllocatableValue loc = cc.getArgument(i); emitMove(loc, arg); argLocations[i] = loc; } @@ -826,6 +826,10 @@ return frameMap; } + @Override + public void beforeRegisterAllocation() { + } + public abstract void emitBitCount(Variable result, Value operand); public abstract void emitBitScanForward(Variable result, Value operand); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,9 +22,9 @@ */ package com.oracle.graal.compiler.gen; +import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.api.meta.Value.*; import static com.oracle.graal.lir.LIRValueUtil.*; -import static com.oracle.graal.api.code.ValueUtil.*; import java.util.*; @@ -187,7 +187,7 @@ private void emitMove(Value dest, Value src) { assert isLegal(src); assert isLegal(dest); - gen.emitMove(dest, src); + gen.emitMove((AllocatableValue) dest, src); } // Traverse assignment graph in depth first order and generate moves in post order diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Sun Apr 28 22:52:12 2013 +0200 @@ -34,16 +34,10 @@ public HighTier() { if (GraalOptions.FullUnroll) { addPhase(new LoopFullUnrollPhase()); - if (GraalOptions.OptCanonicalizer) { - addPhase(new CanonicalizerPhase()); - } } if (GraalOptions.OptTailDuplication) { addPhase(new TailDuplicationPhase()); - if (GraalOptions.OptCanonicalizer) { - addPhase(new CanonicalizerPhase()); - } } if (GraalOptions.PartialEscapeAnalysis) { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraalInternalError.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraalInternalError.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraalInternalError.java Sun Apr 28 22:52:12 2013 +0200 @@ -51,6 +51,23 @@ } /** + * Checks a given condition and throws a {@link GraalInternalError} if it is false. Guarantees + * are stronger than assertions in that they are always checked. Error messages for guarantee + * violations should clearly indicate the nature of the problem as well as a suggested solution + * if possible. + * + * @param condition the condition to check + * @param msg the message that will be associated with the error, in + * {@link String#format(String, Object...)} syntax + * @param args arguments to the format string + */ + public static void guarantee(boolean condition, String msg, Object... args) { + if (!condition) { + throw new GraalInternalError("failed guarantee: " + msg, args); + } + } + + /** * This constructor creates a {@link GraalInternalError} with a message assembled via * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to * always generate the same output. diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Sun Apr 28 22:52:12 2013 +0200 @@ -47,7 +47,8 @@ private int deletedNodeCount; private GraphEventLog eventLog; - InputChangedListener inputChanged; + NodeChangedListener inputChanged; + NodeChangedListener usagesDroppedZero; private final HashMap cachedNodes = new HashMap<>(); private static final class CacheEntry { @@ -152,12 +153,12 @@ return node; } - public interface InputChangedListener { + public interface NodeChangedListener { - void inputChanged(Node node); + void nodeChanged(Node node); } - public void trackInputChange(InputChangedListener inputChangedListener) { + public void trackInputChange(NodeChangedListener inputChangedListener) { this.inputChanged = inputChangedListener; } @@ -165,6 +166,14 @@ inputChanged = null; } + public void trackUsagesDroppedZero(NodeChangedListener usagesDroppedZeroListener) { + this.usagesDroppedZero = usagesDroppedZeroListener; + } + + public void stopTrackingUsagesDroppedZero() { + usagesDroppedZero = null; + } + /** * Adds a new node to the graph, if a similar node already exists in the graph, the * provided node will not be added to the graph but the similar node will be returned diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Sun Apr 28 22:52:12 2013 +0200 @@ -25,7 +25,7 @@ import java.lang.annotation.*; import java.util.*; -import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.graph.NodeClass.*; import com.oracle.graal.graph.iterators.*; @@ -193,12 +193,17 @@ assert assertTrue(result, "not found in usages, old input: %s", oldInput); } if (newInput != null) { - InputChangedListener inputChanged = graph.inputChanged; + NodeChangedListener inputChanged = graph.inputChanged; if (inputChanged != null) { - inputChanged.inputChanged(this); + inputChanged.nodeChanged(this); } assert newInput.usages != null : "not yet added? " + newInput; newInput.usages.add(this); + } else if (oldInput != null && oldInput.usages().isEmpty()) { + NodeChangedListener nodeChangedListener = graph.usagesDroppedZero; + if (nodeChangedListener != null) { + nodeChangedListener.nodeChanged(oldInput); + } } } } @@ -253,9 +258,9 @@ boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); assert assertTrue(result, "not found in inputs, usage: %s", usage); if (other != null) { - InputChangedListener inputChanged = graph.inputChanged; + NodeChangedListener inputChanged = graph.inputChanged; if (inputChanged != null) { - inputChanged.inputChanged(usage); + inputChanged.nodeChanged(usage); } other.usages.add(usage); } @@ -299,6 +304,12 @@ for (Node input : inputs()) { removeThisFromUsages(input); + if (input.usages().isEmpty()) { + NodeChangedListener nodeChangedListener = graph.usagesDroppedZero; + if (nodeChangedListener != null) { + nodeChangedListener.nodeChanged(input); + } + } } getNodeClass().clearInputs(this); } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.amd64; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; @@ -49,7 +51,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - HotSpotGraalRuntime runtime = HotSpotGraalRuntime.getInstance(); + 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(DEOPTIMIZE), null, false, info); diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Sun Apr 28 22:52:12 2013 +0200 @@ -45,6 +45,7 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ParametersOp; import com.oracle.graal.lir.LIRInstruction.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; @@ -161,28 +162,59 @@ Stub stub = runtime().asStub(lirGen.method()); if (stub != null) { - final Set definedRegisters = new HashSet<>(); - ValueProcedure defProc = new ValueProcedure() { + + List registerPreservations = new ArrayList<>(); + final Set definedRegisters = gatherDefinedRegisters(lir, registerPreservations); + stub.initDefinedRegisters(definedRegisters); + + // Eliminate unnecessary register preservation + for (AMD64RegisterPreservationOp op : registerPreservations) { + op.doNotPreserve(definedRegisters); + } + + // Record where preserved registers are saved + for (Map.Entry e : gen.calleeSaveInfo.entrySet()) { + e.getValue().describePreservation(e.getKey().debugInfo(), frameMap); + } + } + + return tasm; + } - @Override - public Value doValue(Value value) { - if (ValueUtil.isRegister(value)) { - final Register reg = ValueUtil.asRegister(value); - definedRegisters.add(reg); - } - return value; + /** + * Finds all the registers that are defined by some given LIR. + * + * @param lir the LIR to examine + * @param registerPreservations register preservation operations in {@code lir} are added to this list + * @return the registers that are defined by or used as temps for any instruction in {@code lir} + */ + private static Set gatherDefinedRegisters(LIR lir, List registerPreservations) { + final Set definedRegisters = new HashSet<>(); + ValueProcedure defProc = new ValueProcedure() { + + @Override + public Value doValue(Value value) { + if (ValueUtil.isRegister(value)) { + final Register reg = ValueUtil.asRegister(value); + definedRegisters.add(reg); } - }; - for (Block block : lir.codeEmittingOrder()) { - for (LIRInstruction op : lir.lir(block)) { + return value; + } + }; + for (Block block : lir.codeEmittingOrder()) { + for (LIRInstruction op : lir.lir(block)) { + if (op instanceof AMD64RegisterPreservationOp) { + // Don't consider these ops as definitions + registerPreservations.add((AMD64RegisterPreservationOp) op); + } else if (op instanceof ParametersOp) { + // Don't consider these ops as definitions + } else { op.forEachTemp(defProc); op.forEachOutput(defProc); } } - stub.initDefinedRegisters(definedRegisters); } - - return tasm; + return definedRegisters; } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,52 @@ +/* + * 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.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +@Opcode("CRUNTIME_CALL_EPILOGUE") +final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction { + + @Use({REG, ILLEGAL}) protected Value thread; + + AMD64HotSpotCRuntimeCallEpilogueOp(Value thread) { + this.thread = thread; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + // reset last Java frame: + HotSpotVMConfig config = graalRuntime().getConfig(); + masm.movslq(new AMD64Address(asRegister(thread), config.threadLastJavaSpOffset), 0); + masm.movslq(new AMD64Address(asRegister(thread), config.threadLastJavaFpOffset), 0); + } +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,51 @@ +/* + * 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.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +@Opcode("CRUNTIME_CALL_PROLOGUE") +final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction { + + @Use({REG, ILLEGAL}) protected Value thread; + + AMD64HotSpotCRuntimeCallPrologueOp(Value thread) { + this.thread = thread; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + + // save last Java frame + masm.movq(new AMD64Address(asRegister(thread), graalRuntime().getConfig().threadLastJavaSpOffset), rsp); + } +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,71 @@ +/* + * 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.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.amd64.AMD64DeoptimizeOp.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@Opcode("DEOPT_CALLER") +final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp { + + private final DeoptimizationAction action; + private final DeoptimizationReason reason; + + AMD64HotSpotDeoptimizeCallerOp(DeoptimizationAction action, DeoptimizationReason reason) { + this.action = action; + this.reason = reason; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + if (isStackSlot(savedRbp)) { + // Restoring RBP from the stack must be done before the frame is removed + masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp)); + } else { + Register framePointer = asRegister(savedRbp); + if (framePointer != rbp) { + masm.movq(rbp, framePointer); + } + } + if (tasm.frameContext != null) { + tasm.frameContext.leave(tasm); + } + 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(DEOPTIMIZE)); + } +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java Sun Apr 28 22:52:12 2013 +0200 @@ -39,10 +39,10 @@ * Called from C++ code to retrieve the singleton instance, creating it first if necessary. */ public static HotSpotGraalRuntime makeInstance() { - if (getInstance() == null) { + if (graalRuntime() == null) { setInstance(new AMD64HotSpotGraalRuntime()); } - return getInstance(); + return graalRuntime(); } @Override diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Sun Apr 28 22:52:12 2013 +0200 @@ -27,6 +27,7 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*; +import java.lang.reflect.*; import java.util.*; import com.oracle.graal.amd64.*; @@ -144,8 +145,8 @@ } } params[params.length - 1] = rbpParam; + ParametersOp paramsOp = new ParametersOp(params); - ParametersOp paramsOp = new ParametersOp(params); append(paramsOp); saveRbp = new SaveRbp(new PlaceholderOp(currentBlock, lir.lir(currentBlock).size())); @@ -171,6 +172,74 @@ return runtime().asStub(method) != null; } + /** + * Map from debug infos that need to be updated with callee save information to the operations + * that provide the information. + */ + Map calleeSaveInfo = new HashMap<>(); + + private LIRFrameState currentRuntimeCallInfo; + + @Override + protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + boolean needsCalleeSave = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall(); + if (needsCalleeSave) { + currentRuntimeCallInfo = info; + } + super.emitCall(callTarget, result, arguments, temps, info); + } + + @Override + public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args) { + boolean needsCalleeSave = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall(); + + RegisterValue[] savedRegisters = null; + StackSlot[] savedRegisterLocations = null; + if (needsCalleeSave) { + Register returnReg = isRegister(cc.getReturn()) ? asRegister(cc.getReturn()) : null; + Set registers = new HashSet<>(Arrays.asList(frameMap.registerConfig.getAllocatableRegisters())); + if (returnReg != null) { + registers.remove(returnReg); + } + + savedRegisters = new RegisterValue[registers.size()]; + savedRegisterLocations = new StackSlot[savedRegisters.length]; + int savedRegisterIndex = 0; + for (Register reg : registers) { + assert reg.isCpu() || reg.isFpu(); + savedRegisters[savedRegisterIndex++] = reg.asValue(reg.isCpu() ? Kind.Long : Kind.Double); + } + + append(new ParametersOp(savedRegisters)); + for (int i = 0; i < savedRegisters.length; i++) { + StackSlot spillSlot = frameMap.allocateSpillSlot(Kind.Long); + savedRegisterLocations[i] = spillSlot; + } + AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations); + append(save); + + Value thread = args[0]; + AMD64HotSpotCRuntimeCallPrologueOp op = new AMD64HotSpotCRuntimeCallPrologueOp(thread); + append(op); + } + + Variable result = super.emitCall(callTarget, cc, info, args); + + if (needsCalleeSave) { + + Value thread = args[0]; + AMD64HotSpotCRuntimeCallEpilogueOp op = new AMD64HotSpotCRuntimeCallEpilogueOp(thread); + append(op); + + AMD64RestoreRegistersOp restore = new AMD64RestoreRegistersOp(savedRegisterLocations.clone(), savedRegisters.clone()); + AMD64RestoreRegistersOp oldValue = calleeSaveInfo.put(currentRuntimeCallInfo, restore); + assert oldValue == null; + append(restore); + } + + return result; + } + @Override protected CallingConvention createCallingConvention() { Stub stub = runtime().asStub(method); @@ -223,7 +292,6 @@ @Override public void emitTailcall(Value[] args, Value address) { append(new AMD64TailcallOp(args, address)); - } @Override @@ -234,6 +302,7 @@ } else { assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special; HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target(); + assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method."; Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant(); append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod)); } @@ -241,9 +310,9 @@ @Override protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - Value metaspaceMethod = AMD64.rbx.asValue(); + AllocatableValue metaspaceMethod = AMD64.rbx.asValue(); emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod())); - Value targetAddress = AMD64.rax.asValue(); + AllocatableValue targetAddress = AMD64.rax.asValue(); emitMove(targetAddress, operand(callTarget.computedAddress())); append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); } @@ -263,6 +332,13 @@ } @Override + public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { + AMD64HotSpotDeoptimizeCallerOp op = new AMD64HotSpotDeoptimizeCallerOp(action, reason); + epilogueOps.add(op); + append(op); + } + + @Override public void beforeRegisterAllocation() { boolean hasDebugInfo = lir.hasDebugInfo(); AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Sun Apr 28 22:52:12 2013 +0200 @@ -143,7 +143,7 @@ } private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { - Value[] locations = new Value[parameterTypes.length]; + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; int currentGeneral = 0; int currentXMM = 0; @@ -183,7 +183,7 @@ } Kind returnKind = returnType == null ? Kind.Void : returnType.getKind(); - Value returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind); + AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind); return new CallingConvention(currentStackOffset, returnLocation, locations); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -33,7 +33,7 @@ import com.oracle.graal.lir.asm.*; /** - * Performs an unwind to throw an exception. + * Returns from a function. */ @Opcode("RETURN") final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp { diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Sun Apr 28 22:52:12 2013 +0200 @@ -29,9 +29,7 @@ import static com.oracle.graal.hotspot.nodes.IdentityHashCodeStubCall.*; import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*; import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*; -import static com.oracle.graal.hotspot.nodes.NewArraySlowStubCall.*; import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*; -import static com.oracle.graal.hotspot.nodes.NewInstanceSlowStubCall.*; import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*; import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*; @@ -43,6 +41,9 @@ 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.stubs.NewArrayStub.*; +import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; +import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*; import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; @@ -110,28 +111,37 @@ /* arg0: hub */ rdx.asValue(word), /* arg1: length */ rbx.asValue(Kind.Int)); - addRuntimeCall(NEW_ARRAY_SLOW, config.newArrayStub, + addRuntimeCall(NEW_ARRAY_C, config.newArrayAddress, /* temps */ null, - /* ret */ rax.asValue(Kind.Object), - /* arg0: hub */ rdx.asValue(word), - /* arg1: length */ rbx.asValue(Kind.Int)); + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: hub */ word, + /* arg2: length */ Kind.Int)); addStubCall(NEW_INSTANCE, /* ret */ rax.asValue(Kind.Object), /* arg0: hub */ rdx.asValue(word)); - addRuntimeCall(NEW_INSTANCE_SLOW, config.newInstanceStub, + addRuntimeCall(NEW_INSTANCE_C, config.newInstanceAddress, /* temps */ null, - /* ret */ rax.asValue(Kind.Object), - /* arg0: hub */ rdx.asValue(word)); + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: hub */ word)); - addRuntimeCall(NEW_MULTI_ARRAY, config.newMultiArrayStub, - /* temps */ null, + addStubCall(NEW_MULTI_ARRAY, /* ret */ rax.asValue(Kind.Object), /* arg0: hub */ rax.asValue(word), /* arg1: rank */ rbx.asValue(Kind.Int), /* arg2: dims */ rcx.asValue(word)); + addRuntimeCall(NEW_MULTI_ARRAY_C, config.newMultiArrayAddress, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: hub */ word, + /* arg2: rank */ Kind.Int, + /* arg3: dims */ word)); + addRuntimeCall(VERIFY_OOP, config.verifyOopStub, /* temps */ null, /* ret */ ret(Kind.Void), diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.amd64.*; 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.amd64.*; import com.oracle.graal.lir.LIRInstruction.Opcode; import com.oracle.graal.lir.amd64.*; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -27,6 +27,7 @@ import sun.misc.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.*; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime.java Sun Apr 28 22:52:12 2013 +0200 @@ -38,10 +38,10 @@ * Called from C++ code to retrieve the singleton instance, creating it first if necessary. */ public static HotSpotGraalRuntime makeInstance() { - if (getInstance() == null) { + if (graalRuntime() == null) { setInstance(new SPARCHotSpotGraalRuntime()); } - return getInstance(); + return graalRuntime(); } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -50,7 +52,7 @@ public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path"; // Some runtime instances we need. - private final HotSpotGraalRuntime graalRuntime = HotSpotGraalRuntime.getInstance(); + private final HotSpotGraalRuntime graalRuntime = graalRuntime(); private final VMToCompilerImpl vmToCompiler = (VMToCompilerImpl) graalRuntime.getVMToCompiler(); /** List of Zip/Jar files to compile (see {@link GraalOptions#CompileTheWorld}. */ diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import java.io.*; import java.util.concurrent.*; @@ -59,7 +61,7 @@ public void run() { GraalDebugConfig hotspotDebugConfig = null; if (GraalOptions.Debug) { - PrintStream log = HotSpotGraalRuntime.getInstance().getVMToCompiler().log(); + PrintStream log = graalRuntime().getVMToCompiler().log(); DebugEnvironment.initialize(log); } try { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,11 +22,17 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import java.util.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.CompilationResult.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.code.CompilationResult.ExceptionHandler; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.replacements.*; /** * Augments a {@link CompilationResult} with HotSpot-specific information. @@ -37,7 +43,12 @@ public final CompilationResult comp; public final HotSpotResolvedJavaMethod method; // used only for methods public final int entryBCI; // used only for methods - public final String name; // used only for stubs + + /** + * Name of the RuntimeStub to be installed for this compilation result. If null, then the + * compilation result will be installed as an nmethod. + */ + public final String stubName; public final Site[] sites; public final ExceptionHandler[] exceptionHandlers; @@ -46,7 +57,12 @@ this.method = method; this.comp = comp; this.entryBCI = entryBCI; - this.name = null; + + if (graalRuntime().getRuntime().lookupJavaType(Stub.class).isAssignableFrom(method.getDeclaringClass()) && method.getAnnotation(Snippet.class) != null) { + this.stubName = MetaUtil.format("%h.%n", method); + } else { + this.stubName = null; + } sites = getSortedSites(comp); if (comp.getExceptionHandlers() == null) { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Sun Apr 28 22:52:12 2013 +0200 @@ -47,9 +47,9 @@ private static HotSpotGraalRuntime instance; /** - * Gets the singleton runtime instance object. + * Gets the singleton {@link HotSpotGraalRuntime} object. */ - public static HotSpotGraalRuntime getInstance() { + public static HotSpotGraalRuntime graalRuntime() { return instance; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Sun Apr 28 22:52:12 2013 +0200 @@ -42,6 +42,8 @@ */ void emitTailcall(Value[] args, Value address); + void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason); + void visitDirectCompareAndSwap(DirectCompareAndSwapNode x); /** diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Sun Apr 28 22:52:12 2013 +0200 @@ -46,7 +46,7 @@ private long address; /** - * Non-null (eventually) iff this is a call to a snippet-based {@linkplain Stub stub}. + * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}. */ private Stub stub; @@ -91,13 +91,13 @@ assert stub != null : "linkage without an address must be a stub"; InstalledCode code = stub.getCode(backend); - Value[] argumentLocations = new Value[cc.getArgumentCount()]; + AllocatableValue[] argumentLocations = new AllocatableValue[cc.getArgumentCount()]; for (int i = 0; i < argumentLocations.length; i++) { argumentLocations[i] = cc.getArgument(i); } Set definedRegisters = stub.getDefinedRegisters(); - Value[] temporaryLocations = new Value[definedRegisters.size()]; + AllocatableValue[] temporaryLocations = new AllocatableValue[definedRegisters.size()]; int i = 0; for (Register reg : definedRegisters) { temporaryLocations[i++] = reg.asValue(); @@ -113,4 +113,12 @@ assert address != 0; return true; } + + /** + * Determines if this is a link to a C/C++ function in the HotSpot runtime. + */ + public boolean isCRuntimeCall() { + HotSpotVMConfig config = HotSpotGraalRuntime.graalRuntime().getConfig(); + return address == config.newArrayAddress || address == config.newInstanceAddress || address == config.newMultiArrayAddress; + } } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Sun Apr 28 22:52:12 2013 +0200 @@ -179,6 +179,11 @@ public int uninitializedIdentityHashCodeValue; /** + * Offset of the pending exception field. + */ + public int pendingExceptionOffset; + + /** * Offset of the pending deoptimization field. */ public int pendingDeoptimizationOffset; @@ -302,6 +307,10 @@ public int threadTlabStartOffset; public int threadTlabSizeOffset; public int threadAllocatedBytesOffset; + public int threadLastJavaSpOffset; + public int threadLastJavaFpOffset; + public int threadLastJavaPcOffset; + public int threadObjectResultOffset; public int tlabRefillWasteLimitOffset; public int tlabRefillWasteIncrement; public int tlabAlignmentReserve; @@ -334,9 +343,6 @@ public int typeProfileWidth; // runtime stubs - public long newInstanceStub; - public long newArrayStub; - public long newMultiArrayStub; public long inlineCacheMissStub; public long handleExceptionStub; public long handleDeoptStub; @@ -372,6 +378,10 @@ public long cipherBlockChainingEncryptAESCryptStub; public long cipherBlockChainingDecryptAESCryptStub; + public long newInstanceAddress; + public long newArrayAddress; + public long newMultiArrayAddress; + public int deoptReasonNullCheck; public int deoptReasonRangeCheck; public int deoptReasonClassCheck; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Sun Apr 28 22:52:12 2013 +0200 @@ -194,20 +194,20 @@ long getMaxCallTargetOffset(long stub); - String disassembleNMethod(long nmethod); + String disassembleCodeBlob(long codeBlob); /** - * Gets a copy of the machine code for an nmethod. + * Gets a copy of the machine code for a CodeBlob. * - * @return the machine code for {@code nmethod} if it is valid, null otherwise + * @return the machine code for {@code codeBlob} if it is valid, null otherwise */ - byte[] getCode(long nmethod); + byte[] getCode(long codeBlob); StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); - Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException; + Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException; - Object executeCompiledMethodVarargs(Object[] args, long nativeMethod) throws InvalidInstalledCodeException; + Object executeCompiledMethodVarargs(Object[] args, long nmethod) throws InvalidInstalledCodeException; int getVtableEntryOffset(long metaspaceMethod); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Sun Apr 28 22:52:12 2013 +0200 @@ -130,16 +130,16 @@ public native long getMaxCallTargetOffset(long stub); @Override - public native String disassembleNMethod(long nmethod); + public native String disassembleCodeBlob(long codeBlob); @Override - public native byte[] getCode(long nmethod); + public native byte[] getCode(long codeBlob); @Override public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); @Override - public native Object executeCompiledMethodVarargs(Object[] args, long nativeMethod); + public native Object executeCompiledMethodVarargs(Object[] args, long nmethod); @Override public native int getVtableEntryOffset(long metaspaceMethod); @@ -172,16 +172,16 @@ public native boolean isInstalledCodeValid(long nativeMethod); @Override - public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException { - return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nativeMethod); + public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException { + return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nmethod); } /** - * Direct call to the given nativeMethod with three object arguments and an object return value. - * This method does not have an implementation on the C++ side, but its entry points (from + * Direct call to the given nmethod with three object arguments and an object return value. This + * method does not have an implementation on the C++ side, but its entry points (from * interpreter and from compiled code) are directly pointing to a manually generated assembly * stub that does the necessary argument shuffling and a tail call via an indirect jump to the * verified entry point of the given native method. */ - private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nativeMethod); + private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nmethod); } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Sun Apr 28 22:52:12 2013 +0200 @@ -25,6 +25,7 @@ import static com.oracle.graal.graph.UnsafeAccess.*; import static com.oracle.graal.hotspot.CompilationTask.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.java.GraphBuilderPhase.*; import static com.oracle.graal.phases.common.InliningUtil.*; @@ -686,7 +687,7 @@ public HotSpotResolvedObjectType createResolvedJavaType(long metaspaceKlass, String name, String simpleName, Class javaMirror, int sizeOrSpecies) { HotSpotResolvedObjectType type = new HotSpotResolvedObjectType(metaspaceKlass, name, simpleName, javaMirror, sizeOrSpecies); - long offset = HotSpotGraalRuntime.getInstance().getConfig().graalMirrorInClassOffset; + long offset = graalRuntime().getConfig().graalMirrorInClassOffset; if (!unsafe.compareAndSwapObject(javaMirror, offset, null, type)) { // lost the race - return the existing value instead type = (HotSpotResolvedObjectType) unsafe.getObject(javaMirror, offset); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.hotspot.debug; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; public class LocalImpl implements Local { @@ -39,9 +40,9 @@ this.bciStart = bciStart; this.bciEnd = bciEnd; this.slot = slot; - JavaType t = HotSpotGraalRuntime.getInstance().lookupType(type, holder, true); + JavaType t = graalRuntime().lookupType(type, holder, true); if (t instanceof ResolvedJavaType) { - this.resolvedType = (ResolvedJavaType) HotSpotGraalRuntime.getInstance().lookupType(type, holder, false); + this.resolvedType = (ResolvedJavaType) graalRuntime().lookupType(type, holder, false); } else { throw new AssertionError(t.getClass() + " is not a ResolvedJavaType"); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.bytecode.*; import com.oracle.graal.hotspot.*; @@ -41,13 +43,13 @@ @Override public int length() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().constantPoolLength(type); + return graalRuntime().getCompilerToVM().constantPoolLength(type); } @Override public Object lookupConstant(int cpi) { assert cpi != 0; - Object constant = HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupConstantInPool(type, cpi); + Object constant = graalRuntime().getCompilerToVM().lookupConstantInPool(type, cpi); return constant; } @@ -59,26 +61,26 @@ @Override public Object lookupAppendix(int cpi, int opcode) { assert Bytecodes.isInvoke(opcode); - return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupAppendixInPool(type, cpi, (byte) opcode); + return graalRuntime().getCompilerToVM().lookupAppendixInPool(type, cpi, (byte) opcode); } @Override public JavaMethod lookupMethod(int cpi, int opcode) { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupMethodInPool(type, cpi, (byte) opcode); + return graalRuntime().getCompilerToVM().lookupMethodInPool(type, cpi, (byte) opcode); } @Override public JavaType lookupType(int cpi, int opcode) { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupTypeInPool(type, cpi); + return graalRuntime().getCompilerToVM().lookupTypeInPool(type, cpi); } @Override public JavaField lookupField(int cpi, int opcode) { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupFieldInPool(type, cpi, (byte) opcode); + return graalRuntime().getCompilerToVM().lookupFieldInPool(type, cpi, (byte) opcode); } @Override public void loadReferencedType(int cpi, int opcode) { - HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupReferencedTypeInPool(type, cpi, (byte) opcode); + graalRuntime().getCompilerToVM().lookupReferencedTypeInPool(type, cpi, (byte) opcode); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import java.lang.reflect.*; import com.oracle.graal.api.code.*; @@ -41,8 +43,9 @@ private final HotSpotResolvedJavaMethod method; private final boolean isDefault; private final Graph graph; - long nmethod; + long codeBlob; long start; + boolean isNmethod; public HotSpotInstalledCode(HotSpotResolvedJavaMethod method, Graph graph, boolean isDefault) { this.method = method; @@ -54,8 +57,8 @@ return isDefault; } - public long getMethodAddress() { - return nmethod; + public long getCodeBlob() { + return codeBlob; } public Graph getGraph() { @@ -69,26 +72,29 @@ @Override public boolean isValid() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().isInstalledCodeValid(nmethod); + return !isNmethod || graalRuntime().getCompilerToVM().isInstalledCodeValid(codeBlob); } @Override public void invalidate() { - HotSpotGraalRuntime.getInstance().getCompilerToVM().invalidateInstalledCode(nmethod); + if (isNmethod) { + graalRuntime().getCompilerToVM().invalidateInstalledCode(codeBlob); + } } @Override public String toString() { - return String.format("InstalledCode[method=%s, nmethod=0x%x]", method, nmethod); + return String.format("InstalledCode[method=%s, codeBlob=0x%x]", method, codeBlob); } @Override public Object execute(Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException { + assert isNmethod; assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3; assert method.getSignature().getParameterKind(0) == Kind.Object; assert method.getSignature().getParameterKind(1) == Kind.Object; assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object; - return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, nmethod); + return graalRuntime().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, codeBlob); } private boolean checkArgs(Object... args) { @@ -107,8 +113,9 @@ @Override public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + assert isNmethod; assert checkArgs(args); - return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethodVarargs(args, nmethod); + return graalRuntime().getCompilerToVM().executeCompiledMethodVarargs(args, codeBlob); } @Override @@ -118,6 +125,6 @@ @Override public byte[] getCode() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCode(nmethod); + return graalRuntime().getCompilerToVM().getCode(codeBlob); } } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Sun Apr 28 22:52:12 2013 +0200 @@ -40,7 +40,7 @@ private static final long serialVersionUID = -8873133496591225071L; - private static final HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + private static final HotSpotVMConfig config = graalRuntime().getConfig(); private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE); private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN); @@ -58,7 +58,7 @@ HotSpotMethodData(long metaspaceMethodData) { this.metaspaceMethodData = metaspaceMethodData; - HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeMethodData(metaspaceMethodData, this); + graalRuntime().getCompilerToVM().initializeMethodData(metaspaceMethodData, this); } public boolean hasNormalData() { @@ -78,7 +78,7 @@ } public int getDeoptimizationCount(DeoptimizationReason reason) { - int reasonIndex = HotSpotGraalRuntime.getInstance().getRuntime().convertDeoptReason(reason); + int reasonIndex = graalRuntime().getRuntime().convertDeoptReason(reason); return unsafe.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,6 +24,7 @@ package com.oracle.graal.hotspot.meta; import static com.oracle.graal.api.meta.MetaUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import java.lang.annotation.*; import java.lang.reflect.*; @@ -109,12 +110,12 @@ if (receiver == null) { assert Modifier.isStatic(flags); if (holder.isInitialized()) { - return HotSpotGraalRuntime.getInstance().getRuntime().readUnsafeConstant(getKind(), holder.mirror(), offset); + return graalRuntime().getRuntime().readUnsafeConstant(getKind(), holder.mirror(), offset); } return null; } else { assert !Modifier.isStatic(flags); - return HotSpotGraalRuntime.getInstance().getRuntime().readUnsafeConstant(getKind(), receiver.asObject(), offset); + return graalRuntime().getRuntime().readUnsafeConstant(getKind(), receiver.asObject(), offset); } } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Sun Apr 28 22:52:12 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.meta; import static com.oracle.graal.api.meta.MetaUtil.*; -import static com.oracle.graal.graph.FieldIntrospection.*; +import static com.oracle.graal.graph.UnsafeAccess.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import java.lang.annotation.*; @@ -66,7 +66,7 @@ HotSpotResolvedJavaMethod(HotSpotResolvedObjectType holder, long metaspaceMethod) { this.metaspaceMethod = metaspaceMethod; this.holder = holder; - HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeMethod(metaspaceMethod, this); + graalRuntime().getCompilerToVM().initializeMethod(metaspaceMethod, this); } @Override @@ -82,12 +82,17 @@ * Gets the address of the C++ Method object for this method. */ public Constant getMetaspaceMethodConstant() { - return Constant.forIntegerKind(HotSpotGraalRuntime.getInstance().getTarget().wordKind, metaspaceMethod, this); + return Constant.forIntegerKind(graalRuntime().getTarget().wordKind, metaspaceMethod, this); + } + + @Override + public Constant getEncoding() { + return getMetaspaceMethodConstant(); } @Override public int getModifiers() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset) & Modifier.methodModifiers(); } @@ -103,7 +108,7 @@ return null; } if (code == null) { - code = HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeBytecode(metaspaceMethod, new byte[codeSize]); + code = graalRuntime().getCompilerToVM().initializeBytecode(metaspaceMethod, new byte[codeSize]); assert code.length == codeSize : "expected: " + codeSize + ", actual: " + code.length; } return code; @@ -123,12 +128,12 @@ for (int i = 0; i < exceptionHandlerCount; i++) { handlers[i] = new ExceptionHandler(-1, -1, -1, -1, null); } - return HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeExceptionHandlers(metaspaceMethod, handlers); + return graalRuntime().getCompilerToVM().initializeExceptionHandlers(metaspaceMethod, handlers); } public boolean hasBalancedMonitors() { if (hasBalancedMonitors == null) { - hasBalancedMonitors = HotSpotGraalRuntime.getInstance().getCompilerToVM().hasBalancedMonitors(metaspaceMethod); + hasBalancedMonitors = graalRuntime().getCompilerToVM().hasBalancedMonitors(metaspaceMethod); } return hasBalancedMonitors; } @@ -145,14 +150,14 @@ @Override public int getMaxLocals() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset); return unsafe.getShort(metaspaceConstMethod + config.methodMaxLocalsOffset) & 0xFFFF; } @Override public int getMaxStackSize() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); long metaspaceConstMethod = unsafe.getLong(metaspaceMethod + config.methodConstMethodOffset); return config.extraStackEntries + (unsafe.getShort(metaspaceConstMethod + config.constMethodMaxStackOffset) & 0xFFFF); } @@ -161,15 +166,15 @@ public StackTraceElement asStackTraceElement(int bci) { if (bci < 0 || bci >= codeSize) { // HotSpot code can only construct stack trace elements for valid bcis - StackTraceElement ste = HotSpotGraalRuntime.getInstance().getCompilerToVM().getStackTraceElement(metaspaceMethod, 0); + StackTraceElement ste = graalRuntime().getCompilerToVM().getStackTraceElement(metaspaceMethod, 0); return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); } - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getStackTraceElement(metaspaceMethod, bci); + return graalRuntime().getCompilerToVM().getStackTraceElement(metaspaceMethod, bci); } public ResolvedJavaMethod uniqueConcreteMethod() { HotSpotResolvedObjectType[] resultHolder = {null}; - long ucm = HotSpotGraalRuntime.getInstance().getCompilerToVM().getUniqueConcreteMethod(metaspaceMethod, resultHolder); + long ucm = graalRuntime().getCompilerToVM().getUniqueConcreteMethod(metaspaceMethod, resultHolder); if (ucm != 0L) { assert resultHolder[0] != null; return resultHolder[0].createMethod(ucm); @@ -180,7 +185,7 @@ @Override public HotSpotSignature getSignature() { if (signature == null) { - signature = new HotSpotSignature(HotSpotGraalRuntime.getInstance().getCompilerToVM().getSignature(metaspaceMethod)); + signature = new HotSpotSignature(graalRuntime().getCompilerToVM().getSignature(metaspaceMethod)); } return signature; } @@ -191,11 +196,11 @@ } public int getCompiledCodeSize() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCompiledCodeSize(metaspaceMethod); + return graalRuntime().getCompilerToVM().getCompiledCodeSize(metaspaceMethod); } public int invocationCount() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getInvocationCount(metaspaceMethod); + return graalRuntime().getCompilerToVM().getInvocationCount(metaspaceMethod); } @Override @@ -219,7 +224,7 @@ ProfilingInfo info; if (GraalOptions.UseProfilingInformation && methodData == null) { - long metaspaceMethodData = unsafeReadWord(metaspaceMethod + HotSpotGraalRuntime.getInstance().getConfig().methodDataOffset); + long metaspaceMethodData = unsafeReadWord(metaspaceMethod + graalRuntime().getConfig().methodDataOffset); if (metaspaceMethodData != 0) { methodData = new HotSpotMethodData(metaspaceMethodData); } @@ -237,7 +242,7 @@ @Override public void reprofile() { - HotSpotGraalRuntime.getInstance().getCompilerToVM().reprofile(metaspaceMethod); + graalRuntime().getCompilerToVM().reprofile(metaspaceMethod); } @Override @@ -311,12 +316,12 @@ @Override public boolean canBeInlined() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().isMethodCompilable(metaspaceMethod); + return graalRuntime().getCompilerToVM().isMethodCompilable(metaspaceMethod); } @Override public LineNumberTable getLineNumberTable() { - long[] values = HotSpotGraalRuntime.getInstance().getCompilerToVM().getLineNumberTable(this); + long[] values = graalRuntime().getCompilerToVM().getLineNumberTable(this); assert values.length % 2 == 0; int[] bci = new int[values.length / 2]; int[] line = new int[values.length / 2]; @@ -331,7 +336,7 @@ @Override public LocalVariableTable getLocalVariableTable() { - Local[] locals = HotSpotGraalRuntime.getInstance().getCompilerToVM().getLocalVariableTable(this); + Local[] locals = graalRuntime().getCompilerToVM().getLocalVariableTable(this); return new LocalVariableTableImpl(locals); } @@ -345,7 +350,7 @@ if (!holder.isInitialized()) { return -1; } - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getVtableEntryOffset(metaspaceMethod); + return graalRuntime().getCompilerToVM().getVtableEntryOffset(metaspaceMethod); } public void setCurrentTask(CompilationTask task) { @@ -364,7 +369,7 @@ } public int intrinsicId() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); return unsafe.getByte(metaspaceMethod + config.methodIntrinsicIdOffset) & 0xff; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.*; public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { @@ -37,6 +38,6 @@ @Override public String getSourceFileName() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getFileName(this); + return graalRuntime().getCompilerToVM().getFileName(this); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Sun Apr 28 22:52:12 2013 +0200 @@ -98,7 +98,7 @@ */ public static ResolvedJavaType fromMetaspaceKlass(long metaspaceKlass) { assert metaspaceKlass != 0; - Class javaClass = (Class) unsafe.getObject(null, metaspaceKlass + HotSpotGraalRuntime.getInstance().getConfig().classMirrorOffset); + Class javaClass = (Class) unsafe.getObject(null, metaspaceKlass + graalRuntime().getConfig().classMirrorOffset); assert javaClass != null; return fromClass(javaClass); } @@ -110,9 +110,9 @@ */ public static ResolvedJavaType fromClass(Class javaClass) { assert javaClass != null; - ResolvedJavaType type = (ResolvedJavaType) unsafe.getObject(javaClass, (long) HotSpotGraalRuntime.getInstance().getConfig().graalMirrorInClassOffset); + ResolvedJavaType type = (ResolvedJavaType) unsafe.getObject(javaClass, (long) graalRuntime().getConfig().graalMirrorInClassOffset); if (type == null) { - type = HotSpotGraalRuntime.getInstance().getCompilerToVM().getResolvedType(javaClass); + type = graalRuntime().getCompilerToVM().getResolvedType(javaClass); assert type != null; } return type; @@ -140,7 +140,7 @@ } public int getAccessFlags() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); return unsafe.getInt(metaspaceKlass + config.klassAccessFlagsOffset); } @@ -160,11 +160,11 @@ @Override public ResolvedJavaType findUniqueConcreteSubtype() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); if (isArray()) { return isFinal(getElementalType(this).getModifiers()) ? this : null; } else if (isInterface()) { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getUniqueImplementor(this); + return graalRuntime().getCompilerToVM().getUniqueImplementor(this); } else { HotSpotResolvedObjectType type = this; while (isAbstract(type.getModifiers())) { @@ -258,12 +258,12 @@ @Override public boolean hasFinalizableSubclass() { assert !isArray(); - return HotSpotGraalRuntime.getInstance().getCompilerToVM().hasFinalizableSubclass(this); + return graalRuntime().getCompilerToVM().hasFinalizableSubclass(this); } @Override public boolean hasFinalizer() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); return (getAccessFlags() & config.klassHasFinalizerFlag) != 0; } @@ -280,7 +280,7 @@ @Override public boolean isInitialized() { if (!isInitialized) { - isInitialized = HotSpotGraalRuntime.getInstance().getCompilerToVM().isTypeInitialized(this); + isInitialized = graalRuntime().getCompilerToVM().isTypeInitialized(this); } return isInitialized; } @@ -288,7 +288,7 @@ @Override public void initialize() { if (!isInitialized) { - HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeType(this); + graalRuntime().getCompilerToVM().initializeType(this); } isInitialized = true; } @@ -328,7 +328,7 @@ @Override public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) { assert method instanceof HotSpotMethod; - return (ResolvedJavaMethod) HotSpotGraalRuntime.getInstance().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor()); + return (ResolvedJavaMethod) graalRuntime().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor()); } @Override @@ -411,7 +411,7 @@ if (isArray() || isInterface()) { instanceFields = new HotSpotResolvedJavaField[0]; } else { - HotSpotResolvedJavaField[] myFields = HotSpotGraalRuntime.getInstance().getCompilerToVM().getInstanceFields(this); + HotSpotResolvedJavaField[] myFields = graalRuntime().getCompilerToVM().getInstanceFields(this); Arrays.sort(myFields, new OffsetComparator()); if (javaMirror != Object.class) { HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); @@ -447,7 +447,7 @@ @Override public String getSourceFileName() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getFileName(this); + return graalRuntime().getCompilerToVM().getFileName(this); } @Override @@ -464,20 +464,20 @@ * Gets the address of the C++ Klass object for this type. */ public Constant klass() { - return Constant.forIntegerKind(HotSpotGraalRuntime.getInstance().getTarget().wordKind, metaspaceKlass, this); + return Constant.forIntegerKind(graalRuntime().getTarget().wordKind, metaspaceKlass, this); } public boolean isPrimaryType() { - return HotSpotGraalRuntime.getInstance().getConfig().secondarySuperCacheOffset != superCheckOffset(); + return graalRuntime().getConfig().secondarySuperCacheOffset != superCheckOffset(); } public int superCheckOffset() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); return unsafe.getInt(metaspaceKlass + config.superCheckOffsetOffset); } public long prototypeMarkWord() { - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); if (isArray()) { return config.arrayPrototypeMarkWord; } else { @@ -523,7 +523,7 @@ Constructor[] constructors = javaMirror.getDeclaredConstructors(); ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; for (int i = 0; i < constructors.length; i++) { - result[i] = HotSpotGraalRuntime.getInstance().getRuntime().lookupJavaConstructor(constructors[i]); + result[i] = graalRuntime().getRuntime().lookupJavaConstructor(constructors[i]); assert result[i].isConstructor(); } return result; @@ -534,7 +534,7 @@ Method[] methods = javaMirror.getDeclaredMethods(); ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; for (int i = 0; i < methods.length; i++) { - result[i] = HotSpotGraalRuntime.getInstance().getRuntime().lookupJavaMethod(methods[i]); + result[i] = graalRuntime().getRuntime().lookupJavaMethod(methods[i]); assert !result[i].isConstructor(); } return result; diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Sun Apr 28 22:52:12 2013 +0200 @@ -32,7 +32,9 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; 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.replacements.SystemSubstitutions.*; +import static com.oracle.graal.hotspot.stubs.Stub.*; import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; import static com.oracle.graal.replacements.Log.*; @@ -47,8 +49,8 @@ import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; import com.oracle.graal.api.code.CompilationResult.Call; 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.CompilationResult.Infopoint; import com.oracle.graal.api.code.Register.RegisterFlag; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; @@ -163,23 +165,23 @@ } } - protected Value ret(Kind kind) { + protected AllocatableValue ret(Kind kind) { if (kind == Kind.Void) { return ILLEGAL; } return globalStubRegConfig.getReturnRegister(kind).asValue(kind); } - protected Value[] javaCallingConvention(Kind... arguments) { + protected AllocatableValue[] javaCallingConvention(Kind... arguments) { return callingConvention(arguments, RuntimeCall); } - protected Value[] nativeCallingConvention(Kind... arguments) { + protected AllocatableValue[] nativeCallingConvention(Kind... arguments) { return callingConvention(arguments, NativeCall); } - private Value[] callingConvention(Kind[] arguments, CallingConvention.Type type) { - Value[] result = new Value[arguments.length]; + private AllocatableValue[] callingConvention(Kind[] arguments, CallingConvention.Type type) { + AllocatableValue[] result = new AllocatableValue[arguments.length]; TargetDescription target = graalRuntime.getTarget(); int currentStackOffset = 0; @@ -262,7 +264,7 @@ /* arg2: value */ Kind.Long, /* arg3: value */ Kind.Long)); - addRuntimeCall(Stub.STUB_PRINTF, config.stubPrintfStub, + addRuntimeCall(STUB_PRINTF, config.stubPrintfStub, /* temps */ null, /* ret */ ret(Kind.Void), /* arg0: format */ javaCallingConvention(Kind.Long, @@ -285,7 +287,7 @@ * @param ret where the call returns its result * @param args where arguments are passed to the call */ - protected RuntimeCallTarget addStubCall(Descriptor descriptor, Value ret, Value... args) { + protected RuntimeCallTarget addStubCall(Descriptor descriptor, AllocatableValue ret, AllocatableValue... args) { return addRuntimeCall(descriptor, 0L, null, ret, args); } @@ -298,8 +300,8 @@ * @param ret where the call returns its result * @param args where arguments are passed to the call */ - protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) { - Value[] temps = tempRegs == null || tempRegs.length == 0 ? Value.NONE : new Value[tempRegs.length]; + protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) { + AllocatableValue[] temps = tempRegs == null || tempRegs.length == 0 ? AllocatableValue.NONE : new AllocatableValue[tempRegs.length]; for (int i = 0; i < temps.length; i++) { temps[i] = tempRegs[i].asValue(); } @@ -358,6 +360,7 @@ registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE))); registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY))); + registerStub(new NewMultiArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_MULTI_ARRAY))); } private void registerStub(Stub stub) { @@ -453,11 +456,11 @@ return "MARK:" + mark.id; } - private static void addExceptionHandlersComment(CompilationResult tm, HexCodeFile hcf) { - if (!tm.getExceptionHandlers().isEmpty()) { + private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) { + if (!compResult.getExceptionHandlers().isEmpty()) { String nl = HexCodeFile.NEW_LINE; StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); - for (CompilationResult.ExceptionHandler e : tm.getExceptionHandlers()) { + for (CompilationResult.ExceptionHandler e : compResult.getExceptionHandlers()) { buf.append(" ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl); hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); @@ -516,7 +519,7 @@ ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; ValueNode array = arrayLengthNode.array(); ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt())); - arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array)); + tool.createNullCheckGuard(arrayLengthRead.dependencies(), array); graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); } else if (n instanceof Invoke) { Invoke invoke = (Invoke) n; @@ -525,7 +528,7 @@ NodeInputList parameters = callTarget.arguments(); ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) { - invoke.asNode().dependencies().add(tool.createNullCheckGuard(receiver)); + tool.createNullCheckGuard(invoke.asNode().dependencies(), receiver); } JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); @@ -536,13 +539,12 @@ if (!hsMethod.getDeclaringClass().isInterface()) { int vtableEntryOffset = hsMethod.vtableEntryOffset(); if (vtableEntryOffset > 0) { - // We use LocationNode.ANY_LOCATION for the reads that access the vtable - // entry and the compiled code entry - // as HotSpot does not guarantee they are final values. assert vtableEntryOffset > 0; - LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind)); - ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), - StampFactory.forKind(wordKind()))); + ReadNode hub = this.createReadHub(tool, graph, wordKind, receiver); + ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod); + // We use LocationNode.ANY_LOCATION for the reads that access the + // compiled code entry as HotSpot does not guarantee they are final + // values. ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), StampFactory.forKind(wordKind()))); @@ -568,7 +570,7 @@ ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object(); assert loadField.kind() != Kind.Illegal; ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp())); - memoryRead.dependencies().add(tool.createNullCheckGuard(object)); + tool.createNullCheckGuard(memoryRead.dependencies(), object); graph.replaceFixedWithFixed(loadField, memoryRead); @@ -585,7 +587,7 @@ LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph); WriteBarrierType barrierType = getFieldStoreBarrierType(storeField); WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType)); - memoryWrite.dependencies().add(tool.createNullCheckGuard(object)); + tool.createNullCheckGuard(memoryWrite.dependencies(), object); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); FixedWithNextNode last = memoryWrite; @@ -661,17 +663,17 @@ WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType)); write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); - } else if (n instanceof LoadHubNode) { LoadHubNode loadHub = (LoadHubNode) n; assert loadHub.kind() == wordKind; - LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); ValueNode object = loadHub.object(); - assert !object.isConstant() || object.asConstant().isNull(); - ValueNode guard = tool.createNullCheckGuard(object); - ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); - hub.dependencies().add(guard); + ReadNode hub = createReadHub(tool, graph, wordKind, object); graph.replaceFixed(loadHub, hub); + } else if (n instanceof LoadMethodNode) { + LoadMethodNode loadMethodNode = (LoadMethodNode) n; + ResolvedJavaMethod method = loadMethodNode.getMethod(); + ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method); + graph.replaceFixed(loadMethodNode, metaspaceMethod); } else if (n instanceof FixedGuardNode) { FixedGuardNode node = (FixedGuardNode) n; ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated()))); @@ -721,6 +723,26 @@ } } + private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) { + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; + assert !hsMethod.getDeclaringClass().isInterface(); + + int vtableEntryOffset = hsMethod.vtableEntryOffset(); + assert vtableEntryOffset > 0; + // We use LocationNode.ANY_LOCATION for the reads that access the vtable + // entry as HotSpot does not guarantee that this is a final value. + ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind()))); + return metaspaceMethod; + } + + private ReadNode createReadHub(LoweringTool tool, StructuredGraph graph, Kind wordKind, ValueNode object) { + LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); + assert !object.isConstant() || object.asConstant().isNull(); + ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); + tool.createNullCheckGuard(hub.dependencies(), object); + return hub; + } + private static WriteBarrierType getFieldStoreBarrierType(StoreFieldNode storeField) { WriteBarrierType barrierType = WriteBarrierType.NONE; if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) { @@ -951,8 +973,8 @@ public String disassemble(InstalledCode code) { if (code.isValid()) { - long nmethod = ((HotSpotInstalledCode) code).getMethodAddress(); - return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod); + long codeBlob = ((HotSpotInstalledCode) code).getCodeBlob(); + return graalRuntime.getCompilerToVM().disassembleCodeBlob(codeBlob); } return null; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import java.util.*; import com.oracle.graal.api.meta.*; @@ -118,7 +120,7 @@ } JavaType type = argumentTypes[index]; if (type == null || !(type instanceof ResolvedJavaType)) { - type = HotSpotGraalRuntime.getInstance().lookupType(arguments.get(index), (HotSpotResolvedObjectType) accessingClass, false); + type = graalRuntime().lookupType(arguments.get(index), (HotSpotResolvedObjectType) accessingClass, false); argumentTypes[index] = type; } return type; @@ -137,7 +139,7 @@ @Override public JavaType getReturnType(ResolvedJavaType accessingClass) { if (returnTypeCache == null || !(returnTypeCache instanceof ResolvedJavaType)) { - returnTypeCache = HotSpotGraalRuntime.getInstance().lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false); + returnTypeCache = graalRuntime().lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false); } return returnTypeCache; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.*; /** * Implementation of {@link JavaType} for unresolved HotSpot classes. @@ -85,6 +86,6 @@ @Override public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { - return (ResolvedJavaType) HotSpotGraalRuntime.getInstance().lookupType(getName(), (HotSpotResolvedObjectType) accessingClass, true); + return (ResolvedJavaType) graalRuntime().lookupType(getName(), (HotSpotResolvedObjectType) accessingClass, true); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -73,7 +73,7 @@ HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; StackSlot slot = hsGen.getLockSlot(lockDepth); if (!eliminated) { - Value result = gen.emitLea(slot); + Value result = gen.emitAddress(slot); gen.setResult(this, result); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,72 @@ +/* + * 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 protected 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 c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -26,7 +26,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -43,7 +42,7 @@ @Override public void generate(LIRGeneratorTool gen) { - Register rawThread = HotSpotGraalRuntime.getInstance().getRuntime().threadRegister(); + Register rawThread = graalRuntime().getRuntime().threadRegister(); gen.setResult(this, rawThread.asValue(this.kind())); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -57,7 +57,7 @@ HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; StackSlot slot = hsGen.getLockSlot(lockDepth); // The register allocator cannot handle stack -> register moves so we use an LEA here - Value result = gen.emitMove(gen.emitLea(slot)); + Value result = gen.emitMove(gen.emitAddress(slot)); gen.setResult(this, result); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 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.hotspot.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}") +public class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable { + + private final DeoptimizationAction action; + private final DeoptimizationReason reason; + + public DeoptimizeCallerNode(DeoptimizationAction action, DeoptimizationReason reason) { + super(StampFactory.forVoid()); + this.action = action; + this.reason = reason; + } + + @Override + public void generate(LIRGeneratorTool gen) { + ((HotSpotLIRGenerator) gen).emitDeoptimizeCaller(action, reason); + } + + @NodeIntrinsic + public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason); +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -47,7 +47,7 @@ public void generate(LIRGenerator gen) { int size = rank * 4; StackSlot array = gen.frameMap().allocateStackBlock(size, false); - Value result = gen.emitLea(array); + Value result = gen.emitAddress(array); gen.setResult(this, result); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -46,7 +46,7 @@ @Override public void generate(LIRGeneratorTool gen) { - Value obj = gen.newVariable(gen.target().wordKind); + AllocatableValue obj = gen.newVariable(gen.target().wordKind); gen.emitMove(obj, gen.operand(object)); gen.setResult(this, obj); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,9 +22,10 @@ */ package com.oracle.graal.hotspot.nodes; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; @@ -68,11 +69,11 @@ ResolvedJavaMethod method = null; ResolvedJavaField methodField = null; ResolvedJavaField metaspaceMethodField = null; - ResolvedJavaField nmethodField = null; + ResolvedJavaField codeBlobField = null; try { method = tool.lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class)); methodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("method")); - nmethodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("nmethod")); + codeBlobField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("codeBlob")); metaspaceMethodField = tool.lookupJavaField(HotSpotResolvedJavaMethod.class.getDeclaredField("metaspaceMethod")); } catch (NoSuchMethodException | SecurityException | NoSuchFieldException e) { throw new IllegalStateException(e); @@ -85,8 +86,8 @@ StructuredGraph g = (StructuredGraph) graph(); - LoadFieldNode loadnmethod = g.add(new LoadFieldNode(code, nmethodField)); - UnsafeLoadNode load = g.add(new UnsafeLoadNode(loadnmethod, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), HotSpotGraalRuntime.getInstance().getTarget().wordKind)); + LoadFieldNode loadCodeBlob = g.add(new LoadFieldNode(code, codeBlobField)); + UnsafeLoadNode load = g.add(new UnsafeLoadNode(loadCodeBlob, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), graalRuntime().getTarget().wordKind)); LoadFieldNode loadMethod = g.add(new LoadFieldNode(code, methodField)); LoadFieldNode loadmetaspaceMethod = g.add(new LoadFieldNode(loadMethod, metaspaceMethodField)); @@ -101,7 +102,7 @@ g.addBeforeFixed(invoke, loadmetaspaceMethod); g.addBeforeFixed(loadmetaspaceMethod, loadMethod); g.addBeforeFixed(invoke, load); - g.addBeforeFixed(load, loadnmethod); + g.addBeforeFixed(load, loadCodeBlob); return invoke; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -43,7 +43,7 @@ public void generate(LIRGenerator gen) { assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance"; StackSlot counter = gen.frameMap().allocateStackBlock(gen.target().wordSize, false); - Value result = gen.emitLea(counter); + Value result = gen.emitAddress(counter); gen.setResult(this, result); } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Sun Apr 28 22:52:12 2013 +0200 @@ -60,7 +60,7 @@ 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.emitLea(slot)); + gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.emitAddress(slot)); } @NodeIntrinsic diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java Sun Apr 28 22:34:46 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +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.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -/** - * Node implementing a call to the {@code new_array} stub. - */ -public class NewArraySlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - private static final Stamp defaultStamp = StampFactory.objectNonNull(); - - @Input private final ValueNode hub; - @Input private final ValueNode length; - - public static final Descriptor NEW_ARRAY_SLOW = new Descriptor("new_array_slow", false, Object.class, Word.class, int.class); - - public NewArraySlowStubCall(ValueNode hub, ValueNode length) { - super(defaultStamp); - this.hub = hub; - this.length = length; - } - - @Override - public boolean inferStamp() { - if (stamp() == defaultStamp && hub.isConstant()) { - updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant()))); - return true; - } - return false; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY_SLOW); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native Object call(Word hub, int length); -} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java Sun Apr 28 22:34:46 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +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.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -/** - * Node implementing a call to HotSpot's {@code new_instance} stub. - */ -public class NewInstanceSlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - private static final Stamp defaultStamp = StampFactory.objectNonNull(); - - @Input private final ValueNode hub; - - public static final Descriptor NEW_INSTANCE_SLOW = new Descriptor("new_instance_slow", false, Object.class, Word.class); - - public NewInstanceSlowStubCall(ValueNode hub) { - super(defaultStamp); - this.hub = hub; - } - - @Override - public boolean inferStamp() { - if (stamp() == defaultStamp && hub.isConstant()) { - updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant()))); - return true; - } - return false; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE_SLOW); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native Object call(Word hub); -} diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Sun Apr 28 22:52:12 2013 +0200 @@ -28,13 +28,14 @@ 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.type.*; import com.oracle.graal.word.*; /** - * Node implementing a call to HotSpot's {@code new_multi_array} stub. + * Node implementing a call to {@link NewMultiArrayStub}. */ public class NewMultiArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.nodes; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import java.lang.reflect.*; import java.util.*; @@ -58,7 +60,7 @@ @Override public void generate(LIRGeneratorTool generator) { LIRGenerator gen = (LIRGenerator) generator; - HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + HotSpotVMConfig config = graalRuntime().getConfig(); ResolvedJavaMethod method = frameState.method(); boolean isStatic = Modifier.isStatic(method.getModifiers()); @@ -69,7 +71,8 @@ parameters.add(frameState.localAt(slot)); } Value[] args = gen.visitInvokeArguments(cc, parameters); - Value entry = gen.emitLoad(Kind.Long, gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0, null); + Value address = gen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0); + Value entry = gen.emitLoad(Kind.Long, address, null); HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen; hsgen.emitTailcall(args, entry); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Sun Apr 28 22:52:12 2013 +0200 @@ -84,8 +84,8 @@ long nonVectorBytes = byteLength % VECTOR_SIZE; long srcOffset = (long) srcPos * elementSize; long destOffset = (long) destPos * elementSize; - if (src == dest && srcPos < destPos) { // bad aliased case - probability(NOT_FREQUENT_PROBABILITY); + if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) { + // bad aliased case for (long i = byteLength - elementSize; i >= byteLength - nonVectorBytes; i -= elementSize) { UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); } @@ -107,7 +107,6 @@ public static void checkNonNull(Object obj) { if (obj == null) { - probability(DEOPT_PATH_PROBABILITY); checkNPECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } @@ -116,7 +115,6 @@ public static int checkArrayType(Word hub) { int layoutHelper = readLayoutHelper(hub); if (layoutHelper >= 0) { - probability(DEOPT_PATH_PROBABILITY); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } return layoutHelper; @@ -124,27 +122,22 @@ public static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) { if (srcPos < 0) { - probability(DEOPT_PATH_PROBABILITY); checkAIOOBECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } if (destPos < 0) { - probability(DEOPT_PATH_PROBABILITY); checkAIOOBECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } if (length < 0) { - probability(DEOPT_PATH_PROBABILITY); checkAIOOBECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } if (srcPos + length > ArrayLengthNode.arrayLength(src)) { - probability(DEOPT_PATH_PROBABILITY); checkAIOOBECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } if (destPos + length > ArrayLengthNode.arrayLength(dest)) { - probability(DEOPT_PATH_PROBABILITY); checkAIOOBECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } @@ -278,13 +271,10 @@ int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0); - if (srcHub.equal(destHub) && src != dest) { - probability(FAST_PATH_PROBABILITY); - + if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, src != dest)) { checkLimits(src, srcPos, dest, destPos, length); - if (isObjectArray) { + if (probability(FAST_PATH_PROBABILITY, isObjectArray)) { genericObjectExactCallCounter.inc(); - probability(FAST_PATH_PROBABILITY); arrayObjectCopy(src, srcPos, dest, destPos, length); } else { genericPrimitiveCallCounter.inc(); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Sun Apr 28 22:52:12 2013 +0200 @@ -65,13 +65,11 @@ */ @Snippet public static Object checkcastExact(Object object, Word exactHub, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); } else { Word objectHub = loadHub(object); if (objectHub.notEqual(exactHub)) { - probability(DEOPT_PATH_PROBABILITY); exactMiss.inc(); DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); } @@ -92,13 +90,11 @@ */ @Snippet public static Object checkcastPrimary(Word hub, Object object, @ConstantParameter int superCheckOffset, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); } else { Word objectHub = loadHub(object); if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { - probability(DEOPT_PATH_PROBABILITY); displayMiss.inc(); DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); } @@ -113,8 +109,7 @@ */ @Snippet public static Object checkcastSecondary(Word hub, Object object, @VarargsParameter Word[] hints, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); } else { Word objectHub = loadHub(object); @@ -142,8 +137,7 @@ */ @Snippet public static Object checkcastDynamic(Word hub, Object object, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); } else { Word objectHub = loadHub(object); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Sun Apr 28 22:52:12 2013 +0200 @@ -49,7 +49,7 @@ public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION; public static HotSpotVMConfig config() { - return HotSpotGraalRuntime.getInstance().getConfig(); + return graalRuntime().getConfig(); } @Fold @@ -97,6 +97,20 @@ return config().threadTlabStartOffset; } + public static final Object PENDING_EXCEPTION_LOCATION = LocationNode.createLocation("PendingException"); + + @Fold + private static int threadPendingExceptionOffset() { + return config().pendingExceptionOffset; + } + + public static final Object OBJECT_RESULT_LOCATION = LocationNode.createLocation("ObjectResult"); + + @Fold + private static int objectResultOffset() { + return config().threadObjectResultOffset; + } + public static Object readExceptionOop(Word thread) { return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION); } @@ -131,6 +145,28 @@ thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION); } + /** + * Clears the pending exception if for the given thread. + * + * @return {@code true} if there was a pending exception + */ + public static boolean clearPendingException(Word thread) { + boolean result = thread.readObject(threadPendingExceptionOffset(), PENDING_EXCEPTION_LOCATION) != null; + thread.writeObject(threadPendingExceptionOffset(), null); + return result; + } + + /** + * Gets and clears the object result from a runtime call stored in a thread local. + * + * @return the object that was in the thread local + */ + public static Object getAndClearObjectResult(Word thread) { + Object result = thread.readObject(objectResultOffset(), OBJECT_RESULT_LOCATION); + thread.writeObject(objectResultOffset(), null); + return result; + } + @Fold public static int threadObjectOffset() { return config().threadObjectOffset; @@ -148,22 +184,22 @@ @Fold public static Kind wordKind() { - return HotSpotGraalRuntime.getInstance().getTarget().wordKind; + return graalRuntime().getTarget().wordKind; } @Fold public static Register threadRegister() { - return HotSpotGraalRuntime.getInstance().getRuntime().threadRegister(); + return graalRuntime().getRuntime().threadRegister(); } @Fold public static Register stackPointerRegister() { - return HotSpotGraalRuntime.getInstance().getRuntime().stackPointerRegister(); + return graalRuntime().getRuntime().stackPointerRegister(); } @Fold public static int wordSize() { - return HotSpotGraalRuntime.getInstance().getTarget().wordSize; + return graalRuntime().getTarget().wordSize; } @Fold @@ -608,11 +644,9 @@ // this code is independent from biased locking (although it does not look that way) final Word biasedLock = mark.and(biasedLockMaskInPlace()); - if (biasedLock.equal(Word.unsigned(unlockedMask()))) { - probability(FAST_PATH_PROBABILITY); + if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask())))) { int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue(); - if (hash != uninitializedIdentityHashCodeValue()) { - probability(FAST_PATH_PROBABILITY); + if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue())) { return hash; } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Sun Apr 28 22:52:12 2013 +0200 @@ -58,14 +58,12 @@ */ @Snippet public static Object instanceofExact(Object object, Word exactHub, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); return falseValue; } Word objectHub = loadHub(object); - if (objectHub.notEqual(exactHub)) { - probability(LIKELY_PROBABILITY); + if (probability(LIKELY_PROBABILITY, objectHub.notEqual(exactHub))) { exactMiss.inc(); return falseValue; } @@ -78,14 +76,12 @@ */ @Snippet public static Object instanceofPrimary(Word hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); return falseValue; } Word objectHub = loadHub(object); - if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { - probability(NOT_LIKELY_PROBABILITY); + if (probability(NOT_LIKELY_PROBABILITY, objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub))) { displayMiss.inc(); return falseValue; } @@ -99,8 +95,7 @@ @Snippet public static Object instanceofSecondary(Word hub, Object object, @VarargsParameter Word[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); return falseValue; } @@ -110,8 +105,7 @@ for (int i = 0; i < hints.length; i++) { Word hintHub = hints[i]; boolean positive = hintIsPositive[i]; - if (hintHub.equal(objectHub)) { - probability(NOT_FREQUENT_PROBABILITY); + if (probability(NOT_FREQUENT_PROBABILITY, hintHub.equal(objectHub))) { hintsHit.inc(); return positive ? trueValue : falseValue; } @@ -127,8 +121,7 @@ */ @Snippet public static Object instanceofDynamic(Class mirror, Object object, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (checkNull && probability(NOT_FREQUENT_PROBABILITY, object == null)) { isNull.inc(); return falseValue; } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Sun Apr 28 22:52:12 2013 +0200 @@ -102,10 +102,9 @@ final Word biasableLockBits = mark.and(biasedLockMaskInPlace()); // First check to see whether biasing is enabled for this object - if (biasableLockBits.notEqual(Word.unsigned(biasedLockPattern()))) { + if (probability(NOT_FREQUENT_PROBABILITY, biasableLockBits.notEqual(Word.unsigned(biasedLockPattern())))) { // Biasing not enabled -> fall through to lightweight locking } else { - probability(FREQUENT_PROBABILITY); // The bias pattern is present in the object's mark word. Need to check // whether the bias owner and the epoch are both still current. Word hub = loadHub(object); @@ -115,9 +114,8 @@ trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord); trace(trace, " thread: 0x%016lx\n", thread); trace(trace, " tmp: 0x%016lx\n", tmp); - if (tmp.equal(0)) { + if (probability(FREQUENT_PROBABILITY, tmp.equal(0))) { // Object is already biased to current thread -> done - probability(FREQUENT_PROBABILITY); traceObject(trace, "+lock{bias:existing}", object); return; } @@ -131,8 +129,7 @@ // If the low three bits in the xor result aren't clear, that means // the prototype header is no longer biasable and we have to revoke // the bias on this object. - if (tmp.and(biasedLockMaskInPlace()).equal(0)) { - probability(FREQUENT_PROBABILITY); + if (probability(FREQUENT_PROBABILITY, tmp.and(biasedLockMaskInPlace()).equal(0))) { // Biasing is still enabled for object's type. See whether the // epoch of the current bias is still valid, meaning that the epoch // bits of the mark word are equal to the epoch bits of the @@ -142,8 +139,7 @@ // that the current epoch is invalid in order to do this because // otherwise the manipulations it performs on the mark word are // illegal. - if (tmp.and(epochMaskInPlace()).equal(0)) { - probability(FREQUENT_PROBABILITY); + if (probability(FREQUENT_PROBABILITY, tmp.and(epochMaskInPlace()).equal(0))) { // The epoch of the current bias is still valid but we know nothing // about the owner; it might be set or it might be clear. Try to // acquire the bias of the object using an atomic operation. If this @@ -154,7 +150,7 @@ Word biasedMark = unbiasedMark.or(thread); trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark)) { + if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:acquired}", object); return; @@ -162,7 +158,6 @@ // If the biasing toward our thread failed, this means that another thread // owns the bias and we need to revoke that bias. The revocation will occur // in the interpreter runtime. - probability(DEOPT_PATH_PROBABILITY); traceObject(trace, "+lock{stub:revoke}", object); MonitorEnterStubCall.call(object, lock); return; @@ -175,7 +170,7 @@ // the bias from one thread to another directly in this situation. Word biasedMark = prototypeMarkWord.or(thread); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark)) { + if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:transfer}", object); return; @@ -183,7 +178,6 @@ // If the biasing toward our thread failed, then another thread // succeeded in biasing it toward itself and we need to revoke that // bias. The revocation will occur in the runtime in the slow case. - probability(DEOPT_PATH_PROBABILITY); traceObject(trace, "+lock{stub:epoch-expired}", object); MonitorEnterStubCall.call(object, lock); return; @@ -239,9 +233,8 @@ // significant 2 bits cleared and page_size is a power of 2 final Word alignedMask = Word.unsigned(wordSize() - 1); final Word stackPointer = stackPointer(); - if (currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0)) { + 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 - probability(DEOPT_PATH_PROBABILITY); traceObject(trace, "+lock{stub:failed-cas}", object); MonitorEnterStubCall.call(object, lock); return; @@ -290,8 +283,7 @@ // the bias bit would be clear. final Word mark = loadWordFromObject(object, markOffset()); trace(trace, " mark: 0x%016lx\n", mark); - if (mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern()))) { - probability(FREQUENT_PROBABILITY); + if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern())))) { endLockScope(); decCounter(); traceObject(trace, "-lock{bias}", object); @@ -313,10 +305,9 @@ // Test if object's mark word is pointing to the displaced mark word, and if so, restore // the displaced mark in the object - if the object's mark word is not pointing to // the displaced mark word, do unlocking via runtime call. - if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock)) { + if (probability(VERY_SLOW_PATH_PROBABILITY, DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock))) { // The object's mark word was not pointing to the displaced header, // we do unlocking via runtime call. - probability(DEOPT_PATH_PROBABILITY); traceObject(trace, "-lock{stub}", object); MonitorExitStubCall.call(object); } else { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Sun Apr 28 22:52:12 2013 +0200 @@ -64,8 +64,7 @@ * this check might lead to problems if the TLAB is within 16GB of the address space end * (checked in c++ code) */ - if (newTop.belowOrEqual(end)) { - probability(FAST_PATH_PROBABILITY); + if (probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); return top; } @@ -76,11 +75,10 @@ public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents, @ConstantParameter boolean locked) { Object result; - if (memory.equal(0)) { + if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) { new_stub.inc(); result = NewInstanceStubCall.call(hub); } else { - probability(FAST_PATH_PROBABILITY); if (locked) { formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents); } else { @@ -108,11 +106,10 @@ private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) { Object result; - if (memory.equal(0)) { + if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) { newarray_stub.inc(); result = NewArrayStubCall.call(hub, length); } else { - probability(FAST_PATH_PROBABILITY); newarray_loopInit.inc(); formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents); result = memory.toObject(); @@ -130,7 +127,6 @@ public static Object allocateArrayAndInitialize(int length, @ConstantParameter int alignment, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, @ConstantParameter boolean fillContents, @ConstantParameter ResolvedJavaType type) { if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { - probability(DEOPT_PATH_PROBABILITY); // This handles both negative array sizes and very large array sizes DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Sun Apr 28 22:52:12 2013 +0200 @@ -84,7 +84,6 @@ private static Word getAndCheckHub(Object src) { Word hub = loadHub(src); if (!(src instanceof Cloneable)) { - probability(DEOPT_PATH_PROBABILITY); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } return hub; @@ -110,8 +109,7 @@ genericCloneCounter.inc(); Word hub = getAndCheckHub(src); int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); - if (layoutHelper < 0) { - probability(LIKELY_PROBABILITY); + if (probability(LIKELY_PROBABILITY, layoutHelper < 0)) { genericArrayCloneCounter.inc(); return arrayClone(src, hub, layoutHelper); } else { diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Sun Apr 28 22:52:12 2013 +0200 @@ -56,8 +56,7 @@ @MethodSubstitution public static int identityHashCode(Object x) { - if (x == null) { - probability(NOT_FREQUENT_PROBABILITY); + if (probability(NOT_FREQUENT_PROBABILITY, x == null)) { return 0; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Sun Apr 28 22:52:12 2013 +0200 @@ -37,6 +37,8 @@ import com.oracle.graal.replacements.*; import com.oracle.graal.word.*; +//JaCoCo Exclude + /** * Utilities and common code paths used by the type check snippets. */ @@ -89,8 +91,7 @@ Word secondarySupers = s.readWord(secondarySupersOffset(), SECONDARY_SUPERS_LOCATION); int length = secondarySupers.readInt(metaspaceArrayLengthOffset(), FINAL_LOCATION); for (int i = 0; i < length; i++) { - if (t.equal(loadSecondarySupersElement(secondarySupers, i))) { - probability(NOT_LIKELY_PROBABILITY); + if (probability(NOT_LIKELY_PROBABILITY, t.equal(loadSecondarySupersElement(secondarySupers, i)))) { s.writeWord(secondarySuperCacheOffset(), t, SECONDARY_SUPER_CACHE_LOCATION); secondariesHit.inc(); return true; diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,11 +22,17 @@ */ package com.oracle.graal.hotspot.stubs; +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; +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.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; @@ -42,7 +48,7 @@ * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails. * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++ - * runtime for to complete the allocation. + * runtime to complete the allocation. */ public class NewArrayStub extends Stub { @@ -54,10 +60,16 @@ protected Arguments makeArguments(SnippetInfo stub) { HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); + // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we + // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since + // the int[] class will never be unloaded. + Constant intArrayHub = intArrayType.klass(); + intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null); + Arguments args = new Arguments(stub); args.add("hub", null); args.add("length", null); - args.addConst("intArrayHub", intArrayType.klass()); + args.addConst("intArrayHub", intArrayHub); args.addConst("log", Boolean.getBoolean("graal.logNewArrayStub")); return args; } @@ -92,7 +104,20 @@ return verifyOop(memory.toObject()); } } - log(log, "newArray: calling new_array_slow", 0L); - return verifyOop(NewArraySlowStubCall.call(hub, length)); + log(log, "newArray: calling new_array_c\n", 0L); + + newArrayC(NEW_ARRAY_C, thread(), hub, length); + + if (clearPendingException(thread())) { + log(log, "newArray: deoptimizing to caller\n", 0L); + getAndClearObjectResult(thread()); + DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); + } + return verifyOop(getAndClearObjectResult(thread())); } + + public static final Descriptor NEW_ARRAY_C = new Descriptor("new_array_c", false, void.class, Word.class, Word.class, int.class); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void newArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int length); } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,12 +22,18 @@ */ package com.oracle.graal.hotspot.stubs; +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; +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.*; @@ -56,9 +62,15 @@ protected Arguments makeArguments(SnippetInfo stub) { HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); + // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we + // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since + // the int[] class will never be unloaded. + Constant intArrayHub = intArrayType.klass(); + intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null); + Arguments args = new Arguments(stub); args.add("hub", null); - args.addConst("intArrayHub", intArrayType.klass()); + args.addConst("intArrayHub", intArrayHub); args.addConst("log", Boolean.getBoolean("graal.logNewInstanceStub")); return args; } @@ -86,7 +98,17 @@ } } } - return verifyOop(NewInstanceSlowStubCall.call(hub)); + + log(log, "newInstance: calling new_instance_c\n", 0L); + + newInstanceC(NEW_INSTANCE_C, thread(), hub); + + if (clearPendingException(thread())) { + log(log, "newInstance: deoptimizing to caller\n", 0L); + getAndClearObjectResult(thread()); + DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); + } + return verifyOop(getAndClearObjectResult(thread())); } /** @@ -208,4 +230,9 @@ private static boolean forceSlowPath() { return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath"); } + + public static final Descriptor NEW_INSTANCE_C = new Descriptor("new_instance_c", false, void.class, Word.class, Word.class); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void newInstanceC(@ConstantNodeParameter Descriptor newInstanceC, Word thread, Word hub); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,72 @@ +/* + * 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.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; + +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.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; +import com.oracle.graal.word.*; + +public class NewMultiArrayStub extends Stub { + + public NewMultiArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage, "newMultiArray"); + } + + @Override + protected Arguments makeArguments(SnippetInfo stub) { + Arguments args = new Arguments(stub); + args.add("hub", null); + args.add("rank", null); + args.add("dims", null); + return args; + } + + @Snippet + private static Object newMultiArray(Word hub, int rank, Word dims) { + newMultiArrayC(NEW_MULTI_ARRAY_C, thread(), hub, rank, dims); + + if (clearPendingException(thread())) { + getAndClearObjectResult(thread()); + DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); + } + return verifyOop(getAndClearObjectResult(thread())); + } + + public static final Descriptor NEW_MULTI_ARRAY_C = new Descriptor("new_multi_array_c", false, void.class, Word.class, Word.class, int.class, Word.class); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void newMultiArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int rank, Word dims); +} diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Sun Apr 28 22:52:12 2013 +0200 @@ -28,6 +28,7 @@ import java.util.concurrent.*; import 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.*; import com.oracle.graal.compiler.*; @@ -51,6 +52,8 @@ import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.word.*; +//JaCoCo Exclude + /** * Base class for implementing some low level code providing the out-of-line slow path for a * snippet. A concrete stub is defined a subclass of this class. @@ -76,13 +79,13 @@ protected InstalledCode code; /** - * The registers defined by this stub. + * The registers/temporaries defined by this stub. */ private Set definedRegisters; public void initDefinedRegisters(Set registers) { assert registers != null; - assert definedRegisters == null : "cannot redefine"; + assert definedRegisters == null || registers.equals(definedRegisters) : "cannot redefine"; definedRegisters = registers; } @@ -100,7 +103,6 @@ super(runtime, replacements, target); this.stubInfo = snippet(getClass(), methodName); this.linkage = linkage; - } /** @@ -123,6 +125,15 @@ return linkage; } + private boolean checkCompilationResult(CompilationResult compResult) { + for (DataPatch data : compResult.getDataReferences()) { + Constant constant = data.constant; + assert constant.getKind() != Kind.Object : MetaUtil.format("%h.%n(%p): ", getMethod()) + "cannot have embedded oop: " + constant; + assert constant.getPrimitiveAnnotation() == null : MetaUtil.format("%h.%n(%p): ", getMethod()) + "cannot have embedded metadata: " + constant; + } + return true; + } + /** * Gets the code for this stub, compiling it first if necessary. */ @@ -143,6 +154,8 @@ final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog()); + assert checkCompilationResult(compResult); + assert definedRegisters != null; code = Debug.scope("CodeInstall", new Callable() { @@ -156,7 +169,6 @@ return installedCode; } }); - } }); assert code != null : "error installing stub " + getMethod(); diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -34,7 +34,6 @@ 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.JavaTypeProfile.ProfiledType; import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.api.meta.ResolvedJavaType.Representation; import com.oracle.graal.bytecode.*; @@ -798,12 +797,7 @@ if (!optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) { return null; } else { - ResolvedJavaType uniqueSubtype = type.findUniqueConcreteSubtype(); - if (uniqueSubtype != null) { - return new JavaTypeProfile(profilingInfo.getNullSeen(bci()), 0.0D, new ProfiledType(uniqueSubtype, 1.0D)); - } else { - return profilingInfo.getTypeProfile(bci()); - } + return profilingInfo.getTypeProfile(bci()); } } @@ -812,7 +806,8 @@ JavaType type = lookupType(cpi, CHECKCAST); ValueNode object = frameState.apop(); if (type instanceof ResolvedJavaType) { - CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, getProfileForTypeCheck((ResolvedJavaType) type))); + JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type); + CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck)); append(checkCast); frameState.apush(checkCast); } else { @@ -1165,6 +1160,10 @@ if (graphBuilderConfig.eagerResolving()) { returnType = returnType.resolve(targetMethod.getDeclaringClass()); } + if (invokeKind != InvokeKind.Static && invokeKind != InvokeKind.Special) { + JavaTypeProfile profile = profilingInfo.getTypeProfile(bci()); + args[0] = TypeProfileProxyNode.create(args[0], profile); + } MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType)); createInvokeNode(callTarget, resultType); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java Sun Apr 28 22:52:12 2013 +0200 @@ -36,8 +36,8 @@ delta = System.currentTimeMillis() - start; // do nothing. } - // better get at least 40 millisecond resolution. - return delta >= 1 && delta < 40; + // better get at least 100 millisecond resolution. + return delta >= 1 && delta < 100; } @Test diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java Sun Apr 28 22:34:46 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2007, 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.jtt.reflect; - -import com.oracle.graal.jtt.*; -import org.junit.*; - -import sun.reflect.*; - -/* - */ -public final class Reflection_getCallerClass01 extends JTTTest { - - public static final class Caller1 { - - private Caller1() { - } - - static String caller1(int depth) { - return Reflection.getCallerClass(depth).getName(); - } - } - - public static final class Caller2 { - - private Caller2() { - } - - static String caller2(int depth) { - return Caller1.caller1(depth); - } - } - - public static String test(int depth) { - return Caller2.caller2(depth); - } - - @Test - public void run0() throws Throwable { - runTest("test", 0); - } - - @Test - public void run1() throws Throwable { - runTest("test", 1); - } - - @Test - public void run2() throws Throwable { - runTest("test", 2); - } - -} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Sun Apr 28 22:52:12 2013 +0200 @@ -30,18 +30,19 @@ import com.oracle.graal.asm.amd64.*; import com.oracle.graal.asm.amd64.AMD64Address.Scale; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; public class AMD64AddressValue extends CompositeValue { private static final long serialVersionUID = -4444600052487578694L; - @Component({REG, UNUSED}) protected AllocatableValue base; - @Component({REG, UNUSED}) protected AllocatableValue index; + @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base; + @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index; protected final Scale scale; protected final int displacement; public AMD64AddressValue(Kind kind, AllocatableValue base, int displacement) { - this(kind, base, AllocatableValue.UNUSED, Scale.Times1, displacement); + this(kind, base, Value.ILLEGAL, Scale.Times1, displacement); } public AMD64AddressValue(Kind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) { @@ -53,7 +54,7 @@ } private static Register toRegister(AllocatableValue value) { - if (value == AllocatableValue.UNUSED) { + if (value == Value.ILLEGAL) { return Register.None; } else { RegisterValue reg = (RegisterValue) value; @@ -67,8 +68,7 @@ @Override public String toString() { - StringBuilder s = new StringBuilder(); - s.append(getKind().getJavaName()).append("["); + StringBuilder s = new StringBuilder("["); String sep = ""; if (isLegal(base)) { s.append(base); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Sun Apr 28 22:52:12 2013 +0200 @@ -26,7 +26,6 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.amd64.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.graph.*; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.lir.amd64; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.asm.*; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Sun Apr 28 22:52:12 2013 +0200 @@ -44,10 +44,10 @@ @Opcode("MOVE") public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp { - @Def({REG, HINT}) protected Value result; + @Def({REG, HINT}) protected AllocatableValue result; @Use({REG, STACK, CONST}) protected Value input; - public MoveToRegOp(Value result, Value input) { + public MoveToRegOp(AllocatableValue result, Value input) { this.result = result; this.input = input; } @@ -63,7 +63,7 @@ } @Override - public Value getResult() { + public AllocatableValue getResult() { return result; } } @@ -71,10 +71,10 @@ @Opcode("MOVE") public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp { - @Def({REG, STACK}) protected Value result; + @Def({REG, STACK}) protected AllocatableValue result; @Use({REG, CONST, HINT}) protected Value input; - public MoveFromRegOp(Value result, Value input) { + public MoveFromRegOp(AllocatableValue result, Value input) { this.result = result; this.input = input; } @@ -90,17 +90,19 @@ } @Override - public Value getResult() { + public AllocatableValue getResult() { return result; } } public abstract static class MemOp extends AMD64LIRInstruction { + protected final Kind kind; @Use({COMPOSITE}) protected AMD64AddressValue address; @State protected LIRFrameState state; - public MemOp(AMD64AddressValue address, LIRFrameState state) { + public MemOp(Kind kind, AMD64AddressValue address, LIRFrameState state) { + this.kind = kind; this.address = address; this.state = state; } @@ -120,14 +122,14 @@ @Def({REG}) protected AllocatableValue result; - public LoadOp(AllocatableValue result, AMD64AddressValue address, LIRFrameState state) { - super(address, state); + public LoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) { + super(kind, address, state); this.result = result; } @Override public void emitMemAccess(AMD64MacroAssembler masm) { - switch (address.getKind()) { + switch (kind) { case Boolean: case Byte: masm.movsxb(asRegister(result), address.toAddress()); @@ -163,15 +165,15 @@ @Use({REG}) protected AllocatableValue input; - public StoreOp(AMD64AddressValue address, AllocatableValue input, LIRFrameState state) { - super(address, state); + public StoreOp(Kind kind, AMD64AddressValue address, AllocatableValue input, LIRFrameState state) { + super(kind, address, state); this.input = input; } @Override public void emitMemAccess(AMD64MacroAssembler masm) { assert isRegister(input); - switch (address.getKind()) { + switch (kind) { case Boolean: case Byte: masm.movb(address.toAddress(), asRegister(input)); @@ -205,14 +207,14 @@ protected final Constant input; - public StoreConstantOp(AMD64AddressValue address, Constant input, LIRFrameState state) { - super(address, state); + public StoreConstantOp(Kind kind, AMD64AddressValue address, Constant input, LIRFrameState state) { + super(kind, address, state); this.input = input; } @Override public void emitMemAccess(AMD64MacroAssembler masm) { - switch (address.getKind()) { + switch (kind) { case Boolean: case Byte: masm.movb(address.toAddress(), input.asInt() & 0xFF); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegisterPreservationOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegisterPreservationOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,63 @@ +/* + * 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.lir.amd64; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.asm.*; + +/** + * Base class for the operations that save or restore registers around another operation that may + * potentially destroy any register (e.g., a call). + */ +public abstract class AMD64RegisterPreservationOp extends AMD64LIRInstruction { + + protected static void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value[] dst, Value[] src) { + for (int i = 0; i < dst.length; i++) { + if (dst[i] != null) { + AMD64Move.move(tasm, masm, dst[i], src[i]); + } else { + assert src[i] == null; + } + } + } + + protected static void doNotPreserve(Set registers, RegisterValue[] registerValues, StackSlot[] slots) { + for (int i = 0; i < slots.length; i++) { + if (registerValues[i] != null) { + if (registers.contains(registerValues[i].getRegister())) { + registerValues[i] = null; + slots[i] = null; + } + } + } + } + + /** + * Records that no registers in {@code registers} need to be preserved. + */ + public abstract void doNotPreserve(Set registers); +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,84 @@ +/* + * 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.lir.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Restores registers from stack slots. + */ +@Opcode("RESTORE_REGISTER") +public final class AMD64RestoreRegistersOp extends AMD64RegisterPreservationOp { + + @Use(STACK) protected StackSlot[] src; + @Def(REG) protected RegisterValue[] dst; + + public AMD64RestoreRegistersOp(StackSlot[] src, RegisterValue[] dst) { + this.src = src; + this.dst = dst; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + emitCode(tasm, masm, dst, src); + } + + @Override + public void doNotPreserve(Set registers) { + doNotPreserve(registers, dst, src); + } + + /** + * Updates {@code debugInfo} with a description of where each preserved register is saved. + */ + public void describePreservation(DebugInfo debugInfo, FrameMap frameMap) { + int preserved = 0; + for (RegisterValue r : dst) { + if (r != null) { + preserved++; + } + } + if (preserved != 0) { + Register[] keys = new Register[preserved]; + int[] values = new int[keys.length]; + int mapIndex = 0; + for (int i = 0; i < src.length; i++) { + if (dst[i] != null) { + keys[mapIndex] = dst[i].getRegister(); + values[mapIndex] = frameMap.indexForStackSlot(src[i]); + mapIndex++; + } + } + assert mapIndex == preserved; + debugInfo.setCalleeSaveInfo(new RegisterSaveLayout(keys, values)); + } + } +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,58 @@ +/* + * 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.lir.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Saves registers to stack slots. + */ +@Opcode("SAVE_REGISTER") +public final class AMD64SaveRegistersOp extends AMD64RegisterPreservationOp { + + @Use(REG) protected RegisterValue[] src; + @Def(STACK) protected StackSlot[] dst; + + public AMD64SaveRegistersOp(RegisterValue[] src, StackSlot[] dst) { + this.src = src; + this.dst = dst; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + emitCode(tasm, masm, dst, src); + } + + @Override + public void doNotPreserve(Set registers) { + doNotPreserve(registers, src, dst); + } + +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java Sun Apr 28 22:52:12 2013 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.ptx.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; /** * Represents an address in target machine memory, specified via some combination of a base register @@ -38,7 +39,7 @@ private static final long serialVersionUID = 1802222435353022623L; - @Component({REG, UNUSED}) private AllocatableValue base; + @Component({REG, OperandFlag.ILLEGAL}) private AllocatableValue base; private final long displacement; /** @@ -68,7 +69,7 @@ } public PTXAddress toAddress() { - Register baseReg = base == AllocatableValue.UNUSED ? Register.None : asRegister(base); + Register baseReg = base == Value.ILLEGAL ? Register.None : asRegister(base); return new PTXAddress(baseReg, displacement); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java Sun Apr 28 22:52:12 2013 +0200 @@ -25,7 +25,6 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.ptx.*; import com.oracle.graal.graph.*; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Sun Apr 28 22:52:12 2013 +0200 @@ -97,6 +97,7 @@ @SuppressWarnings("unused") public static class CondMoveOp extends PTXLIRInstruction { + @Def({REG, HINT}) protected Value result; @Alive({REG}) protected Value trueValue; @Use({REG, STACK, CONST}) protected Value falseValue; @@ -119,6 +120,7 @@ @SuppressWarnings("unused") public static class FloatCondMoveOp extends PTXLIRInstruction { + @Def({REG}) protected Value result; @Alive({REG}) protected Value trueValue; @Alive({REG}) protected Value falseValue; @@ -142,14 +144,14 @@ } public static class SequentialSwitchOp extends PTXLIRInstruction implements FallThroughOp { + @Use({CONST}) protected Constant[] keyConstants; private final LabelRef[] keyTargets; private LabelRef defaultTarget; @Alive({REG}) protected Value key; @Temp({REG, ILLEGAL}) protected Value scratch; - public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, - Value key, Value scratch) { + public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { assert keyConstants.length == keyTargets.length; this.keyConstants = keyConstants; this.keyTargets = keyTargets; @@ -216,14 +218,14 @@ } public static class TableSwitchOp extends PTXLIRInstruction { + private final int lowKey; private final LabelRef defaultTarget; private final LabelRef[] targets; @Alive protected Value index; @Temp protected Value scratch; - public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, - Variable index, Variable scratch) { + public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) { this.lowKey = lowKey; this.defaultTarget = defaultTarget; this.targets = targets; @@ -238,9 +240,7 @@ } @SuppressWarnings("unused") - private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey, - LabelRef defaultTarget, LabelRef[] targets, - Register value, Register scratch) { + private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Register value, Register scratch) { Buffer buf = masm.codeBuffer; // Compare index against jump table bounds int highKey = lowKey + targets.length - 1; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Sun Apr 28 22:52:12 2013 +0200 @@ -39,10 +39,10 @@ @Opcode("MOVE") public static class SpillMoveOp extends PTXLIRInstruction implements MoveOp { - @Def({REG, STACK}) protected Value result; + @Def({REG, STACK}) protected AllocatableValue result; @Use({REG, STACK, CONST}) protected Value input; - public SpillMoveOp(Value result, Value input) { + public SpillMoveOp(AllocatableValue result, Value input) { this.result = result; this.input = input; } @@ -58,7 +58,7 @@ } @Override - public Value getResult() { + public AllocatableValue getResult() { return result; } } @@ -66,10 +66,10 @@ @Opcode("MOVE") public static class MoveToRegOp extends PTXLIRInstruction implements MoveOp { - @Def({REG, HINT}) protected Value result; + @Def({REG, HINT}) protected AllocatableValue result; @Use({REG, STACK, CONST}) protected Value input; - public MoveToRegOp(Value result, Value input) { + public MoveToRegOp(AllocatableValue result, Value input) { this.result = result; this.input = input; } @@ -85,7 +85,7 @@ } @Override - public Value getResult() { + public AllocatableValue getResult() { return result; } } @@ -93,10 +93,10 @@ @Opcode("MOVE") public static class MoveFromRegOp extends PTXLIRInstruction implements MoveOp { - @Def({REG, STACK}) protected Value result; + @Def({REG, STACK}) protected AllocatableValue result; @Use({REG, CONST, HINT}) protected Value input; - public MoveFromRegOp(Value result, Value input) { + public MoveFromRegOp(AllocatableValue result, Value input) { this.result = result; this.input = input; } @@ -112,18 +112,20 @@ } @Override - public Value getResult() { + public AllocatableValue getResult() { return result; } } public static class LoadOp extends PTXLIRInstruction { + private final Kind kind; @Def({REG}) protected AllocatableValue result; @Use({COMPOSITE}) protected PTXAddressValue address; @State protected LIRFrameState state; - public LoadOp(AllocatableValue result, PTXAddressValue address, LIRFrameState state) { + public LoadOp(Kind kind, AllocatableValue result, PTXAddressValue address, LIRFrameState state) { + this.kind = kind; this.result = result; this.address = address; this.state = state; @@ -132,7 +134,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { PTXAddress addr = address.toAddress(); - switch (address.getKind()) { + switch (kind) { case Byte: masm.ld_global_s8(asRegister(result), addr.getBase(), addr.getDisplacement()); break; @@ -165,11 +167,13 @@ public static class StoreOp extends PTXLIRInstruction { + private final Kind kind; @Use({COMPOSITE}) protected PTXAddressValue address; @Use({REG}) protected AllocatableValue input; @State protected LIRFrameState state; - public StoreOp(PTXAddressValue address, AllocatableValue input, LIRFrameState state) { + public StoreOp(Kind kind, PTXAddressValue address, AllocatableValue input, LIRFrameState state) { + this.kind = kind; this.address = address; this.input = input; this.state = state; @@ -179,7 +183,7 @@ public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { assert isRegister(input); PTXAddress addr = address.toAddress(); - switch (address.getKind()) { + switch (kind) { case Byte: masm.st_global_s8(addr.getBase(), addr.getDisplacement(), asRegister(input)); break; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Sun Apr 28 22:52:12 2013 +0200 @@ -210,8 +210,7 @@ } /** - * Computes the offset of a stack slot relative to the frame register. This is also the bit - * index of stack slots in the reference map. + * Computes the offset of a stack slot relative to the frame register. * * @param slot a stack slot * @return the offset of the stack slot @@ -226,6 +225,18 @@ } /** + * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack + * slots in the reference map. + * + * @param slot a stack slot + * @return the index of the stack slot + */ + public int indexForStackSlot(StackSlot slot) { + assert offsetForStackSlot(slot) % target.wordSize == 0; + return offsetForStackSlot(slot) / target.wordSize; + } + + /** * Gets the offset to the stack area where callee-saved registers are stored. * * @return The offset to the callee save area (in bytes). @@ -285,7 +296,7 @@ return getSlot(kind, 0); } - private List freedSlots; + private Set freedSlots; /** * Frees a spill slot that was obtained via {@link #allocateSpillSlot(Kind)} such that it can be @@ -293,7 +304,7 @@ */ public void freeSpillSlot(StackSlot slot) { if (freedSlots == null) { - freedSlots = new ArrayList<>(); + freedSlots = new HashSet<>(); } freedSlots.add(slot); } @@ -329,11 +340,6 @@ } } - private int frameRefMapIndex(StackSlot slot) { - assert offsetForStackSlot(slot) % target.wordSize == 0; - return offsetForStackSlot(slot) / target.wordSize; - } - /** * Initializes a reference map that covers all registers of the target architecture. */ @@ -368,7 +374,7 @@ if (isRegister(location)) { registerRefMap.set(asRegister(location).number); } else if (isStackSlot(location)) { - int index = frameRefMapIndex(asStackSlot(location)); + int index = indexForStackSlot(asStackSlot(location)); frameRefMap.set(index); } else { assert isConstant(location); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Sun Apr 28 22:52:12 2013 +0200 @@ -64,7 +64,7 @@ public interface SpillMoveFactory { - LIRInstruction createMove(Value result, Value input); + LIRInstruction createMove(AllocatableValue result, Value input); } private boolean hasArgInCallerFrame; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Sun Apr 28 22:52:12 2013 +0200 @@ -181,11 +181,6 @@ ILLEGAL, /** - * The value can be {@link AllocatableValue#UNUSED}. - */ - UNUSED, - - /** * The register allocator should try to assign a certain register to improve code quality. * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints. */ @@ -205,10 +200,10 @@ static { ALLOWED_FLAGS = new EnumMap<>(OperandMode.class); - ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED)); - ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED)); - ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, UNUSED, HINT)); - ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, UNUSED, HINT)); + ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED)); + ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED)); + ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, HINT)); + ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT)); } /** diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Sun Apr 28 22:52:12 2013 +0200 @@ -232,8 +232,7 @@ 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)) || - (value == AllocatableValue.UNUSED && flags.contains(OperandFlag.UNUSED))) { + (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) { return value; } TTY.println("instruction %s", op); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,14 +22,14 @@ */ package com.oracle.graal.lir; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.cfg.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - /** * A collection of machine-independent LIR operations, as well as interfaces to be implemented for * specific kinds or LIR operations. @@ -117,7 +117,7 @@ Value getInput(); - Value getResult(); + AllocatableValue getResult(); } /** diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Sun Apr 28 22:52:12 2013 +0200 @@ -113,7 +113,7 @@ Debug.metric("TargetMethods").increment(); Debug.metric("CodeBytesEmitted").add(compilationResult.getTargetCodeSize()); - Debug.metric("SafepointsEmitted").add(compilationResult.getInfopoints().size()); + Debug.metric("InfopointsEmitted").add(compilationResult.getInfopoints().size()); Debug.metric("DataPatches").add(ldp.size()); Debug.metric("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size()); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -25,10 +25,14 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; @@ -146,18 +150,169 @@ tool.deleteBranch(falseSuccessor()); tool.addToWorkList(trueSuccessor()); ((StructuredGraph) graph()).removeSplit(this, trueSuccessor()); + return; } else { tool.deleteBranch(trueSuccessor()); tool.addToWorkList(falseSuccessor()); ((StructuredGraph) graph()).removeSplit(this, falseSuccessor()); + return; } - } else if (trueSuccessor().guards().isEmpty() && falseSuccessor().guards().isEmpty()) { - if (!removeOrMaterializeIf(tool)) { - removeIntermediateMaterialization(tool); + } else if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) { + + if (removeOrMaterializeIf(tool)) { + return; + } + } + + if (removeIntermediateMaterialization(tool)) { + return; + } + + if (falseSuccessor().usages().isEmpty() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) { + BeginNode intermediateBegin = falseSuccessor(); + IfNode nextIf = (IfNode) intermediateBegin.next(); + double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability; + if (this.trueSuccessorProbability < probabilityB) { + // Reordering of those two if statements is beneficial from the point of view of + // their probabilities. + if (prepareForSwap(tool.runtime(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) { + // Reording is allowed from (if1 => begin => if2) to (if2 => begin => if1). + assert intermediateBegin.next() == nextIf; + BeginNode bothFalseBegin = nextIf.falseSuccessor(); + nextIf.setFalseSuccessor(null); + intermediateBegin.setNext(null); + this.setFalseSuccessor(null); + + this.replaceAtPredecessor(nextIf); + nextIf.setFalseSuccessor(intermediateBegin); + intermediateBegin.setNext(this); + this.setFalseSuccessor(bothFalseBegin); + return; + } } } } + private static boolean prepareForSwap(MetaAccessProvider runtime, LogicNode a, LogicNode b, double probabilityA, double probabilityB) { + if (a instanceof InstanceOfNode) { + InstanceOfNode instanceOfA = (InstanceOfNode) a; + if (b instanceof IsNullNode) { + IsNullNode isNullNode = (IsNullNode) b; + if (isNullNode.object() == instanceOfA.object()) { + if (instanceOfA.profile() != null && instanceOfA.profile().getNullSeen() != TriState.FALSE) { + instanceOfA.setProfile(new JavaTypeProfile(TriState.FALSE, instanceOfA.profile().getNotRecordedProbability(), instanceOfA.profile().getTypes())); + } + Debug.log("Can swap instanceof and isnull if"); + return true; + } + } else if (b instanceof InstanceOfNode) { + InstanceOfNode instanceOfB = (InstanceOfNode) b; + if (instanceOfA.object() == instanceOfB.object() && !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) { + // Two instanceof on the same value with mutually exclusive types. + JavaTypeProfile profileA = instanceOfA.profile(); + JavaTypeProfile profileB = instanceOfB.profile(); + + Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type()); + JavaTypeProfile newProfile = null; + if (profileA != null && profileB != null) { + double remainder = 1.0; + ArrayList profiledTypes = new ArrayList<>(); + for (ProfiledType type : profileB.getTypes()) { + if (instanceOfB.type().isAssignableFrom(type.getType())) { + // Do not add to profile. + } else { + ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() * (1.0 - probabilityA) / (1.0 - probabilityB))); + profiledTypes.add(newType); + remainder -= newType.getProbability(); + } + } + + for (ProfiledType type : profileA.getTypes()) { + if (instanceOfA.type().isAssignableFrom(type.getType())) { + ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() / (1.0 - probabilityB))); + profiledTypes.add(newType); + remainder -= newType.getProbability(); + } + } + Collections.sort(profiledTypes); + + if (remainder < 0.0) { + // Can happen due to round-off errors. + remainder = 0.0; + } + newProfile = new JavaTypeProfile(profileB.getNullSeen(), remainder, profiledTypes.toArray(new ProfiledType[profiledTypes.size()])); + Debug.log("First profile: %s", profileA); + Debug.log("Original second profile: %s", profileB); + Debug.log("New second profile: %s", newProfile); + } + instanceOfB.setProfile(profileA); + instanceOfA.setProfile(newProfile); + return true; + } + } + } else if (a instanceof CompareNode) { + CompareNode compareA = (CompareNode) a; + Condition conditionA = compareA.condition(); + if (compareA.unorderedIsTrue()) { + return false; + } + if (b instanceof CompareNode) { + CompareNode compareB = (CompareNode) b; + if (compareA == compareB) { + Debug.log("Same conditions => do not swap and leave the work for global value numbering."); + return false; + } + if (compareB.unorderedIsTrue()) { + return false; + } + Condition comparableCondition = null; + Condition conditionB = compareB.condition(); + if (compareB.x() == compareA.x() && compareB.y() == compareA.y()) { + comparableCondition = conditionB; + } else if (compareB.x() == compareA.y() && compareB.y() == compareA.x()) { + comparableCondition = conditionB.mirror(); + } + + if (comparableCondition != null) { + Condition combined = conditionA.join(comparableCondition); + if (combined == null) { + // The two conditions are disjoint => can reorder. + Debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition); + return true; + } + } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) { + boolean canSwap = false; + if ((compareA.x() == compareB.x() && valuesDistinct(runtime, compareA.y(), compareB.y()))) { + canSwap = true; + } else if ((compareA.x() == compareB.y() && valuesDistinct(runtime, compareA.y(), compareB.x()))) { + canSwap = true; + } else if ((compareA.y() == compareB.x() && valuesDistinct(runtime, compareA.x(), compareB.y()))) { + canSwap = true; + } else if ((compareA.y() == compareB.y() && valuesDistinct(runtime, compareA.x(), compareB.x()))) { + canSwap = true; + } + + if (canSwap) { + Debug.log("Can swap equality condition with one shared and one disjoint value."); + return true; + } + } + } + } + + return false; + } + + private static boolean valuesDistinct(MetaAccessProvider runtime, ValueNode a, ValueNode b) { + if (a.isConstant() && b.isConstant()) { + return !runtime.constantEquals(a.asConstant(), b.asConstant()); + } + + Stamp stampA = a.stamp(); + Stamp stampB = b.stamp(); + return stampA.alwaysDistinct(stampB); + } + /** * Tries to remove an empty if construct or replace an if construct with a materialization. * @@ -173,7 +328,7 @@ if (!phis.hasNext()) { // empty if construct with no phis: remove it removeEmptyIf(tool); - return false; + return true; } else { PhiNode singlePhi = phis.next(); if (!phis.hasNext()) { @@ -260,11 +415,12 @@ return false; } - MergeNode merge = (MergeNode) predecessor(); - if (!merge.anchored().isEmpty()) { + if (predecessor() instanceof LoopBeginNode) { return false; } + MergeNode merge = (MergeNode) predecessor(); + // Only consider merges with a single usage that is both a phi and an operand of the // comparison NodeIterable mergeUsages = merge.usages(); @@ -289,10 +445,7 @@ } List mergePredecessors = merge.cfgPredecessors().snapshot(); - if (phi.valueCount() != merge.forwardEndCount()) { - // Handles a loop begin merge - return false; - } + assert phi.valueCount() == merge.forwardEndCount(); Constant[] xs = constantValues(compare.x(), merge); Constant[] ys = constantValues(compare.y(), merge); @@ -300,6 +453,11 @@ return false; } + // Sanity check that both ends are not followed by a merge without frame state. + if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) { + return false; + } + List falseEnds = new ArrayList<>(mergePredecessors.size()); List trueEnds = new ArrayList<>(mergePredecessors.size()); Map phiValues = new HashMap<>(mergePredecessors.size()); @@ -336,6 +494,45 @@ return true; } + private static boolean checkFrameState(FixedNode start) { + FixedNode node = start; + while (true) { + if (node instanceof MergeNode) { + MergeNode mergeNode = (MergeNode) node; + if (mergeNode.stateAfter() == null) { + return false; + } else { + return true; + } + } else if (node instanceof StateSplit) { + StateSplit stateSplitNode = (StateSplit) node; + if (stateSplitNode.stateAfter() != null) { + return true; + } + } + + if (node instanceof ControlSplitNode) { + ControlSplitNode controlSplitNode = (ControlSplitNode) node; + for (Node succ : controlSplitNode.cfgSuccessors()) { + if (checkFrameState((FixedNode) succ)) { + return true; + } + } + return false; + } else if (node instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node; + node = fixedWithNextNode.next(); + } else if (node instanceof EndNode) { + EndNode endNode = (EndNode) node; + node = endNode.merge(); + } else if (node instanceof ControlSinkNode) { + return true; + } else { + return false; + } + } + } + /** * Connects a set of ends to a given successor, inserting a merge node if there is more than one * end. If {@code ends} is empty, then {@code successor} is diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -144,7 +144,7 @@ } if (node instanceof FixedWithNextNode) { ((StructuredGraph) graph()).replaceFixedWithFixed(this, (FixedWithNextNode) node); - } else if (node instanceof DeoptimizeNode) { + } else if (node instanceof ControlSinkNode) { this.replaceAtPredecessor(node); this.replaceAtUsages(null); GraphUtil.killCFG(this); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -188,7 +188,7 @@ if (node == null) { assert kind() == Kind.Void && usages().isEmpty(); ((StructuredGraph) graph()).removeSplit(this, next()); - } else if (node instanceof DeoptimizeNode) { + } else if (node instanceof ControlSinkNode) { this.replaceAtPredecessor(node); this.replaceAtUsages(null); GraphUtil.killCFG(this); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -154,6 +154,10 @@ if (this.anchored().isNotEmpty()) { return; } + if (merge.stateAfter() == null && this.stateAfter() != null) { + // We hold a state, but the succeeding merge does not => do not combine. + return; + } for (PhiNode phi : phis()) { for (Node usage : phi.usages().filter(isNotA(FrameState.class))) { if (!merge.isPhiAtMerge(usage)) { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,131 @@ +/* + * 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.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A node that attached a type profile to a proxied input node. + */ +public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType { + + @Input private ValueNode object; + private final JavaTypeProfile profile; + private transient ResolvedJavaType lastCheckedType; + private transient JavaTypeProfile lastCheckedProfile; + + public ValueNode getObject() { + return object; + } + + public static ValueNode create(ValueNode object, JavaTypeProfile profile) { + if (profile == null) { + // No profile, so create no node. + return object; + } + if (profile.getTypes().length == 0) { + // Only null profiling is not beneficial enough to keep the node around. + return object; + } + return object.graph().add(new TypeProfileProxyNode(object, profile)); + } + + private TypeProfileProxyNode(ValueNode object, JavaTypeProfile profile) { + super(object.stamp()); + this.object = object; + this.profile = profile; + } + + public JavaTypeProfile getProfile() { + return profile; + } + + @Override + public boolean inferStamp() { + return object.inferStamp(); + } + + @Override + public Stamp stamp() { + return object.stamp(); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (object.objectStamp().isExactType()) { + // The profile is useless - we know the type! + return object; + } else if (object instanceof TypeProfileProxyNode) { + TypeProfileProxyNode other = (TypeProfileProxyNode) object; + JavaTypeProfile otherProfile = other.getProfile(); + if (otherProfile == lastCheckedProfile) { + // We have already incorporated the knowledge about this profile => abort. + return this; + } + lastCheckedProfile = otherProfile; + JavaTypeProfile newProfile = this.profile.restrict(otherProfile); + if (newProfile.equals(otherProfile)) { + // We are useless - just use the other proxy node. + Debug.log("Canonicalize with other proxy node."); + return object; + } + if (newProfile != this.profile) { + Debug.log("Improved profile via other profile."); + return TypeProfileProxyNode.create(object, newProfile); + } + } else if (object.objectStamp().type() != null) { + ResolvedJavaType type = object.objectStamp().type(); + ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype(); + if (uniqueConcrete != null) { + // Profile is useless => remove. + Debug.log("Profile useless, there is enough static type information available."); + return object; + } + if (type == lastCheckedType) { + // We have already incorporate the knowledge about this type => abort. + } + lastCheckedType = type; + JavaTypeProfile newProfile = this.profile.restrict(type, object.objectStamp().nonNull()); + if (newProfile != this.profile) { + Debug.log("Improved profile via static type information."); + if (newProfile.getTypes().length == 0) { + // Only null profiling is not beneficial enough to keep the node around. + return object; + } + return TypeProfileProxyNode.create(object, newProfile); + } + } + return this; + } + + public static void cleanFromGraph(StructuredGraph graph) { + for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) { + proxy.replaceAtUsages(proxy.getObject()); + } + } +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -91,18 +91,6 @@ return getY().generateAddress(gen, xAddr); } - @Override - public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) { - Value xAddr = getX().generateAddress(gen, base); - return getY().generateLoad(gen, xAddr, deopting); - } - - @Override - public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) { - Value xAddr = getX().generateAddress(gen, base); - getY().generateStore(gen, xAddr, value, deopting); - } - @NodeIntrinsic public static native Location addLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, Location x, Location y); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,7 +24,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; /** @@ -56,16 +55,6 @@ @Override public Value generateAddress(LIRGeneratorTool gen, Value base) { - return gen.emitLea(base, displacement(), Value.ILLEGAL, 0); - } - - @Override - public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) { - return gen.emitLoad(getValueKind(), base, displacement(), Value.ILLEGAL, 0, deopting); - } - - @Override - public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) { - gen.emitStore(getValueKind(), base, displacement(), Value.ILLEGAL, 0, value, deopting); + return gen.emitAddress(base, displacement(), Value.ILLEGAL, 0); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -53,7 +54,8 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this)); + Value address = location().generateAddress(gen, gen.operand(object())); + gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this)); } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -91,17 +91,7 @@ @Override public Value generateAddress(LIRGeneratorTool gen, Value base) { - return gen.emitLea(base, displacement, gen.operand(index()), indexScaling()); - } - - @Override - public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) { - return gen.emitLoad(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), deopting); - } - - @Override - public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) { - gen.emitStore(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), value, deopting); + return gen.emitAddress(base, displacement, gen.operand(index()), indexScaling()); } @NodeIntrinsic diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,60 @@ +/* + * 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.extended; + +import java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Loads a method from the virtual method table of a given hub. + */ +public final class LoadMethodNode extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode hub; + private final ResolvedJavaMethod method; + + public ValueNode getHub() { + return hub; + } + + public LoadMethodNode(ResolvedJavaMethod method, ValueNode hub, Kind kind) { + super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind)); + this.hub = hub; + this.method = method; + assert !Modifier.isAbstract(method.getModifiers()) : "Cannot load abstract method from a hub"; + assert !Modifier.isStatic(method.getModifiers()) : "Cannot load a static method from a hub"; + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + tool.getRuntime().lower(this, tool); + } + + public ResolvedJavaMethod getMethod() { + return method; + } +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,7 +24,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ValueNumberable; -import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -100,8 +99,4 @@ } public abstract Value generateAddress(LIRGeneratorTool gen, Value base); - - public abstract Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting); - - public abstract void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -57,7 +57,8 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this)); + Value address = location().generateAddress(gen, gen.operand(object())); + gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this)); } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -91,7 +91,7 @@ public void generate(LIRGeneratorTool generator) { if (kind() != object().kind()) { assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value"; - Value result = generator.newVariable(kind()); + AllocatableValue result = generator.newVariable(kind()); generator.emitMove(result, generator.operand(object())); generator.setResult(this, result); } else { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,10 +22,11 @@ */ 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.*; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.graph.*; /** * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}. @@ -84,7 +85,8 @@ @Override public void generate(LIRGeneratorTool gen) { - location().generateStore(gen, gen.operand(object()), gen.operand(value()), this); + Value address = location().generateAddress(gen, gen.operand(object())); + gen.emitStore(location().getValueKind(), address, gen.operand(value()), this); } @NodeIntrinsic diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -80,7 +80,7 @@ @Override public boolean verify() { for (Node usage : usages()) { - assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage); + assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage); } return super.verify(); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -36,7 +36,7 @@ @Input private ValueNode object; private final ResolvedJavaType type; - private final JavaTypeProfile profile; + private JavaTypeProfile profile; /** * Constructs a new InstanceOfNode. @@ -109,10 +109,14 @@ return profile; } + public void setProfile(JavaTypeProfile profile) { + this.profile = profile; + } + @Override public boolean verify() { for (Node usage : usages()) { - assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage); + assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: ", usage); } return super.verify(); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.java; +import java.lang.reflect.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -102,6 +104,14 @@ for (Node n : usages()) { assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n); } + if (invokeKind == InvokeKind.Special || invokeKind == InvokeKind.Static) { + assertFalse(Modifier.isAbstract(targetMethod.getModifiers()), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod); + } + if (invokeKind == InvokeKind.Static) { + assertTrue(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for static methods (%s)", targetMethod); + } else { + assertFalse(Modifier.isStatic(targetMethod.getModifiers()), "static calls are only allowed for non-static methods (%s)", targetMethod); + } return super.verify(); } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Sun Apr 28 22:52:12 2013 +0200 @@ -29,11 +29,11 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; -public abstract class LIRGeneratorTool { +public interface LIRGeneratorTool { - public abstract TargetDescription target(); + TargetDescription target(); - public abstract CodeCacheProvider getRuntime(); + CodeCacheProvider getRuntime(); /** * Checks whether the supplied constant can be used without loading it into a register for most @@ -43,100 +43,99 @@ * @return True if the constant can be used directly, false if the constant needs to be in a * register. */ - public abstract boolean canInlineConstant(Constant c); + boolean canInlineConstant(Constant c); - public abstract RegisterAttributes attributes(Register register); + RegisterAttributes attributes(Register register); - public abstract Value operand(ValueNode object); + Value operand(ValueNode object); - public abstract AllocatableValue newVariable(Kind kind); + AllocatableValue newVariable(Kind kind); - public abstract Value setResult(ValueNode x, Value operand); + Value setResult(ValueNode x, Value operand); - public abstract Value emitMove(Value input); + AllocatableValue emitMove(Value input); - public abstract void emitMove(Value dst, Value src); + void emitMove(AllocatableValue dst, Value src); - public abstract Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting); + Value emitAddress(Value base, long displacement, Value index, int scale); - public abstract void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode deopting); + Value emitAddress(StackSlot slot); - public abstract Value emitLea(Value base, long displacement, Value index, int scale); + Value emitLoad(Kind kind, Value address, DeoptimizingNode deopting); - public abstract Value emitLea(StackSlot slot); + void emitStore(Kind kind, Value address, Value input, DeoptimizingNode deopting); - public abstract Value emitNegate(Value input); + Value emitNegate(Value input); - public abstract Value emitAdd(Value a, Value b); + Value emitAdd(Value a, Value b); - public abstract Value emitSub(Value a, Value b); + Value emitSub(Value a, Value b); - public abstract Value emitMul(Value a, Value b); + Value emitMul(Value a, Value b); - public abstract Value emitDiv(Value a, Value b, DeoptimizingNode deopting); + Value emitDiv(Value a, Value b, DeoptimizingNode deopting); - public abstract Value emitRem(Value a, Value b, DeoptimizingNode deopting); + Value emitRem(Value a, Value b, DeoptimizingNode deopting); - public abstract Value emitUDiv(Value a, Value b, DeoptimizingNode deopting); + Value emitUDiv(Value a, Value b, DeoptimizingNode deopting); - public abstract Value emitURem(Value a, Value b, DeoptimizingNode deopting); + Value emitURem(Value a, Value b, DeoptimizingNode deopting); - public abstract Value emitAnd(Value a, Value b); + Value emitAnd(Value a, Value b); - public abstract Value emitOr(Value a, Value b); + Value emitOr(Value a, Value b); - public abstract Value emitXor(Value a, Value b); + Value emitXor(Value a, Value b); - public abstract Value emitShl(Value a, Value b); + Value emitShl(Value a, Value b); - public abstract Value emitShr(Value a, Value b); + Value emitShr(Value a, Value b); - public abstract Value emitUShr(Value a, Value b); + Value emitUShr(Value a, Value b); - public abstract Value emitConvert(ConvertNode.Op opcode, Value inputVal); + Value emitConvert(ConvertNode.Op opcode, Value inputVal); - public abstract void emitMembar(int barriers); + void emitMembar(int barriers); - public abstract void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting); + void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting); - public abstract void emitNullCheck(ValueNode v, DeoptimizingNode deopting); + void emitNullCheck(ValueNode v, DeoptimizingNode deopting); - public abstract Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args); + Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args); - public abstract void emitIf(IfNode i); + void emitIf(IfNode i); - public abstract void emitConditional(ConditionalNode i); + void emitConditional(ConditionalNode i); - public abstract void emitSwitch(SwitchNode i); + void emitSwitch(SwitchNode i); - public abstract void emitInvoke(Invoke i); + void emitInvoke(Invoke i); - public abstract void visitRuntimeCall(RuntimeCallNode i); + void visitRuntimeCall(RuntimeCallNode i); // Handling of block-end nodes still needs to be unified in the LIRGenerator. - public abstract void visitMerge(MergeNode i); + void visitMerge(MergeNode i); - public abstract void visitEndNode(EndNode i); + void visitEndNode(EndNode i); - public abstract void visitLoopEnd(LoopEndNode i); + void visitLoopEnd(LoopEndNode i); - public abstract void visitCompareAndSwap(CompareAndSwapNode i); + void visitCompareAndSwap(CompareAndSwapNode i); // These methods define the contract a runtime specific backend must provide. - public abstract void visitReturn(ReturnNode i); + void visitReturn(ReturnNode i); - public abstract void visitSafepointNode(SafepointNode i); + void visitSafepointNode(SafepointNode i); - public abstract void visitBreakpointNode(BreakpointNode i); + void visitBreakpointNode(BreakpointNode i); - public abstract void emitUnwind(Value operand); + void emitUnwind(Value operand); /** * Called just before register allocation is performed on the LIR owned by this generator. */ - public void beforeRegisterAllocation() { - } + void beforeRegisterAllocation(); - public abstract void visitInfopointNode(InfopointNode i); + void visitInfopointNode(InfopointNode i); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Sun Apr 28 22:52:12 2013 +0200 @@ -34,7 +34,7 @@ Replacements getReplacements(); - ValueNode createNullCheckGuard(ValueNode object); + ValueNode createNullCheckGuard(NodeInputList dependencies, ValueNode object); ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Sun Apr 28 22:52:12 2013 +0200 @@ -229,7 +229,7 @@ public static RuntimeException approxSourceException(Node node, Throwable cause) { final StackTraceElement[] elements = approxSourceStackTraceElement(node); @SuppressWarnings("serial") - RuntimeException exception = new RuntimeException(cause.getMessage(), cause) { + RuntimeException exception = new RuntimeException((cause == null) ? null : cause.getMessage(), cause) { @Override public final synchronized Throwable fillInStackTrace() { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,14 +22,13 @@ */ package com.oracle.graal.phases.common; -import java.util.*; import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; @@ -49,6 +48,7 @@ public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits"); private final CustomCanonicalizer customCanonicalizer; + private final Iterable workingSet; public interface CustomCanonicalizer { @@ -60,12 +60,17 @@ } public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer) { + this(customCanonicalizer, null); + } + + public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer, Iterable workingSet) { this.customCanonicalizer = customCanonicalizer; + this.workingSet = workingSet; } @Override protected void run(StructuredGraph graph, PhaseContext context) { - new Instance(context.getRuntime(), context.getAssumptions(), null, customCanonicalizer).run(graph); + new Instance(context.getRuntime(), context.getAssumptions(), workingSet, customCanonicalizer).run(graph); } public static class Instance extends Phase { @@ -78,7 +83,6 @@ private NodeWorkList workList; private Tool tool; - private List snapshotTemp; public Instance(MetaAccessProvider runtime, Assumptions assumptions) { this(runtime, assumptions, null, 0, null); @@ -110,7 +114,6 @@ this.runtime = runtime; this.customCanonicalizer = customCanonicalizer; this.initWorkingSet = workingSet; - this.snapshotTemp = new ArrayList<>(); } @Override @@ -129,19 +132,22 @@ } private void processWorkSet(StructuredGraph graph) { - graph.trackInputChange(new InputChangedListener() { + NodeChangedListener nodeChangedListener = new NodeChangedListener() { @Override - public void inputChanged(Node node) { + public void nodeChanged(Node node) { workList.addAgain(node); } - }); + }; + graph.trackInputChange(nodeChangedListener); + graph.trackUsagesDroppedZero(nodeChangedListener); for (Node n : workList) { processNode(n, graph); } graph.stopTrackingInputChange(); + graph.stopTrackingUsagesDroppedZero(); } private void processNode(Node node, StructuredGraph graph) { @@ -153,17 +159,9 @@ } int mark = graph.getMark(); if (!tryKillUnused(node)) { - node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); if (!tryCanonicalize(node, graph)) { tryInferStamp(node, graph); - } else { - for (Node in : snapshotTemp) { - if (in.isAlive() && in.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(in); - } - } } - snapshotTemp.clear(); } for (Node newNode : graph.getNewNodes(mark)) { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -27,7 +27,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -78,22 +77,18 @@ IfNode ifNode = (IfNode) deoptBegin.predecessor(); BeginNode otherBegin = ifNode.trueSuccessor(); LogicNode conditionNode = ifNode.condition(); - if (!(conditionNode instanceof InstanceOfNode) && !(conditionNode instanceof InstanceOfDynamicNode)) { - // TODO The lowering currently does not support a FixedGuard as the usage of an - // InstanceOfNode. Relax this restriction. - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor())); - FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); - if (deoptBegin == ifNode.trueSuccessor()) { - graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor()); - } else { - graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor()); - } - Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); - FixedNode next = pred.next(); - pred.setNext(guard); - guard.setNext(next); - return; + FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor())); + FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); + if (deoptBegin == ifNode.trueSuccessor()) { + graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor()); + } else { + graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor()); } + Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); + FixedNode next = pred.next(); + pred.setNext(guard); + guard.setNext(next); + return; } // We could not convert the control split - at least cut off control flow after the split. diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -67,7 +67,8 @@ if (node instanceof DeoptimizingNode) { DeoptimizingNode deopt = (DeoptimizingNode) node; if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) { - deopt.setDeoptimizationState(currentState.getFramestate()); + FrameState state = currentState.getFramestate(); + deopt.setDeoptimizationState(state); } } @@ -93,7 +94,7 @@ if (merge.stateAfter() != null) { return new FrameStateAssignmentState(merge.stateAfter()); } - return new FrameStateAssignmentState(singleFrameState(states)); + return new FrameStateAssignmentState(singleFrameState(merge, states)); } @Override @@ -125,15 +126,34 @@ return true; } - private static FrameState singleFrameState(List states) { - Iterator it = states.iterator(); - assert it.hasNext(); - FrameState first = it.next().getFramestate(); - while (it.hasNext()) { - if (first != it.next().getFramestate()) { + private static FrameState singleFrameState(@SuppressWarnings("unused") MergeNode merge, List states) { + if (states.size() == 0) { + return null; + } + FrameState firstState = states.get(0).getFramestate(); + FrameState singleState = firstState; + if (singleState == null) { + return null; + } + int singleBci = singleState.bci; + for (int i = 1; i < states.size(); ++i) { + FrameState cur = states.get(i).getFramestate(); + if (cur == null) { return null; } + + if (cur != singleState) { + singleState = null; + } + + if (cur.bci != singleBci) { + singleBci = FrameState.INVALID_FRAMESTATE_BCI; + } + } - return first; + if (singleState != null) { + return singleState; + } + return null; } } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -144,6 +144,9 @@ } } } + + // Clean up type profiles. + TypeProfileProxyNode.cleanFromGraph(graph); } @Override diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Sun Apr 28 22:52:12 2013 +0200 @@ -42,6 +42,7 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; public class InliningUtil { @@ -254,6 +255,10 @@ Class macroNodeClass = getMacroNodeClass(replacements, concrete); StructuredGraph graph = (StructuredGraph) invoke.asNode().graph(); if (macroNodeClass != null) { + if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != concrete) { + assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static; + InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete); + } FixedWithNextNode macroNode; try { macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke); @@ -294,12 +299,12 @@ } }); } + } - protected void replaceInvokeCallTarget(StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) { - MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget(); - MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType())); - invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget); - } + public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) { + MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget(); + MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType())); + invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget); } /** @@ -378,7 +383,7 @@ @Override public void tryToDevirtualizeInvoke(StructuredGraph graph, MetaAccessProvider runtime, Assumptions assumptions) { createGuard(graph, runtime); - replaceInvokeCallTarget(graph, InvokeKind.Special, concrete); + replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete); } private void createGuard(StructuredGraph graph, MetaAccessProvider runtime) { @@ -414,14 +419,17 @@ public final List concretes; public final ArrayList ptypes; - public final int[] typesToConcretes; + public final ArrayList typesToConcretes; public final double notRecordedTypeProbability; + private final ArrayList concretesProbabilities; - public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList ptypes, int[] typesToConcretes, double notRecordedTypeProbability) { + public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList concretesProbabilities, ArrayList ptypes, + ArrayList typesToConcretes, double notRecordedTypeProbability) { super(invoke); - assert concretes.size() > 0 && concretes.size() <= ptypes.size() : "must have at least one method but no more than types methods"; - assert ptypes.size() == typesToConcretes.length : "array lengths must match"; + assert concretes.size() > 0 : "must have at least one method"; + assert ptypes.size() == typesToConcretes.size() : "array lengths must match"; + this.concretesProbabilities = concretesProbabilities; this.concretes = concretes; this.ptypes = ptypes; this.typesToConcretes = typesToConcretes; @@ -444,9 +452,9 @@ // receiver null check must be the first node InliningUtil.receiverNullCheck(invoke); if (hasSingleMethod()) { - inlineSingleMethod(graph, callback, replacements, assumptions); + inlineSingleMethod(graph, callback, replacements, assumptions, runtime); } else { - inlineMultipleMethods(graph, callback, replacements, assumptions); + inlineMultipleMethods(graph, callback, replacements, assumptions, runtime); } } @@ -458,7 +466,7 @@ return notRecordedTypeProbability > 0; } - private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions) { + private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions, MetaAccessProvider runtime) { int numberOfMethods = concretes.size(); FixedNode continuation = invoke.next(); @@ -513,7 +521,7 @@ assert invoke.asNode().isAlive(); // replace the invoke with a switch on the type of the actual receiver - createDispatchOnTypeBeforeInvoke(graph, successors, false); + boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime); assert invoke.next() == continuation; invoke.setNext(null); @@ -528,9 +536,15 @@ BeginNode node = successors[i]; Invoke invokeForInlining = (Invoke) node.next(); - ResolvedJavaType commonType = getLeastCommonType(i); + ResolvedJavaType commonType; + if (methodDispatch) { + commonType = concretes.get(i).getDeclaringClass(); + } else { + commonType = getLeastCommonType(i); + } + ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver(); - boolean exact = getTypeCount(i) == 1; + boolean exact = (getTypeCount(i) == 1 && !methodDispatch); PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact); invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver); @@ -541,6 +555,7 @@ if (shouldFallbackToInvoke()) { replacementNodes.add(null); } + if (GraalOptions.OptTailDuplication) { /* * We might want to perform tail duplication at the merge after a type switch, if @@ -560,15 +575,15 @@ if (opportunities > 0) { metricInliningTailDuplication.increment(); Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities); - TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes); + TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, new HighTierContext(runtime, assumptions, replacements)); } } } private int getTypeCount(int concreteMethodIndex) { int count = 0; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { + for (int i = 0; i < typesToConcretes.size(); i++) { + if (typesToConcretes.get(i) == concreteMethodIndex) { count++; } } @@ -577,8 +592,8 @@ private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) { ResolvedJavaType commonType = null; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { + for (int i = 0; i < typesToConcretes.size(); i++) { + if (typesToConcretes.get(i) == concreteMethodIndex) { if (commonType == null) { commonType = ptypes.get(i).getType(); } else { @@ -598,14 +613,14 @@ return result; } - private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions) { + private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions, MetaAccessProvider runtime) { assert concretes.size() == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; BeginNode calleeEntryNode = graph.add(new BeginNode()); BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux}; - createDispatchOnTypeBeforeInvoke(graph, successors, false); + createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime); calleeEntryNode.setNext(invoke.asNode()); @@ -613,20 +628,57 @@ inline(invoke, concrete, callback, replacements, assumptions, false); } - private void createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor) { - assert ptypes.size() > 1; + private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider runtime) { + assert ptypes.size() >= 1; Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind(); LoadHubNode hub = graph.add(new LoadHubNode(((MethodCallTargetNode) invoke.callTarget()).receiver(), hubKind)); graph.addBeforeFixed(invoke.asNode(), hub); + if (!invokeIsOnlySuccessor && chooseMethodDispatch()) { + assert successors.length == concretes.size() + 1; + assert concretes.size() > 0; + Debug.log("Method check cascade with %d methods", concretes.size()); + + LoadMethodNode[] methods = new LoadMethodNode[concretes.size()]; + ValueNode[] constantMethods = new ValueNode[concretes.size()]; + double[] probability = new double[concretes.size()]; + for (int i = 0; i < concretes.size(); ++i) { + ResolvedJavaMethod firstMethod = concretes.get(i); + Constant firstMethodConstant = firstMethod.getEncoding(); + + ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, runtime, graph); + constantMethods[i] = firstMethodConstantNode; + probability[i] = concretesProbabilities.get(i); + if (i > 0) { + probability[i] /= (1.0 - probability[i - 1]); + } + } + + FixedNode lastSucc = successors[concretes.size()]; + for (int i = concretes.size() - 1; i >= 0; --i) { + LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].kind())); + methods[i] = method; + CompareNode methodCheck = CompareNode.createCompareNode(Condition.EQ, methods[i], constantMethods[i]); + IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i])); + method.setNext(ifNode); + lastSucc = method; + } + + FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor(); + pred.setNext(lastSucc); + return true; + } else { + Debug.log("Type switch with %d types", concretes.size()); + } + ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()]; double[] keyProbabilities = new double[ptypes.size() + 1]; int[] keySuccessors = new int[ptypes.size() + 1]; for (int i = 0; i < ptypes.size(); i++) { keys[i] = ptypes.get(i).getType(); keyProbabilities[i] = ptypes.get(i).getProbability(); - keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes[i]; + keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i); assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux"; } keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability; @@ -635,6 +687,45 @@ TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors)); FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor(); pred.setNext(typeSwitch); + return false; + } + + private boolean chooseMethodDispatch() { + if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) { + // Always chose method dispatch if there is a single concrete method and the call + // site is megamorphic. + return true; + } + + if (concretes.size() == ptypes.size()) { + // Always prefer types over methods if the number of types is smaller than the + // number of methods. + return false; + } + + return chooseMethodDispatchCostBased(); + } + + private boolean chooseMethodDispatchCostBased() { + double remainder = 1.0 - this.notRecordedTypeProbability; + double costEstimateMethodDispatch = remainder; + for (int i = 0; i < concretes.size(); ++i) { + if (i != 0) { + costEstimateMethodDispatch += remainder; + } + remainder -= concretesProbabilities.get(i); + } + + double costEstimateTypeDispatch = 0.0; + remainder = 1.0; + for (int i = 0; i < ptypes.size(); ++i) { + if (i != 0) { + costEstimateTypeDispatch += remainder; + } + remainder -= ptypes.get(i).getProbability(); + } + costEstimateTypeDispatch += notRecordedTypeProbability; + return costEstimateMethodDispatch < costEstimateTypeDispatch; } private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, @@ -691,17 +782,17 @@ @Override public void tryToDevirtualizeInvoke(StructuredGraph graph, MetaAccessProvider runtime, Assumptions assumptions) { if (hasSingleMethod()) { - tryToDevirtualizeSingleMethod(graph); + tryToDevirtualizeSingleMethod(graph, runtime); } else { - tryToDevirtualizeMultipleMethods(graph); + tryToDevirtualizeMultipleMethods(graph, runtime); } } - private void tryToDevirtualizeSingleMethod(StructuredGraph graph) { - devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0)); + private void tryToDevirtualizeSingleMethod(StructuredGraph graph, MetaAccessProvider runtime) { + devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0), runtime); } - private void tryToDevirtualizeMultipleMethods(StructuredGraph graph) { + private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider runtime) { MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget(); if (methodCallTarget.invokeKind() == InvokeKind.Interface) { ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod(); @@ -712,25 +803,25 @@ if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) { ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod); if (baseClassTargetMethod != null) { - devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod)); + devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), runtime); } } } } - private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target) { + private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider runtime) { InliningUtil.receiverNullCheck(invoke); BeginNode invocationEntry = graph.add(new BeginNode()); BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux}; - createDispatchOnTypeBeforeInvoke(graph, successors, true); + createDispatchOnTypeBeforeInvoke(graph, successors, true, runtime); invocationEntry.setNext(invoke.asNode()); ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver(); PiNode anchoredReceiver = createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false); invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver); - replaceInvokeCallTarget(graph, kind, target); + replaceInvokeCallTarget(invoke, graph, kind, target); } private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) { @@ -775,15 +866,13 @@ @Override public void inline(StructuredGraph graph, MetaAccessProvider runtime, Replacements replacements, InliningCallback callback, Assumptions assumptions) { assumptions.record(takenAssumption); - Debug.log("recording assumption: %s", takenAssumption); - super.inline(graph, runtime, replacements, callback, assumptions); } @Override public void tryToDevirtualizeInvoke(StructuredGraph graph, MetaAccessProvider runtime, Assumptions assumptions) { assumptions.record(takenAssumption); - replaceInvokeCallTarget(graph, InvokeKind.Special, concrete); + replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete); } @Override @@ -802,7 +891,6 @@ if (!checkInvokeConditions(invoke)) { return null; } - ResolvedJavaMethod caller = getCaller(invoke); MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); ResolvedJavaMethod targetMethod = callTarget.targetMethod(); @@ -845,7 +933,7 @@ } // type check based inlining - return getTypeCheckedInlineInfo(replacements, invoke, caller, holder, targetMethod, optimisticOpts); + return getTypeCheckedInlineInfo(replacements, invoke, targetMethod, optimisticOpts); } private static InlineInfo getAssumptionInlineInfo(Replacements replacements, Invoke invoke, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete, Assumption takenAssumption) { @@ -864,27 +952,28 @@ return new ExactInlineInfo(invoke, targetMethod); } - private static InlineInfo getTypeCheckedInlineInfo(Replacements replacements, Invoke invoke, ResolvedJavaMethod caller, ResolvedJavaType holder, ResolvedJavaMethod targetMethod, - OptimisticOptimizations optimisticOpts) { - ProfilingInfo profilingInfo = caller.getProfilingInfo(); - JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); - if (typeProfile == null) { + private static InlineInfo getTypeCheckedInlineInfo(Replacements replacements, Invoke invoke, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) { + JavaTypeProfile typeProfile = null; + ValueNode receiver = invoke.callTarget().arguments().get(0); + if (receiver instanceof TypeProfileProxyNode) { + TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver; + typeProfile = typeProfileProxyNode.getProfile(); + } else { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists"); } - ProfiledType[] rawProfiledTypes = typeProfile.getTypes(); - ArrayList ptypes = getCompatibleTypes(rawProfiledTypes, holder); - if (ptypes == null || ptypes.size() <= 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remained after filtering (%d types were recorded)", rawProfiledTypes.length); + ProfiledType[] ptypes = typeProfile.getTypes(); + if (ptypes == null || ptypes.length <= 0) { + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types in profile"); } double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); - if (ptypes.size() == 1 && notRecordedTypeProbability == 0) { + if (ptypes.length == 1 && notRecordedTypeProbability == 0) { if (!optimisticOpts.inlineMonomorphicCalls()) { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled"); } - ResolvedJavaType type = ptypes.get(0).getType(); + ResolvedJavaType type = ptypes[0].getType(); ResolvedJavaMethod concrete = type.resolveMethod(targetMethod); if (!checkTargetConditions(replacements, invoke, concrete, optimisticOpts)) { return null; @@ -894,27 +983,68 @@ invoke.setPolymorphic(true); if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.size()); + return logNotInlinedMethodAndReturnNull(invoke, 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.size(), + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability * 100); } - // determine concrete methods and map type to specific method + // Find unique methods and their probabilities. ArrayList concreteMethods = new ArrayList<>(); - int[] typesToConcretes = new int[ptypes.size()]; - for (int i = 0; i < ptypes.size(); i++) { - ResolvedJavaMethod concrete = ptypes.get(i).getType().resolveMethod(targetMethod); - + ArrayList concreteMethodsProbabilities = new ArrayList<>(); + for (int i = 0; i < ptypes.length; i++) { + ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod); int index = concreteMethods.indexOf(concrete); + double curProbability = ptypes[i].getProbability(); if (index < 0) { index = concreteMethods.size(); concreteMethods.add(concrete); + concreteMethodsProbabilities.add(curProbability); + } else { + concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability); } - typesToConcretes[i] = index; + } + + // Clear methods that fall below the threshold. + if (notRecordedTypeProbability > 0) { + ArrayList newConcreteMethods = new ArrayList<>(); + ArrayList newConcreteMethodsProbabilities = new ArrayList<>(); + for (int i = 0; i < concreteMethods.size(); ++i) { + if (concreteMethodsProbabilities.get(i) >= GraalOptions.MegamorphicInliningMinMethodProbability) { + newConcreteMethods.add(concreteMethods.get(i)); + newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i)); + } + } + + 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()); + } + + concreteMethods = newConcreteMethods; + concreteMethodsProbabilities = newConcreteMethodsProbabilities; + } + + // Clean out types whose methods are no longer available. + ArrayList usedTypes = new ArrayList<>(); + ArrayList typesToConcretes = new ArrayList<>(); + for (ProfiledType type : ptypes) { + ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod); + int index = concreteMethods.indexOf(concrete); + if (index == -1) { + notRecordedTypeProbability += type.getProbability(); + } else { + usedTypes.add(type); + typesToConcretes.add(index); + } + } + + 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); } for (ResolvedJavaMethod concrete : concreteMethods) { @@ -922,27 +1052,10 @@ return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); } } - return new MultiTypeGuardInlineInfo(invoke, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability); + return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability); } } - private static ArrayList getCompatibleTypes(ProfiledType[] types, ResolvedJavaType holder) { - ArrayList result = new ArrayList<>(); - for (int i = 0; i < types.length; i++) { - ProfiledType ptype = types[i]; - ResolvedJavaType type = ptype.getType(); - assert !type.isInterface() && (type.isArray() || !Modifier.isAbstract(type.getModifiers())) : type; - if (!GraalOptions.OptFilterProfiledTypes || holder.isAssignableFrom(type)) { - result.add(ptype); - } - } - return result; - } - - private static ResolvedJavaMethod getCaller(Invoke invoke) { - return invoke.stateAfter().method(); - } - private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { // to avoid that floating reads on receiver fields float above the type check return graph.unique(new PiNode(receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType), anchor)); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,7 +24,7 @@ import java.util.*; -import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.phases.*; @@ -49,7 +49,7 @@ } } - private static class Listener implements InputChangedListener { + private static class Listener implements NodeChangedListener { private final Set canonicalizationRoots; @@ -58,7 +58,7 @@ } @Override - public void inputChanged(Node node) { + public void nodeChanged(Node node) { canonicalizationRoots.add(node); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -68,8 +68,14 @@ } @Override - public ValueNode createNullCheckGuard(ValueNode object) { - return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true); + public ValueNode createNullCheckGuard(NodeInputList list, ValueNode object) { + if (object.objectStamp().nonNull()) { + // Short cut creation of null check guard if the object is known to be non-null. + return null; + } + ValueNode guard = createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true); + list.add(guard); + return guard; } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -36,13 +36,14 @@ import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.tiers.*; /** * This class is a phase that looks for opportunities for tail duplication. The static method - * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail - * duplication from other places, e.g., inlining. + * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List, PhaseContext)} can also be used + * to drive tail duplication from other places, e.g., inlining. */ -public class TailDuplicationPhase extends Phase { +public class TailDuplicationPhase extends BasePhase { /* * Various metrics on the circumstances in which tail duplication was/wasn't performed. @@ -129,14 +130,14 @@ }; @Override - protected void run(StructuredGraph graph) { + protected void run(StructuredGraph graph, PhaseContext phaseContext) { NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); // A snapshot is taken here, so that new MergeNode instances aren't considered for tail // duplication. for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= GraalOptions.TailDuplicationProbability) { - tailDuplicate(merge, DEFAULT_DECISION, null); + tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext); } } } @@ -156,8 +157,9 @@ * size needs to match the merge's end count. Each entry can either be null or a * {@link PiNode}, and is used to replace {@link PiNode#object()} with the * {@link PiNode} in the duplicated branch that corresponds to the entry. + * @param phaseContext */ - public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements) { + public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements, PhaseContext phaseContext) { assert !(merge instanceof LoopBeginNode); assert replacements == null || replacements.size() == merge.forwardEndCount(); FixedNode fixed = merge; @@ -171,14 +173,14 @@ metricDuplicationEnd.increment(); if (decision.doTransform(merge, fixedCount)) { metricDuplicationEndPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); + new DuplicationOperation(merge, replacements).duplicate(phaseContext); return true; } } else if (merge.stateAfter() != null) { metricDuplicationOther.increment(); if (decision.doTransform(merge, fixedCount)) { metricDuplicationOtherPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); + new DuplicationOperation(merge, replacements).duplicate(phaseContext); return true; } } @@ -220,10 +222,14 @@ *
  • Determines the complete set of duplicated nodes.
  • *
  • Performs the actual duplication.
  • *
+ * + * @param phaseContext */ - private void duplicate() { + private void duplicate(PhaseContext phaseContext) { Debug.log("tail duplication at merge %s in %s", merge, graph.method()); + int startMark = graph.getMark(); + ValueAnchorNode anchor = addValueAnchor(); // determine the fixed nodes that should be duplicated (currently: all nodes up until @@ -297,6 +303,7 @@ phi.setMerge(mergeAfter); } } + new CanonicalizerPhase(null, graph.getNewNodes(startMark)).apply(graph, phaseContext); Debug.dump(graph, "After tail duplication at %s", merge); } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Sun Apr 28 22:52:12 2013 +0200 @@ -44,7 +44,8 @@ public static boolean Intrinsify = true; static boolean InlineMonomorphicCalls = true; static boolean InlinePolymorphicCalls = true; - static boolean InlineMegamorphicCalls = ____; + static boolean InlineMegamorphicCalls = true; + public static double MegamorphicInliningMinMethodProbability = 0.33; public static int MaximumDesiredSize = 5000; public static int MaximumRecursiveInlining = 1; public static float BoostInliningForEscapeAnalysis = 2f; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Sun Apr 28 22:52:12 2013 +0200 @@ -446,9 +446,10 @@ @Override protected void doState(LIRFrameState state) { if (state.hasDebugInfo()) { - stateString.append(debugInfoToString(state.debugInfo().getBytecodePosition(), state.debugInfo().getRegisterRefMap(), state.debugInfo().getFrameRefMap(), target.arch)); + DebugInfo di = state.debugInfo(); + stateString.append(debugInfoToString(di.getBytecodePosition(), di.getRegisterRefMap(), di.getFrameRefMap(), di.getCalleeSaveInfo(), target.arch)); } else { - stateString.append(debugInfoToString(state.topFrame, null, null, target.arch)); + stateString.append(debugInfoToString(state.topFrame, null, null, null, target.arch)); } } }); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java Sun Apr 28 22:52:12 2013 +0200 @@ -114,7 +114,7 @@ /** * Formats given debug info as a multi line string. */ - protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, Architecture arch) { + protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, RegisterSaveLayout calleeSaveInfo, Architecture arch) { StringBuilder sb = new StringBuilder(); if (registerRefMap != null) { @@ -128,8 +128,16 @@ if (frameRefMap != null) { sb.append("frame-ref-map:"); - for (int reg = frameRefMap.nextSetBit(0); reg >= 0; reg = frameRefMap.nextSetBit(reg + 1)) { - sb.append(' ').append("s").append(reg); + for (int slot = frameRefMap.nextSetBit(0); slot >= 0; slot = frameRefMap.nextSetBit(slot + 1)) { + sb.append(' ').append("s").append(slot); + } + sb.append("\n"); + } + + if (calleeSaveInfo != null) { + sb.append("callee-save-info:"); + for (Map.Entry e : calleeSaveInfo.registersToSlots(true).entrySet()) { + sb.append(" " + e.getKey() + " -> s" + e.getValue()); } sb.append("\n"); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Sun Apr 28 22:52:12 2013 +0200 @@ -57,8 +57,7 @@ */ @Snippet public static int f2i(float input, int result) { - if (result == Integer.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); + if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { if (Float.isNaN(input)) { // input is NaN -> return 0 return 0; @@ -83,8 +82,7 @@ */ @Snippet public static long f2l(float input, long result) { - if (result == Long.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); + if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { if (Float.isNaN(input)) { // input is NaN -> return 0 return 0; @@ -109,8 +107,7 @@ */ @Snippet public static int d2i(double input, int result) { - if (result == Integer.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); + if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { if (Double.isNaN(input)) { // input is NaN -> return 0 return 0; @@ -135,8 +132,7 @@ */ @Snippet public static long d2l(double input, long result) { - if (result == Long.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); + if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { if (Double.isNaN(input)) { // input is NaN -> return 0 return 0; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Sun Apr 28 22:52:12 2013 +0200 @@ -97,8 +97,8 @@ */ protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { InstanceOfUsageReplacer replacer; - if (usage instanceof IfNode) { - replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage); + if (usage instanceof IfNode || usage instanceof FixedGuardNode) { + replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (FixedNode) usage); } else { assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; ConditionalNode c = (ConditionalNode) usage; @@ -193,9 +193,9 @@ */ public static class IfUsageReplacer extends InstanceOfUsageReplacer { - private final IfNode usage; + private final FixedNode usage; - public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage) { + public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, FixedNode usage) { super(instantiation, instanceOf, trueValue, falseValue); this.usage = usage; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.replacements; +import static com.oracle.graal.api.meta.MetaUtil.*; + import java.lang.reflect.*; import java.util.*; @@ -178,7 +180,8 @@ } else { result = runtime.lookupJavaType(intrinsic.value()); } - assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result); + assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + toJavaName(result, false) + " derived from @" + NodeIntrinsic.class.getSimpleName() + + " annotation on " + format("%H.%n(%p)", target) + " is not a subclass of " + ValueNode.class; return result; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,20 +24,20 @@ 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.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.Fold; /** * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods. */ public class NodeIntrinsificationVerificationPhase extends Phase { - public static boolean verify(StructuredGraph graph) { + public static void verify(StructuredGraph graph) { new NodeIntrinsificationVerificationPhase().apply(graph); - return true; } @Override @@ -49,11 +49,17 @@ private static void checkInvoke(MethodCallTargetNode n) { ResolvedJavaMethod target = n.targetMethod(); - NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); - if (intrinsic != null) { - throw new GraalInternalError("Illegal call to node intrinsic in " + n.graph() + ": " + n.invoke()); + if (target.getAnnotation(Node.NodeIntrinsic.class) != null) { + error(n, "Intrinsification"); } else if (target.getAnnotation(Fold.class) != null) { - throw new GraalInternalError("Illegal call to foldable method in " + n.graph() + ": " + n.invoke()); + error(n, "Folding"); } } + + private static void error(MethodCallTargetNode n, String failedAction) throws GraalInternalError { + String context = MetaUtil.format("%H.%n", ((StructuredGraph) n.graph()).method()); + String target = n.invoke().callTarget().targetName(); + throw new GraalInternalError(failedAction + " of call to '" + target + "' in '" + context + "' failed, most likely due to a parameter annotated with @" + + ConstantNodeParameter.class.getSimpleName() + " not being resolvable to a constant during compilation"); + } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sun Apr 28 22:52:12 2013 +0200 @@ -279,7 +279,10 @@ */ protected void finalizeGraph(StructuredGraph graph) { new NodeIntrinsificationPhase(runtime).apply(graph); - assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph); + if (!SnippetTemplate.hasConstantParameter(method)) { + NodeIntrinsificationVerificationPhase.verify(graph); + } + new ConvertDeoptimizeToGuardPhase().apply(graph); if (original == null) { new SnippetFrameStateCleanupPhase().apply(graph); @@ -293,7 +296,14 @@ private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) { StructuredGraph graph = graphCache.get(methodToParse); if (graph == null) { - graphCache.putIfAbsent(methodToParse, buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy)); + StructuredGraph newGraph = Debug.scope("ParseGraph", new Object[]{methodToParse}, new Callable() { + + public StructuredGraph call() throws Exception { + return buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy); + } + }); + + graphCache.putIfAbsent(methodToParse, newGraph); graph = graphCache.get(methodToParse); assert graph != null; } @@ -309,8 +319,6 @@ GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); graphBuilder.apply(graph); - Debug.dump(graph, "%s: %s", methodToParse.getName(), GraphBuilderPhase.class.getSimpleName()); - new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); return graph; @@ -364,6 +372,11 @@ if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) { targetGraph = intrinsicGraph; } else { + if (callee.getName().startsWith("$jacoco")) { + throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + format("%H.%n(%p)", callee) + " from " + format("%H.%n(%p)", methodToParse) + + " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " + + methodToParse.getDeclaringClass().getSourceFileName() + " should fix this."); + } targetGraph = parseGraph(callee, policy); } InliningUtil.inline(callTarget.invoke(), targetGraph, true); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Sun Apr 28 22:52:12 2013 +0200 @@ -378,7 +378,7 @@ new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), 0, null).apply(snippetCopy); } - assert NodeIntrinsificationVerificationPhase.verify(snippetCopy); + NodeIntrinsificationVerificationPhase.verify(snippetCopy); // Gather the template parameters parameters = new Object[parameterCount]; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,17 +22,17 @@ */ package com.oracle.graal.replacements.nodes; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; /** * Instances of this node class will look for a preceding if node and put the given probability into * the if node's taken probability. Then the branch probability node will be removed. This node is * intended primarily for snippets, so that they can define their fast and slow paths. */ -public class BranchProbabilityNode extends FixedWithNextNode implements Simplifiable { +public class BranchProbabilityNode extends FloatingNode implements Canonicalizable, Lowerable { public static final double LIKELY_PROBABILITY = 0.6; public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY; @@ -43,41 +43,80 @@ public static final double FAST_PATH_PROBABILITY = 0.99; public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY; - public static final double NOT_DEOPT_PATH_PROBABILITY = 0.999; - public static final double DEOPT_PATH_PROBABILITY = 1 - NOT_DEOPT_PATH_PROBABILITY; + public static final double VERY_FAST_DEOPT_PATH_PROBABILITY = 0.999; + public static final double VERY_SLOW_PATH_PROBABILITY = 1 - VERY_FAST_DEOPT_PATH_PROBABILITY; - private final double probability; + @Input private ValueNode probability; + @Input private ValueNode condition; - public BranchProbabilityNode(double probability) { - super(StampFactory.forVoid()); - assert probability >= 0 && probability <= 1; + public BranchProbabilityNode(ValueNode probability, ValueNode condition) { + super(condition.stamp()); this.probability = probability; + this.condition = condition; + } + + public ValueNode getProbability() { + return probability; + } + + public ValueNode getCondition() { + return condition; } @Override - public void simplify(SimplifierTool tool) { - FixedNode current = this; - while (!(current instanceof BeginNode)) { - current = (FixedNode) current.predecessor(); + public ValueNode canonical(CanonicalizerTool tool) { + if (probability.isConstant()) { + double probabilityValue = probability.asConstant().asDouble(); + if (probabilityValue < 0.0) { + throw new GraalInternalError("A negative probability of " + probabilityValue + " is not allowed!"); + } else if (probabilityValue > 1.0) { + throw new GraalInternalError("A probability of more than 1.0 (" + probabilityValue + ") is not allowed!"); + } + boolean couldSet = false; + for (IntegerEqualsNode node : this.usages().filter(IntegerEqualsNode.class)) { + if (node.condition() == Condition.EQ) { + ValueNode other = node.x(); + if (node.x() == this) { + other = node.y(); + } + if (other.isConstant()) { + double probabilityToSet = probabilityValue; + if (other.asConstant().asInt() == 0) { + probabilityToSet = 1.0 - probabilityToSet; + } + for (IfNode ifNodeUsages : node.usages().filter(IfNode.class)) { + couldSet = true; + ifNodeUsages.setTrueSuccessorProbability(probabilityToSet); + } + } + } + } + if (!couldSet) { + throw new GraalInternalError("Wrong usage of branch probability injection!"); + } + return condition; } - BeginNode begin = (BeginNode) current; - assert begin.predecessor() instanceof IfNode : "explicit branch probability cannot follow a merge, only if nodes"; - IfNode ifNode = (IfNode) begin.predecessor(); - if (ifNode.trueSuccessor() == begin) { - ifNode.setTrueSuccessorProbability(probability); - } else { - ifNode.setTrueSuccessorProbability(1 - probability); - } - - FixedNode next = next(); - setNext(null); - ((FixedWithNextNode) predecessor()).setNext(next); - GraphUtil.killCFG(this); + return this; } - @SuppressWarnings("unused") + /** + * This intrinsic should only be used for the condition of an if statement. The parameter + * condition should also only denote a simple condition and not a combined condition involving + * && or || operators. It injects the probability of the condition into the if statement. + * + * @param probability the probability that the given condition is true as a double value between + * 0.0 and 1.0. + * @param condition the simple condition without any && or || operators + * @return the condition + */ @NodeIntrinsic - public static void probability(@ConstantNodeParameter double probability) { + public static boolean probability(double probability, boolean condition) { + assert probability >= 0.0 && probability <= 1.0; + return condition; } + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + throw new GraalInternalError("Branch probability could not be injected, because the probability value did not reduce to a constant value."); + } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -47,7 +47,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, null)); + gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), null)); } @SuppressWarnings("unchecked") diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -50,7 +50,7 @@ @Override public void generate(LIRGeneratorTool gen) { Value v = gen.operand(value); - gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, null); + gen.emitStore(kind, gen.operand(address), v, null); } /* diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -71,6 +71,7 @@ StructuredGraph snippetGraph = getSnippetGraph(tool); InvokeNode invoke = replaceWithInvoke(); + assert invoke.verify(); if (snippetGraph != null) { InliningUtil.inline(invoke, snippetGraph, false); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java Sun Apr 28 22:52:12 2013 +0200 @@ -54,7 +54,7 @@ @Override public void generate(LIRGeneratorTool generator) { Value val = generator.operand(value); - generator.emitMove(val, register.asValue(val.getKind())); + generator.emitMove(register.asValue(val.getKind()), val); } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -38,7 +38,7 @@ @Test public void testSingleAssumption() { Assumption assumption = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.create(SingleAssumptionNodeFactory.getInstance(), assumption); + TestRootNode root = TestHelper.createRoot(SingleAssumptionNodeFactory.getInstance(), assumption); Assert.assertEquals(42, TestHelper.executeWith(root)); assumption.invalidate(); @@ -63,7 +63,7 @@ public void testMultipleAssumption() { Assumption assumption1 = Truffle.getRuntime().createAssumption(); Assumption assumption2 = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.create(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2); + TestRootNode root = TestHelper.createRoot(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2); Assert.assertEquals(42, TestHelper.executeWith(root)); assumption2.invalidate(); @@ -95,7 +95,7 @@ public void testDerivedAssumption() { Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); Assumption assumption = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.create(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption); + TestRootNode root = TestHelper.createRoot(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption); Assert.assertEquals(42, TestHelper.executeWith(root)); assumption.invalidate(); @@ -117,7 +117,7 @@ public void testDerivedAssumptionRedeclared() { Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); Assumption assumption = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.create(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption); + TestRootNode root = TestHelper.createRoot(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption); Assert.assertEquals(42, TestHelper.executeWith(root)); assumption.invalidate(); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -36,7 +36,7 @@ @Test public void testAdd() { - TestRootNode node = create(AddNodeFactory.getInstance()); + TestRootNode node = createRoot(AddNodeFactory.getInstance()); assertEquals(42, executeWith(node, 19, 23)); assertEquals(42d, executeWith(node, 19d, 23d)); assertEquals(42d, executeWith(node, "19", "23")); @@ -45,7 +45,7 @@ @Test(expected = RuntimeException.class) public void testAddUnsupported() { - TestRootNode node = create(AddNodeFactory.getInstance()); + TestRootNode node = createRoot(AddNodeFactory.getInstance()); executeWith(node, new Object(), new Object()); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -39,7 +39,7 @@ @Test public void testConcat() { - TestRootNode node = create(StrConcatFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); Str str1 = new Str("42"); Str str2 = new Str(" is the number."); assertEquals(str1.concat(str2), executeWith(node, str1, str2)); @@ -47,13 +47,13 @@ @Test(expected = UnsupportedOperationException.class) public void testConcatUnsupported() { - TestRootNode node = create(StrConcatFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); executeWith(node, 42, new Str(" is the number.")); } @Test public void testSubstrSpecialized() { - TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); Str str = new Str("test 42"); assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7)); @@ -61,7 +61,7 @@ @Test public void testSubstrGeneric() { - TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); Str str = new Str("test 42"); assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7")); @@ -69,27 +69,27 @@ @Test(expected = UnsupportedOperationException.class) public void testSubstrUnsupported() { - TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); executeWith(node, new Object(), "5", "7"); } @Test public void testLength() { - TestRootNode node = create(StrLengthFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); Str testStr = new Str("test 42"); assertEquals(testStr.length(), executeWith(node, testStr)); } @Test(expected = UnsupportedOperationException.class) public void testLengthUnsupported() { - TestRootNode node = create(StrLengthFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); executeWith(node, new Object()); } @Test public void testAccessContext() { Context context = new Context(); - TestRootNode node = create(StrAccessContextFactory.getInstance(), context); + TestRootNode node = createRoot(StrAccessContextFactory.getInstance(), context); // accessible by node assertSame(context, node.getNode().getContext()); // accessible by execution diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,48 +22,86 @@ */ package com.oracle.truffle.api.codegen.test; +import org.junit.*; + import com.oracle.truffle.api.*; import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.DoubleEvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.EvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ArgumentNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestArguments; import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; public class ExecuteEvaluatedTest { - /* Represents target[element] */ - @NodeChildren({@NodeChild("target"), @NodeChild("element")}) - abstract static class ReadElementNode extends ValueNode { + @Test + public void testSingleEvaluated() { + ArgumentNode arg0 = new ArgumentNode(0); + CallTarget callTarget = TestHelper.createCallTarget(UseEvaluatedNodeFactory.create(arg0, EvaluatedNodeFactory.create(null))); + + Assert.assertEquals(43, callTarget.call(new TestArguments(42))); + Assert.assertEquals(1, arg0.getInvocationCount()); + } + + @NodeChild("exp") + abstract static class EvaluatedNode extends ValueNode { @Specialization - int getInt(Object[] target, int element) { - return (int) target[element]; + int doExecuteWith(int exp) { + return exp + 1; } - public abstract Object executeWith(VirtualFrame frame, Object targetValue); + public abstract Object executeEvaluated(VirtualFrame frame, Object targetValue); + + public abstract int executeIntEvaluated(VirtualFrame frame, Object targetValue) throws UnexpectedResultException; } - /* Represents target[element]() */ - @NodeChildren({@NodeChild("target"), @NodeChild(value = "element", type = ReadElementNode.class, executeWith = "target")}) - abstract static class ElementCallNode extends ValueNode { + @NodeChildren({@NodeChild("exp0"), @NodeChild(value = "exp1", type = EvaluatedNode.class, executeWith = "exp0")}) + abstract static class UseEvaluatedNode extends ValueNode { @Specialization - Object call(Object receiver, Object callTarget) { - return ((CallTarget) callTarget).call(new TestArguments(receiver)); + int call(int exp0, int exp1) { + Assert.assertEquals(exp0 + 1, exp1); + return exp1; } + } + @Test + public void testDoubleEvaluated() { + ArgumentNode arg0 = new ArgumentNode(0); + ArgumentNode arg1 = new ArgumentNode(1); + CallTarget callTarget = TestHelper.createCallTarget(UseDoubleEvaluatedNodeFactory.create(arg0, arg1, DoubleEvaluatedNodeFactory.create(null, null))); + + Assert.assertEquals(85, callTarget.call(new TestArguments(42, 43))); + Assert.assertEquals(1, arg0.getInvocationCount()); + Assert.assertEquals(1, arg1.getInvocationCount()); } - public static class TestArguments extends Arguments { + @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1")}) + abstract static class DoubleEvaluatedNode extends ValueNode { - private final Object receiver; - - public TestArguments(Object receiver) { - this.receiver = receiver; + @Specialization + int doExecuteWith(int exp0, int exp1) { + return exp0 + exp1; } - public Object getReceiver() { - return receiver; + public abstract Object executeEvaluated(VirtualFrame frame, Object exp0, Object exp1); + + public abstract int executeIntEvaluated(VirtualFrame frame, Object exp0, Object exp1) throws UnexpectedResultException; + } + + @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1"), @NodeChild(value = "exp2", type = DoubleEvaluatedNode.class, executeWith = {"exp0", "exp1"})}) + abstract static class UseDoubleEvaluatedNode extends ValueNode { + + @Specialization + int call(int exp0, int exp1, int exp2) { + Assert.assertEquals(exp0 + exp1, exp2); + return exp2; } - } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -40,7 +40,7 @@ @Test public void testGuardInvocations() { - TestRootNode root = create(InvocationGuardFactory.getInstance()); + TestRootNode root = createRoot(InvocationGuardFactory.getInstance()); assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1, 1)); assertEquals(1, InvocationGuard.specializedInvocations); @@ -76,7 +76,7 @@ @Test public void testGuardGlobal() { - TestRootNode root = create(GlobalFlagGuardFactory.getInstance()); + TestRootNode root = createRoot(GlobalFlagGuardFactory.getInstance()); assertEquals(42, executeWith(root, NULL)); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java Sun Apr 28 22:52:12 2013 +0200 @@ -42,7 +42,7 @@ return nodes; } - static TestRootNode create(NodeFactory factory, Object... constants) { + static E createNode(NodeFactory factory, Object... constants) { ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size()); List argumentList = new ArrayList<>(); @@ -52,11 +52,23 @@ } else { argumentList.addAll(Arrays.asList(argumentNodes)); } - return new TestRootNode<>(factory.createNode(argumentList.toArray(new Object[argumentList.size()]))); + return factory.createNode(argumentList.toArray(new Object[argumentList.size()])); + } + + static TestRootNode createRoot(NodeFactory factory, Object... constants) { + return new TestRootNode<>(createNode(factory, constants)); + } + + static CallTarget createCallTarget(ValueNode node) { + return createCallTarget(new TestRootNode<>(node)); + } + + static CallTarget createCallTarget(TestRootNode node) { + return Truffle.getRuntime().createCallTarget(node); } static Object executeWith(TestRootNode node, Object... values) { - return Truffle.getRuntime().createCallTarget(node).call(new TestArguments(values)); + return createCallTarget(node).call(new TestArguments(values)); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -101,15 +101,21 @@ public static class ArgumentNode extends ValueNode { + private int invocationCount; final int index; public ArgumentNode(int index) { this.index = index; } + public int getInvocationCount() { + return invocationCount; + } + @Override public Object execute(VirtualFrame frame) { - return ((TestArguments) frame.getArguments()).get(index); + invocationCount++; + return frame.getArguments(TestArguments.class).get(index); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Sun Apr 28 22:52:12 2013 +0200 @@ -24,6 +24,8 @@ import java.lang.annotation.*; +import com.oracle.truffle.api.nodes.*; + @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE}) public @interface NodeChild { @@ -32,5 +34,14 @@ Class type() default NodeClass.InheritNode.class; + /** + * Executes the {@link NodeChild} with values from other defined {@link NodeChild} elements. + * These referenced children must be defined before the current node in the execution order. The + * current node {@link #type()} attribute must be set to a {@link Node} which supports the + * evaluated execution with the number of {@link #executeWith()} arguments that are defined. For + * example if this child is executed with one argument, the {@link #type()} attribute must + * define a node which publicly declares a method with the signature + * Object execute*(VirtualFrame, Object). + */ String[] executeWith() default {}; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -35,7 +35,7 @@ * A guest language can pass its own custom arguments when invoking a Truffle method by creating a * subclass of {@link Arguments}. When invoking a call target with * {@link CallTarget#call(Arguments)}, the arguments can be passed. A Truffle node can access the - * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments()}. + * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments}. *

* *

@@ -97,7 +97,7 @@ } int execute(VirtualFrame frame) { - return ((TestArguments) frame.getArguments()).values[index]; + return frame.getArguments(TestArguments.class).values[index]; } } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -34,7 +34,7 @@ *

* Dynamically typed languages can speculate on the type of a frame slot and only fall back at run * time to a more generic type if necessary. The new type of a frame slot can be set using the - * {@link FrameSlot#setType(Class)} method. + * {@link FrameSlot#setKind(FrameSlotKind)} method. *

* *

@@ -48,13 +48,13 @@ public void test() { TruffleRuntime runtime = Truffle.getRuntime(); FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", FrameSlotKind.Int); TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot)); CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); - Assert.assertEquals(int.class, slot.getType()); + Assert.assertEquals(FrameSlotKind.Int, slot.getKind()); Object result = target.call(); Assert.assertEquals("42", result); - Assert.assertEquals(Object.class, slot.getType()); + Assert.assertEquals(FrameSlotKind.Object, slot.getKind()); } class TestRootNode extends RootNode { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -35,9 +35,9 @@ * The frame is the preferred data structure for passing values between nodes. It can in particular * be used for storing the values of local variables of the guest language. The * {@link FrameDescriptor} represents the current structure of the frame. The method - * {@link FrameDescriptor#addFrameSlot(Object, Class)} can be used to create predefined frame slots. - * The setter and getter methods in the {@link Frame} class can be used to access the current value - * of a particular frame slot. + * {@link FrameDescriptor#addFrameSlot(Object, FrameSlotKind)} can be used to create predefined + * frame slots. The setter and getter methods in the {@link Frame} class can be used to access the + * current value of a particular frame slot. *

* *

@@ -64,7 +64,7 @@ public void test() { TruffleRuntime runtime = Truffle.getRuntime(); FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", FrameSlotKind.Int); TestRootNode rootNode = new TestRootNode(new AssignLocal(slot), new ReadLocal(slot)); CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); Object result = target.call(); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Sun Apr 28 22:52:12 2013 +0200 @@ -47,13 +47,13 @@ public void test() { TruffleRuntime runtime = Truffle.getRuntime(); FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", FrameSlotKind.Int); TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot)); CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); - Assert.assertEquals(int.class, slot.getType()); + Assert.assertEquals(FrameSlotKind.Int, slot.getKind()); Object result = target.call(); Assert.assertEquals("42", result); - Assert.assertEquals(Object.class, slot.getType()); + Assert.assertEquals(FrameSlotKind.Object, slot.getKind()); } class TestRootNode extends RootNode { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.truffle.api; +import java.lang.annotation.*; import java.util.concurrent.*; /** @@ -30,7 +31,11 @@ */ public class CompilerDirectives { - private static final double SLOWPATH_PROBABILITY = 0.0001; + public static final double LIKELY_PROBABILITY = 0.75; + public static final double UNLIKELY_PROBABILITY = 1.0 - LIKELY_PROBABILITY; + + public static final double SLOWPATH_PROBABILITY = 0.0001; + public static final double FASTPATH_PROBABILITY = 1.0 - SLOWPATH_PROBABILITY; /** * Directive for the compiler to discontinue compilation at this code position and instead @@ -62,20 +67,38 @@ } /** - * Directive for the compiler that the current path has a very low probability to be executed. - */ - public static void slowpath() { - injectBranchProbability(SLOWPATH_PROBABILITY); - } - - /** - * Injects a probability for the current path into the probability information of the - * immediately preceeding branch instruction. + * Injects a probability for the given condition into the probability information of the + * immediately succeeding branch instruction for the condition. The probability must be a value + * between 0.0 and 1.0 (inclusive). The condition should not be a combined condition. + * + * Example usage immediately before an if statement (it specifies that the likelihood for a to + * be greater than b is 90%): + * + * + * if (injectBranchProbability(0.9, a > b)) { + * // ... + * } + * + * + * Example usage for a combined condition (it specifies that the likelihood for a to be greater + * than b is 90% and under the assumption that this is true, the likelihood for a being 0 is + * 10%): + * + * + * if (injectBranchProbability(0.9, a > b) && injectBranchProbability(0.1, a == 0)) { + * // ... + * } + * + * + * There are predefined constants for commonly used probabilities (see + * {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY}, + * {@link #FASTPATH_PROBABILITY} ). * * @param probability the probability value between 0.0 and 1.0 that should be injected */ - public static void injectBranchProbability(double probability) { + public static boolean injectBranchProbability(double probability, boolean condition) { assert probability >= 0.0 && probability <= 1.0; + return condition; } /** @@ -85,4 +108,22 @@ */ public static void bailout(String reason) { } + + /** + * Marks fields that should be considered final for a Truffle compilation although they are not + * final while executing in the interpreter. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface CompilationFinal { + } + + /** + * Marks methods that are considered unsafe. Wrong usage of those methods can lead to unexpected + * behavior including a crash of the runtime. Therefore, special care should be taken. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD}) + public @interface Unsafe { + } } diff -r c21b1e5b515c -r 16a10b48e526 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 Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Sun Apr 28 22:52:12 2013 +0200 @@ -31,26 +31,26 @@ private final String identifier; private final int startLine; private final int startColumn; - private final int endLine; - private final int endColumn; + private final int charIndex; + private final int charLength; /** * Creates a new object representing a section in the source code of a guest language program. * * @param source object representing the source program this is should be a section of * @param identifier an identifier used when printing the section - * @param startLine the index of the start line of the section (inclusive) - * @param startColumn the index of the start column of the section (inclusive) - * @param endLine the index of the end line of the section (inclusive) - * @param endColumn the index of the end column of the section (inclusive) + * @param startLine the index of the start line of the section + * @param startColumn the index of the start column of the section + * @param charIndex the index of the first character of the section + * @param charLength the length of the section in number of characters */ - public SourceSection(Source source, String identifier, int startLine, int startColumn, int endLine, int endColumn) { + public SourceSection(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) { this.source = source; this.identifier = identifier; this.startLine = startLine; this.startColumn = startColumn; - this.endLine = endLine; - this.endColumn = endColumn; + this.charIndex = charIndex; + this.charLength = charLength; } /** @@ -81,21 +81,23 @@ } /** - * Returns the index of the end line of this source section (inclusive). + * Returns the index of the first character of this section. All characters of the source can be + * retrieved via the {@link Source#getCode()} method. * - * @return the end line + * @return the character index */ - public final int getEndLine() { - return endLine; + public final int getCharIndex() { + return charIndex; } /** - * Returns the index of the end column of this source section (inclusive). + * Returns the length of this section in characters. All characters of the source can be + * retrieved via the {@link Source#getCode()} method. * - * @return the end column + * @return the character length */ - public final int getEndColumn() { - return endColumn; + public final int getCharLength() { + return charLength; } /** @@ -106,4 +108,19 @@ public final String getIdentifier() { return identifier; } + + /** + * Returns the code represented by this code section. + * + * @return the code as a String object + */ + public final String getCode() { + return getSource().getCode().substring(charIndex, charLength); + } + + @Override + public String toString() { + return String.format("%s:%d", source.getName(), startLine); + } + } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java Sun Apr 28 22:52:12 2013 +0200 @@ -36,9 +36,17 @@ FrameDescriptor getFrameDescriptor(); /** + * Retrieves the arguments object from this frame. The runtime assumes that the arguments object + * is never null. Additionally, the runtime may assume that the given parameter indicating the + * class of the arguments object is correct. The runtime is not required to actually check the + * type of the arguments object. The parameter must be a value that can be reduced to a compile + * time constant. + * + * @param clazz the known type of the arguments object as a compile time constant * @return the arguments used when calling this method */ - Arguments getArguments(); + @CompilerDirectives.Unsafe + T getArguments(Class clazz); /** * Read access to a local variable of type {@link Object}. diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Sun Apr 28 22:52:12 2013 +0200 @@ -53,9 +53,9 @@ return addFrameSlot(identifier, null); } - public FrameSlot addFrameSlot(Object identifier, Class type) { + public FrameSlot addFrameSlot(Object identifier, FrameSlotKind kind) { assert !identifierToSlotMap.containsKey(identifier); - FrameSlotImpl slot = new FrameSlotImpl(this, identifier, slots.size(), type); + FrameSlotImpl slot = new FrameSlotImpl(this, identifier, slots.size(), kind); slots.add(slot); identifierToSlotMap.put(identifier, slot); updateVersion(); @@ -74,12 +74,12 @@ return addFrameSlot(identifier); } - public FrameSlot findOrAddFrameSlot(Object identifier, Class type) { + public FrameSlot findOrAddFrameSlot(Object identifier, FrameSlotKind kind) { FrameSlot result = findFrameSlot(identifier); if (result != null) { return result; } - return addFrameSlot(identifier, type); + return addFrameSlot(identifier, kind); } public int getSize() { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java Sun Apr 28 22:52:12 2013 +0200 @@ -31,9 +31,9 @@ int getIndex(); - Class getType(); + FrameSlotKind getKind(); - void setType(Class type); + void setKind(FrameSlotKind kind); FrameDescriptor getFrameDescriptor(); } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java Sun Apr 28 22:52:12 2013 +0200 @@ -27,13 +27,13 @@ private final FrameDescriptor descriptor; private final Object identifier; private final int index; - private Class type; + private FrameSlotKind kind; - protected FrameSlotImpl(FrameDescriptor descriptor, Object identifier, int index, Class type) { + protected FrameSlotImpl(FrameDescriptor descriptor, Object identifier, int index, FrameSlotKind kind) { this.descriptor = descriptor; this.identifier = identifier; this.index = index; - this.type = type; + this.kind = kind; } public Object getIdentifier() { @@ -44,19 +44,19 @@ return index; } - public Class getType() { - return type; + public FrameSlotKind getKind() { + return kind; } - public void setType(final Class type) { - assert this.type != type; - this.type = type; + public void setKind(final FrameSlotKind kind) { + assert this.kind != kind; + this.kind = kind; this.descriptor.updateVersion(); } @Override public String toString() { - return "[" + index + "," + identifier + "," + type + "]"; + return "[" + index + "," + identifier + "," + kind + "]"; } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java Sun Apr 28 22:52:12 2013 +0200 @@ -0,0 +1,27 @@ +/* + * 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.truffle.api.frame; + +public enum FrameSlotKind { + Illegal, Object, Long, Int, Double, Float, Boolean; +} diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java Sun Apr 28 22:52:12 2013 +0200 @@ -33,8 +33,8 @@ * @param value the new value of the local variable */ public static void setObjectSafe(Frame frame, FrameSlot slot, Object value) { - if (slot.getType() != Object.class) { - slot.setType(Object.class); + if (slot.getKind() != FrameSlotKind.Object) { + slot.setKind(FrameSlotKind.Object); } try { frame.setObject(slot, value); @@ -52,8 +52,8 @@ * @param value the new value of the local variable */ public static void setBooleanSafe(Frame frame, FrameSlot slot, boolean value) { - if (slot.getType() != boolean.class) { - slot.setType(boolean.class); + if (slot.getKind() != FrameSlotKind.Boolean) { + slot.setKind(FrameSlotKind.Boolean); } try { frame.setBoolean(slot, value); @@ -71,8 +71,8 @@ * @param value the new value of the local variable */ public static void setIntSafe(Frame frame, FrameSlot slot, int value) { - if (slot.getType() != int.class) { - slot.setType(int.class); + if (slot.getKind() != FrameSlotKind.Int) { + slot.setKind(FrameSlotKind.Int); } try { frame.setInt(slot, value); @@ -90,8 +90,8 @@ * @param value the new value of the local variable */ public static void setLongSafe(Frame frame, FrameSlot slot, long value) { - if (slot.getType() != long.class) { - slot.setType(long.class); + if (slot.getKind() != FrameSlotKind.Long) { + slot.setKind(FrameSlotKind.Long); } try { frame.setLong(slot, value); @@ -109,8 +109,8 @@ * @param value the new value of the local variable */ public static void setFloatSafe(Frame frame, FrameSlot slot, float value) { - if (slot.getType() != float.class) { - slot.setType(float.class); + if (slot.getKind() != FrameSlotKind.Float) { + slot.setKind(FrameSlotKind.Float); } try { frame.setFloat(slot, value); @@ -128,8 +128,8 @@ * @param value the new value of the local variable */ public static void setDoubleSafe(Frame frame, FrameSlot slot, double value) { - if (slot.getType() != double.class) { - slot.setType(double.class); + if (slot.getKind() != FrameSlotKind.Double) { + slot.setKind(FrameSlotKind.Double); } try { frame.setDouble(slot, value); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java Sun Apr 28 22:52:12 2013 +0200 @@ -38,9 +38,10 @@ this.arguments = arguments; } + @SuppressWarnings("unchecked") @Override - public Arguments getArguments() { - return arguments; + public T getArguments(Class clazz) { + return (T) arguments; } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Sun Apr 28 22:52:12 2013 +0200 @@ -34,8 +34,8 @@ } @Override - public Arguments getArguments() { - return wrapped.getArguments(); + public T getArguments(Class clazz) { + return wrapped.getArguments(clazz); } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Sun Apr 28 22:52:12 2013 +0200 @@ -33,19 +33,20 @@ private final PackedFrame caller; private final Arguments arguments; private Object[] locals; - private Class[] tags; + private byte[] tags; public DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) { this.descriptor = descriptor; this.caller = caller; this.arguments = arguments; this.locals = new Object[descriptor.getSize()]; - this.tags = new Class[descriptor.getSize()]; + this.tags = new byte[descriptor.getSize()]; } + @SuppressWarnings("unchecked") @Override - public Arguments getArguments() { - return arguments; + public T getArguments(Class clazz) { + return (T) arguments; } @Override @@ -65,73 +66,73 @@ @Override public Object getObject(FrameSlot slot) throws FrameSlotTypeException { - verifyGet(slot, Object.class); + verifyGet(slot, FrameSlotKind.Object); return locals[slot.getIndex()]; } @Override public void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException { - verifySet(slot, Object.class); + verifySet(slot, FrameSlotKind.Object); locals[slot.getIndex()] = value; } @Override public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException { - verifyGet(slot, boolean.class); + verifyGet(slot, FrameSlotKind.Boolean); return (boolean) locals[slot.getIndex()]; } @Override public void setBoolean(FrameSlot slot, boolean value) throws FrameSlotTypeException { - verifySet(slot, boolean.class); + verifySet(slot, FrameSlotKind.Boolean); locals[slot.getIndex()] = value; } @Override public int getInt(FrameSlot slot) throws FrameSlotTypeException { - verifyGet(slot, int.class); + verifyGet(slot, FrameSlotKind.Int); return (int) locals[slot.getIndex()]; } @Override public void setInt(FrameSlot slot, int value) throws FrameSlotTypeException { - verifySet(slot, int.class); + verifySet(slot, FrameSlotKind.Int); locals[slot.getIndex()] = value; } @Override public long getLong(FrameSlot slot) throws FrameSlotTypeException { - verifyGet(slot, long.class); + verifyGet(slot, FrameSlotKind.Long); return (long) locals[slot.getIndex()]; } @Override public void setLong(FrameSlot slot, long value) throws FrameSlotTypeException { - verifySet(slot, long.class); + verifySet(slot, FrameSlotKind.Long); locals[slot.getIndex()] = value; } @Override public float getFloat(FrameSlot slot) throws FrameSlotTypeException { - verifyGet(slot, float.class); + verifyGet(slot, FrameSlotKind.Float); return (float) locals[slot.getIndex()]; } @Override public void setFloat(FrameSlot slot, float value) throws FrameSlotTypeException { - verifySet(slot, float.class); + verifySet(slot, FrameSlotKind.Float); locals[slot.getIndex()] = value; } @Override public double getDouble(FrameSlot slot) throws FrameSlotTypeException { - verifyGet(slot, double.class); + verifyGet(slot, FrameSlotKind.Double); return (double) locals[slot.getIndex()]; } @Override public void setDouble(FrameSlot slot, double value) throws FrameSlotTypeException { - verifySet(slot, double.class); + verifySet(slot, FrameSlotKind.Double); locals[slot.getIndex()] = value; } @@ -147,19 +148,19 @@ assert index >= 0 && index < descriptor.getSize(); return descriptor.getTypeConversion().getDefaultValue(); } - Class tag = tags[index]; - if (tag == null) { + byte tag = tags[index]; + if (tag == FrameSlotKind.Illegal.ordinal()) { return descriptor.getTypeConversion().getDefaultValue(); } else { return locals[index]; } } - private void verifySet(FrameSlot slot, Class accessType) throws FrameSlotTypeException { - Class slotType = slot.getType(); - if (slotType != accessType) { - if (slotType == null) { - slot.setType(accessType); + private void verifySet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException { + FrameSlotKind slotKind = slot.getKind(); + if (slotKind != accessKind) { + if (slotKind == FrameSlotKind.Illegal) { + slot.setKind(accessKind); } else { throw new FrameSlotTypeException(); } @@ -168,14 +169,14 @@ if (slotIndex >= tags.length) { resize(); } - tags[slotIndex] = accessType; + tags[slotIndex] = (byte) accessKind.ordinal(); } - private void verifyGet(FrameSlot slot, Class accessType) throws FrameSlotTypeException { - Class slotType = slot.getType(); - if (slotType != accessType) { - if (slotType == null && accessType == Object.class) { - slot.setType(Object.class); + private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException { + FrameSlotKind slotKind = slot.getKind(); + if (slotKind != accessKind) { + if (slotKind == FrameSlotKind.Illegal && accessKind == FrameSlotKind.Object) { + slot.setKind(FrameSlotKind.Object); this.setObject(slot, descriptor.getTypeConversion().getDefaultValue()); } else { throw new FrameSlotTypeException(); @@ -185,9 +186,9 @@ if (slotIndex >= tags.length) { resize(); } - if (tags[slotIndex] != accessType) { + if (tags[slotIndex] != accessKind.ordinal()) { descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot)); - if (tags[slotIndex] != accessType) { + if (tags[slotIndex] != accessKind.ordinal()) { throw new FrameSlotTypeException(); } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Sun Apr 28 22:52:12 2013 +0200 @@ -48,6 +48,7 @@ private final DeclaredType childAnnotation; private final DeclaredType childrenAnnotation; private final TypeMirror compilerDirectives; + private final TypeMirror compilerAsserts; private final List errors = new ArrayList<>(); @@ -59,6 +60,7 @@ childAnnotation = getRequired(context, Child.class); childrenAnnotation = getRequired(context, Children.class); compilerDirectives = getRequired(context, CompilerDirectives.class); + compilerAsserts = getRequired(context, CompilerAsserts.class); assumption = getRequired(context, Assumption.class); invalidAssumption = getRequired(context, InvalidAssumptionException.class); } @@ -118,4 +120,8 @@ public DeclaredType getChildrenAnnotation() { return childrenAnnotation; } + + public TypeMirror getCompilerAsserts() { + return compilerAsserts; + } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Sun Apr 28 22:52:12 2013 +0200 @@ -475,6 +475,19 @@ currentElement.registerAtEnd(callback); } + public CodeTreeBuilder defaultDeclaration(TypeMirror type, String name) { + if (!Utils.isVoid(type)) { + startStatement(); + type(type); + string(" "); + string(name); + string(" = "); + defaultValue(type); + end(); // statement + } + return this; + } + public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) { if (Utils.isVoid(type)) { startStatement(); diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Sun Apr 28 22:52:12 2013 +0200 @@ -44,8 +44,8 @@ } @Override - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { - List execTypes = nodeData.findGenericExecutableTypes(getContext()); + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) { + List execTypes = nodeData.findGenericExecutableTypes(getContext(), evaluatedCount); List types = new ArrayList<>(); for (ExecutableTypeData type : execTypes) { types.add(type.getType().getPrimitiveType()); @@ -57,7 +57,7 @@ @Override protected ParameterSpec createReturnParameterSpec() { - return super.createValueParameterSpec("returnValue", getNode()); + return super.createValueParameterSpec("returnValue", getNode(), 0); } @Override diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java Sun Apr 28 22:52:12 2013 +0200 @@ -22,10 +22,14 @@ */ package com.oracle.truffle.codegen.processor.node; +import java.util.*; + import javax.lang.model.element.*; import javax.lang.model.type.*; +import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; public class NodeChildData extends MessageContainer { @@ -54,6 +58,9 @@ private final Cardinality cardinality; private final ExecutionKind executionKind; + + private List executeWith = Collections.emptyList(); + private NodeData nodeData; public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) { @@ -66,6 +73,34 @@ this.executionKind = executionKind; } + public List getExecuteWith() { + return executeWith; + } + + void setExecuteWith(List executeWith) { + this.executeWith = executeWith; + } + + public ExecutableTypeData findExecutableType(ProcessorContext context, TypeData targetType) { + ExecutableTypeData executableType = nodeData.findExecutableType(targetType, getExecuteWith().size()); + if (executableType == null) { + executableType = findAnyGenericExecutableType(context); + } + return executableType; + } + + public List findGenericExecutableTypes(ProcessorContext context) { + return nodeData.findGenericExecutableTypes(context, getExecuteWith().size()); + } + + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { + return nodeData.findAnyGenericExecutableType(context, getExecuteWith().size()); + } + + public List findExecutableTypes() { + return nodeData.getExecutableTypes(getExecuteWith().size()); + } + @Override public Element getMessageElement() { return sourceElement; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Sun Apr 28 22:52:12 2013 +0200 @@ -43,6 +43,9 @@ private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; + private static final String EXECUTE_GENERIC_NAME = "executeGeneric_"; + private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize_"; + public NodeCodeGenerator(ProcessorContext context) { super(context); } @@ -67,6 +70,10 @@ return name; } + private static String valueNameEvaluated(ActualParameter targetParameter) { + return valueName(targetParameter) + "Evaluated"; + } + private static String valueName(ActualParameter param) { return param.getLocalName(); } @@ -92,8 +99,7 @@ } } - private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, - boolean includeImplicit) { + private void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) { if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { builder.string("frameValue"); } @@ -122,12 +128,12 @@ } } - private static String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) { + private String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) { if (sourceParameter != null) { if (!sourceParameter.getSpecification().isSignature()) { return valueName(targetParameter); } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) { - if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) { + if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), targetParameter.getTypeSystemType())) { return castValueName(targetParameter); } } @@ -137,7 +143,7 @@ } } - private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { + private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { CodeTreeBuilder builder = parent.create(); boolean castedValues = sourceMethod != targetMethod; @@ -150,43 +156,47 @@ TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); NodeData node = (NodeData) targetMethod.getTemplate(); - boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType()); - if (accessible) { - if (builder.findMethod().getModifiers().contains(STATIC)) { + if (target == null) { + boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType()); + if (accessible) { + if (builder.findMethod().getModifiers().contains(STATIC)) { + if (method.getModifiers().contains(STATIC)) { + builder.type(targetClass.asType()); + } else { + builder.string(THIS_NODE_LOCAL_VAR_NAME); + } + } else { + if (targetMethod instanceof ExecutableTypeData) { + builder.string("this"); + } else { + builder.string("super"); + } + } + } else { if (method.getModifiers().contains(STATIC)) { builder.type(targetClass.asType()); } else { - builder.string(THIS_NODE_LOCAL_VAR_NAME); - } - } else { - if (targetMethod instanceof ExecutableTypeData) { - builder.string("this"); - } else { - builder.string("super"); + ActualParameter parameter = null; + for (ActualParameter searchParameter : targetMethod.getParameters()) { + if (searchParameter.getSpecification().isSignature()) { + parameter = searchParameter; + break; + } + } + ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName()); + assert parameter != null; + + if (castedValues && sourceParameter != null) { + builder.string(valueName(sourceParameter, parameter)); + } else { + builder.string(valueName(parameter)); + } } } + builder.string("."); } else { - if (method.getModifiers().contains(STATIC)) { - builder.type(targetClass.asType()); - } else { - ActualParameter parameter = null; - for (ActualParameter searchParameter : targetMethod.getParameters()) { - if (searchParameter.getSpecification().isSignature()) { - parameter = searchParameter; - break; - } - } - ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName()); - assert parameter != null; - - if (castedValues && sourceParameter != null) { - builder.string(valueName(sourceParameter, parameter)); - } else { - builder.string(valueName(parameter)); - } - } + builder.tree(target); } - builder.string("."); builder.startCall(method.getSimpleName().toString()); for (ActualParameter targetParameter : targetMethod.getParameters()) { @@ -236,41 +246,16 @@ return builder.getRoot(); } - private static String genClassName(NodeData node) { + private static String baseClassName(NodeData node) { String nodeid = node.getNodeId(); if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { nodeid = nodeid.substring(0, nodeid.length() - 4); } String name = Utils.firstLetterUpperCase(nodeid); - name += "GenNode"; + name += "BaseNode"; return name; } - private String generatedGenericMethodName(SpecializationData specialization) { - final String prefix = "generic"; - - if (specialization == null) { - return prefix; - } - - if (!specialization.getNode().needsRewrites(context)) { - return prefix; - } - - SpecializationData prev = null; - for (SpecializationData current : specialization.getNode().getSpecializations()) { - if (specialization == current) { - if (prev == null || prev.isUninitialized()) { - return prefix; - } else { - return prefix + current.getId(); - } - } - prev = current; - } - return prefix; - } - private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); startCallTypeSystemMethod(context, builder, node, methodName); @@ -304,14 +289,20 @@ // find out which values needs a cast valuesNeedsCast = new HashSet<>(); for (GuardData guard : targetSpecialization.getGuards()) { - for (ActualParameter parameter : guard.getParameters()) { - NodeChildData field = node.findChild(parameter.getSpecification().getName()); + for (ActualParameter targetParameter : guard.getParameters()) { + NodeChildData field = node.findChild(targetParameter.getSpecification().getName()); if (field == null) { continue; } - TypeData typeData = parameter.getTypeSystemType(); - if (typeData != null && !typeData.isGeneric()) { - valuesNeedsCast.add(parameter.getLocalName()); + TypeData targetType = targetParameter.getTypeSystemType(); + ActualParameter sourceParameter = sourceSpecialization.findParameter(targetParameter.getLocalName()); + if (sourceParameter == null) { + sourceParameter = targetParameter; + } + TypeData sourceType = sourceParameter.getTypeSystemType(); + + if (sourceType.needsCastTo(getContext(), targetType)) { + valuesNeedsCast.add(targetParameter.getLocalName()); } } } @@ -353,14 +344,14 @@ return builder.getRoot(); } - private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; if (guardedSpecialization.getGuards().size() > 0) { // Explicitly specified guards for (GuardData guard : guardedSpecialization.getGuards()) { builder.string(andOperator); - builder.tree(createTemplateMethodCall(parent, valueSpecialization, guard, null)); + builder.tree(createTemplateMethodCall(parent, null, valueSpecialization, guard, null)); andOperator = " && "; } } @@ -368,7 +359,7 @@ return builder.isEmpty() ? null : builder.getRoot(); } - private CodeTree createCasts(CodeTreeBuilder parent, Set castWhiteList, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private CodeTree createCasts(CodeTreeBuilder parent, Set castWhiteList, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); // Implict guards based on method signature for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { @@ -378,6 +369,14 @@ } ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); + if (valueParam == null) { + /* + * If used inside a function execute method. The value param may not exist. In that + * case it assumes that the value is already converted. + */ + valueParam = guardedParam; + } + if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) { continue; } @@ -398,15 +397,9 @@ String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; if (emitAssumptions) { - boolean isStatic = parent.findMethod().getModifiers().contains(STATIC); - for (String assumption : guardedSpecialization.getAssumptions()) { builder.string(andOperator); - if (isStatic) { - builder.string(THIS_NODE_LOCAL_VAR_NAME); - } else { - builder.string("this"); - } + builder.string("this"); builder.string(".").string(assumption).string(".isValid()"); andOperator = " && "; } @@ -419,6 +412,14 @@ } ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); + if (valueParam == null) { + /* + * If used inside a function execute method. The value param may not exist. In that + * case it assumes that the value is already converted. + */ + valueParam = guardedParam; + } + CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); if (implicitGuard == null) { continue; @@ -439,7 +440,7 @@ TypeData targetType = target.getTypeSystemType(); TypeData sourceType = source.getTypeSystemType(); - if (targetType.equalsType(sourceType) || targetType.isGeneric()) { + if (!sourceType.needsCastTo(getContext(), targetType)) { return null; } @@ -471,7 +472,7 @@ TypeData sourceType = source.getTypeSystemType(); TypeData targetType = target.getTypeSystemType(); - if (!sourceType.needsCastTo(targetType)) { + if (!sourceType.needsCastTo(getContext(), targetType)) { return null; } @@ -570,6 +571,16 @@ return true; } + private static CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn().startNew(nodeSpecializationClassName(specialization)); + if (hasCopyConstructor) { + builder.string(thisLocalVariableName); + } + builder.end().end(); + return builder.getRoot(); + } + @Override protected void createChildren(NodeData node) { Map> childTypes = new LinkedHashMap<>(); @@ -585,15 +596,15 @@ } } - private class NodeGenFactory extends ClassElementFactory { + private class NodeBaseFactory extends ClassElementFactory { - public NodeGenFactory(ProcessorContext context) { + public NodeBaseFactory(ProcessorContext context) { super(context); } @Override protected CodeTypeElement create(NodeData node) { - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), genClassName(node), node.getNodeType(), false); + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); for (NodeChildData child : node.getChildren()) { clazz.add(createChildField(child)); @@ -620,6 +631,19 @@ return clazz; } + @Override + protected void createChildren(NodeData node) { + CodeTypeElement clazz = getElement(); + + if (node.needsRewrites(context)) { + clazz.add(createGenericExecute(node, EXECUTE_SPECIALIZE_NAME, true)); + } + + if (node.getGenericSpecialization() != null) { + clazz.add(createGenericExecute(node, EXECUTE_GENERIC_NAME, false)); + } + } + private void createConstructors(NodeData node, CodeTypeElement clazz) { List constructors = findUserConstructors(node.getNodeType()); if (constructors.isEmpty()) { @@ -720,6 +744,162 @@ var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); return var; } + + private CodeExecutableElement createGenericExecute(NodeData node, String name, boolean specialize) { + TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, name); + CodeTreeBuilder builder = method.createBuilder(); + + String prefix = null; + if (specialize) { + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); + + builder.startStatement(); + builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end(); + builder.end(); + + emitSpecializationListeners(builder, node); + builder.defaultDeclaration(node.getGenericSpecialization().getReturnSignature().getPrimitiveType(), "result"); + if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) { + builder.defaultDeclaration(getContext().getType(boolean.class), "resultIsSet"); + } + builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); + prefix = null; + } + + addInternalValueParameters(method, node.getGenericSpecialization(), true); + + List specializations = node.getSpecializations(); + if (!specialize && !node.getGenericSpecialization().isUseSpecializationsForGeneric()) { + specializations = Arrays.asList(node.getGenericSpecialization()); + } + + // group specializations for reachabiltiy + List unreachableSpecializations = new ArrayList<>(); + List filteredSpecializations = new ArrayList<>(); + if (!specialize) { + unreachableSpecializations = new ArrayList<>(); + filteredSpecializations = new ArrayList<>(); + boolean unreachable = false; + for (SpecializationData specialization : specializations) { + if (unreachable) { + unreachableSpecializations.add(specialization); + } else { + filteredSpecializations.add(specialization); + if (!specialization.isUninitialized() && !specialization.hasRewrite(getContext())) { + unreachable = true; + } + } + } + } else { + unreachableSpecializations = Collections.emptyList(); + filteredSpecializations = specializations; + } + + for (SpecializationData current : filteredSpecializations) { + if (current.isUninitialized()) { + continue; + } + CodeTreeBuilder execute = new CodeTreeBuilder(builder); + + execute.tree(createGenericInvoke(builder, current, specialize)); + + if (specialize && !current.isGeneric()) { + builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end(); + } + + builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true)); + } + + for (SpecializationData specializationData : unreachableSpecializations) { + builder.string("// unreachable ").string(specializationData.getId()).newLine(); + } + + return method; + } + + private CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData current, boolean specialize) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + if (!current.getExceptions().isEmpty()) { + builder.startTryBlock(); + } + + CodeTree executeCall = null; + if (current.getMethod() != null) { + executeCall = createTemplateMethodCall(builder, null, current.getNode().getGenericSpecialization(), current, null); + } + + if (specialize && executeCall == null && !current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { + emitEncounteredSynthetic(builder); + } else if (specialize) { + + if (current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { + builder.startIf().string("!resultIsSet").end().startBlock(); + if (executeCall != null) { + if (current.getReturnSignature().isVoid()) { + builder.statement(executeCall); + } else { + builder.startStatement().string("result = ").tree(executeCall).end(); + } + builder.statement("resultIsSet = true"); + } else { + emitEncounteredSynthetic(builder); + } + builder.end(); + } + + if (!current.isGeneric()) { + builder.startIf().string("allowed").end().startBlock(); + } + + if (!current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { + if (current.getReturnSignature().isVoid()) { + builder.statement(executeCall); + } else { + builder.startStatement().string("result = ").tree(executeCall).end(); + } + } + + builder.startStatement().startCall("super", "replace"); + builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end(); + builder.end().end(); + + if (current.getReturnSignature().isVoid()) { + builder.returnStatement(); + } else { + builder.startReturn().string("result").end(); + } + if (!current.isGeneric()) { + builder.end(); + } + } else { + if (executeCall == null) { + emitEncounteredSynthetic(builder); + } else { + builder.startReturn().tree(executeCall).end(); + } + } + + if (!current.getExceptions().isEmpty()) { + for (SpecializationThrowsData exception : current.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); + builder.string("// fall through").newLine(); + } + builder.end(); + } + + return builder.getRoot(); + } + + private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { + for (TemplateMethod listener : node.getSpecializationListeners()) { + builder.startStatement(); + builder.tree(createTemplateMethodCall(builder, null, listener, listener, null)); + builder.end(); // statement + } + } } private class NodeFactoryFactory extends ClassElementFactory { @@ -752,23 +932,15 @@ Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); if (node.needsFactory()) { - NodeGenFactory factory = new NodeGenFactory(context); + NodeBaseFactory factory = new NodeBaseFactory(context); add(factory, node); generatedNode = factory.getElement(); - createFactoryMethods(node, clazz, createVisibility); - if (node.needsRewrites(context)) { clazz.add(createCreateSpecializedMethod(node, createVisibility)); - clazz.add(createSpecializeMethod(node)); } - if (node.getGenericSpecialization() != null) { - List genericMethods = createGeneratedGenericMethod(node); - for (CodeExecutableElement method : genericMethods) { - clazz.add(method); - } - } + createFactoryMethods(node, clazz, createVisibility); for (SpecializationData specialization : node.getSpecializations()) { add(new SpecializedNodeFactory(context, generatedNode), specialization); @@ -1145,125 +1317,6 @@ return method; } - private CodeExecutableElement createSpecializeMethod(NodeData node) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize"); - method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addInternalValueParameters(method, node.getGenericSpecialization(), true); - - CodeTreeBuilder body = method.createBuilder(); - body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); - - boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null; - - for (int i = 1; i < node.getSpecializations().size(); i++) { - SpecializationData specialization = node.getSpecializations().get(i); - body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end(); - - CodeTree guarded = createReturnNewSpecialization(body, specialization, THIS_NODE_LOCAL_VAR_NAME, hasCopyConstructor); - - body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded, null, true)); - } - body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); - - return method; - } - - private CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - builder.startReturn().startNew(nodeSpecializationClassName(specialization)); - if (hasCopyConstructor) { - builder.string(thisLocalVariableName); - } - builder.end().end(); - return builder.getRoot(); - } - - private List createGeneratedGenericMethod(NodeData node) { - TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); - if (node.needsRewrites(context)) { - List methods = new ArrayList<>(); - - List specializations = node.getSpecializations(); - SpecializationData prev = null; - for (int i = 0; i < specializations.size(); i++) { - SpecializationData current = specializations.get(i); - SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null; - if (prev == null || current.isUninitialized()) { - prev = current; - continue; - } else { - String methodName = generatedGenericMethodName(current); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName); - method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); - addInternalValueParameters(method, node.getGenericSpecialization(), true); - - emitGeneratedGenericSpecialization(method.createBuilder(), current, next); - - methods.add(method); - } - prev = current; - } - - return methods; - } else { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null)); - method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); - addInternalValueParameters(method, node.getGenericSpecialization(), true); - emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0); - return Arrays.asList(method); - } - } - - private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) { - CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder); - emitInvokeDoMethod(invokeMethodBuilder, current, 0); - CodeTree invokeMethod = invokeMethodBuilder.getRoot(); - - if (next != null) { - CodeTreeBuilder nextBuilder = builder.create(); - - nextBuilder.startReturn().startCall(generatedGenericMethodName(next)); - nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME); - addInternalValueParameterNames(nextBuilder, next, next, null, true, true); - nextBuilder.end().end(); - - invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot(), true); - } - - builder.tree(invokeMethod); - - if (next != null) { - builder.end(); - } - } - - private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) { - if (!specialization.getExceptions().isEmpty()) { - builder.startTryBlock(); - } - - if (specialization.getMethod() == null) { - emitEncounteredSynthetic(builder); - } else { - builder.startReturn(); - builder.tree(createTemplateMethodCall(builder, specialization.getNode().getGenericSpecialization(), specialization, null)); - builder.end(); // return - } - - if (!specialization.getExceptions().isEmpty()) { - for (SpecializationThrowsData exception : specialization.getExceptions()) { - builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level); - - builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo())); - builder.string(THIS_NODE_LOCAL_VAR_NAME); - addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true); - builder.end().end(); - } - builder.end(); - } - } - } private class SpecializedNodeFactory extends ClassElementFactory { @@ -1313,10 +1366,6 @@ clazz.remove(executeMethod); } } - - if (specialization.hasRewrite(getContext())) { - buildSpecializeAndExecute(clazz, specialization); - } } private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { @@ -1343,7 +1392,12 @@ int i = 0; for (VariableElement param : method.getParameters()) { CodeVariableElement var = CodeVariableElement.clone(param); - var.setName(valueName(execType.getParameters().get(i))); + ActualParameter actualParameter = execType.getParameters().get(i); + if (actualParameter.getSpecification().isSignature()) { + var.setName(valueNameEvaluated(actualParameter)); + } else { + var.setName(valueName(actualParameter)); + } method.getParameters().set(i, var); i++; } @@ -1398,7 +1452,7 @@ CodeTreeBuilder builder = new CodeTreeBuilder(parent); NodeData node = specialization.getNode(); - ExecutableTypeData castedType = node.findExecutableType(type); + ExecutableTypeData castedType = node.findExecutableType(type, 0); TypeData primaryType = castExecutable.getType(); boolean needsTry = castExecutable.hasUnexpectedValue(getContext()); @@ -1413,17 +1467,13 @@ ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName()); if (targetParameter != null) { - TypeData sourceType = sourceParameter.getTypeSystemType(); - TypeData targetType = targetParameter.getTypeSystemType(); - if (sourceType.needsCastTo(targetType)) { - executeParameters.add(targetParameter); - } + executeParameters.add(targetParameter); } } builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true)); - CodeTree primaryExecuteCall = createTemplateMethodCall(builder, executable, castExecutable, null); + CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null); if (needsTry) { if (!returnVoid) { builder.declaration(primaryType.getPrimitiveType(), "value"); @@ -1444,14 +1494,14 @@ builder.string("// ignore").newLine(); } else { builder.startReturn(); - builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()"))); + builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), castedType, CodeTreeBuilder.singleString("ex.getResult()"))); builder.end(); } builder.end(); if (!returnVoid) { builder.startReturn(); - builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value"))); + builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, CodeTreeBuilder.singleString("value"))); builder.end(); } } else { @@ -1459,7 +1509,7 @@ builder.statement(primaryExecuteCall); } else { builder.startReturn(); - builder.tree(createExpectType(node, castedType, primaryExecuteCall)); + builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, primaryExecuteCall)); builder.end(); } } @@ -1467,21 +1517,24 @@ return builder.getRoot(); } - private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) { - if (castedType == null) { + private CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) { + boolean hasUnexpected = castedType.hasUnexpectedValue(getContext()); + return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); + } + + private CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { + if (targetType == null) { return value; - } else if (castedType.getType().isVoid()) { - return value; - } else if (castedType.getType().isGeneric()) { + } else if (!sourceType.needsCastTo(getContext(), targetType)) { return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); String targetMethodName; - if (castedType.hasUnexpectedValue(getContext())) { - targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType()); + if (expect) { + targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); } else { - targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType()); + targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); } startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); @@ -1499,15 +1552,15 @@ builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false)); CodeTree executeNode; - if (specialization.isUninitialized()) { - builder.tree(createSpecializeCall(builder, executable, specialization)); - } executeNode = createExecute(builder, executable, specialization); SpecializationData next = specialization.findNextSpecialization(); CodeTree returnSpecialized = null; if (next != null) { - returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null); + CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); + returnBuilder.tree(createDeoptimize(builder)); + returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null)); + returnSpecialized = returnBuilder.getRoot(); } builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false)); @@ -1522,28 +1575,6 @@ return builder.getRoot(); } - private CodeTree createSpecializeCall(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { - NodeData node = specialization.getNode(); - - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - emitSpecializationListeners(builder, node); - - builder.startStatement(); - builder.startCall("replace"); - if (node.needsRewrites(getContext())) { - builder.startCall(factoryClassName(node), "specialize"); - builder.string("this"); - builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); - addInternalValueParameterNames(builder, executable, specialization, null, true, true); - builder.end(); // call replace, call specialize - } else { - builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); - } - builder.end().end(); - emitSpecializationListeners(builder, node); - return builder.getRoot(); - } - private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { NodeData node = specialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1559,27 +1590,18 @@ CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); if (specialization.isUninitialized()) { - String genericMethodName = generatedGenericMethodName(null); - returnBuilder.startCall(factoryClassName(node), genericMethodName); - returnBuilder.string("this"); - addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true); + returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME); + returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); returnBuilder.end(); } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { emitEncounteredSynthetic(builder); } else if (specialization.isGeneric()) { - String genericMethodName; - if (!specialization.isUseSpecializationsForGeneric()) { - genericMethodName = generatedGenericMethodName(specialization); - } else { - genericMethodName = generatedGenericMethodName(null); - } - - returnBuilder.startCall(factoryClassName(node), genericMethodName); - returnBuilder.string("this"); - addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true); + returnBuilder.startCall("super", EXECUTE_GENERIC_NAME); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); returnBuilder.end(); } else { - returnBuilder.tree(createTemplateMethodCall(returnBuilder, executable, specialization, null)); + returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); } if (!returnBuilder.isEmpty()) { @@ -1590,7 +1612,7 @@ if (targetType == null || sourceType == null) { builder.tree(returnBuilder.getRoot()); - } else if (sourceType.needsCastTo(targetType)) { + } else if (sourceType.needsCastTo(getContext(), targetType)) { builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot())); } else { builder.tree(returnBuilder.getRoot()); @@ -1601,13 +1623,14 @@ if (!specialization.getExceptions().isEmpty()) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); - builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null)); + builder.tree(createDeoptimize(builder)); + builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null)); } builder.end(); } if (!specialization.getAssumptions().isEmpty()) { builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); - builder.tree(createReturnSpecializeAndExecute(parent, executable, specialization.findNextSpecialization(), null)); + builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null)); builder.end(); } @@ -1627,50 +1650,53 @@ } TypeData targetType = targetParameter.getTypeSystemType(); - ExecutableTypeData targetExecutable = field.getNodeData().findExecutableType(targetType); + ExecutableTypeData targetExecutable = field.findExecutableType(getContext(), targetType); ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); - String targetVariableName = null; + String targetVariableName = valueName(targetParameter); CodeTree executionExpression = null; if (cast || sourceParameter != null) { TypeData sourceType = sourceParameter.getTypeSystemType(); - if (!sourceType.needsCastTo(targetType)) { + if (!sourceType.needsCastTo(getContext(), targetType)) { if (field.isShortCircuit() && sourceParameter != null) { - builder.tree(createShortCircuitValue(builder, sourceExecutable, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter)); + builder.tree(createShortCircuitValue(builder, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter)); } - continue; + builder.startStatement(); + builder.type(targetParameter.getType()).string(" "); + builder.string(valueName(targetParameter)).string(" = "); + builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); + builder.end(); + } else { + executionExpression = createExpectExecutableType(sourceNode, sourceType, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); } - executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueName(targetParameter))); - targetVariableName = castValueName(targetParameter); } else if (sourceParameter == null) { - targetVariableName = valueName(targetParameter); - executionExpression = createExecuteChildExpression(builder, field, targetParameter); + executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter); } - CodeTreeVariable executionVar = new CodeTreeVariable(); - CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, sourceExecutable, specialization, targetParameter, unexpectedParameter); - CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter, - shortCircuitTree != executionVar); + if (executionExpression != null) { + CodeTreeVariable executionVar = new CodeTreeVariable(); + CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, specialization, targetParameter, unexpectedParameter); + CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter, + shortCircuitTree != executionVar); - executionVar.set(unexpectedTree); - builder.tree(shortCircuitTree); + executionVar.set(unexpectedTree); + builder.tree(shortCircuitTree); + } } return builder.getRoot(); } - private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { - for (TemplateMethod listener : node.getSpecializationListeners()) { - builder.startStatement(); - builder.tree(createTemplateMethodCall(builder, listener, listener, null)); - builder.end(); // statement - } - } - private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable, ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); boolean unexpected = targetExecutable.hasUnexpectedValue(getContext()); + boolean cast = false; + if (targetExecutable.getType().needsCastTo(getContext(), param.getTypeSystemType())) { + unexpected = true; + cast = true; + } + builder.startStatement(); if (!shortCircuit) { @@ -1689,7 +1715,11 @@ builder.string(targetVariableName); } builder.string(" = "); - builder.tree(body); + if (cast) { + builder.tree(createCastType(specialization.getNode(), targetExecutable.getType(), param.getTypeSystemType(), true, body)); + } else { + builder.tree(body); + } builder.end(); if (unexpected) { @@ -1698,17 +1728,18 @@ ActualParameter genericParameter = generic.findParameter(param.getLocalName()); List genericParameters = generic.getParametersAfter(genericParameter); + builder.tree(createDeoptimize(builder)); builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false)); - builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param)); + builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param)); builder.end(); // catch block } return builder.getRoot(); } - private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter) { + private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) { TypeData type = sourceParameter.getTypeSystemType(); - ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type); + ExecutableTypeData execType = targetField.findExecutableType(getContext(), type); /* * FIXME Temporary deactivated due to partial evaluation failure else if @@ -1730,16 +1761,47 @@ } builder.string("."); } + builder.startCall(execType.getMethodName()); - if (execType.getParameters().size() == 1) { - builder.string("frameValue"); + + List signatureParameters = getModel().getSignatureParameters(); + int index = 0; + for (ActualParameter parameter : execType.getParameters()) { + + if (!parameter.getSpecification().isSignature()) { + builder.string(parameter.getLocalName()); + } else { + if (index < signatureParameters.size()) { + ActualParameter specializationParam = signatureParameters.get(index); + + TypeData targetType = parameter.getTypeSystemType(); + TypeData sourceType = specializationParam.getTypeSystemType(); + String localName = specializationParam.getLocalName(); + if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) { + localName = "ex.getResult()"; + sourceType = getModel().getNode().getTypeSystem().getGenericTypeData(); + } + + CodeTree value = CodeTreeBuilder.singleString(localName); + + if (sourceType.needsCastTo(getContext(), targetType)) { + value = createCallTypeSystemMethod(getContext(), builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value); + } + builder.tree(value); + } else { + builder.defaultValue(parameter.getType()); + } + index++; + } } + builder.end(); + return builder.getRoot(); } - private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, ExecutableTypeData currentExecutable, SpecializationData specialization, - ActualParameter parameter, ActualParameter exceptionParam) { + private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ActualParameter parameter, + ActualParameter exceptionParam) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName()); @@ -1753,7 +1815,7 @@ ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); - builder.tree(createShortCircuitValue(builder, currentExecutable, specialization, forField, shortCircuitParam, exceptionParam)); + builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam)); builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); builder.startIf().string(shortCircuitParam.getLocalName()).end(); @@ -1764,8 +1826,7 @@ return builder.getRoot(); } - private CodeTree createShortCircuitValue(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, NodeChildData forField, - ActualParameter shortCircuitParam, ActualParameter exceptionParam) { + private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeChildData forField, ActualParameter shortCircuitParam, ActualParameter exceptionParam) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); int shortCircuitIndex = 0; for (NodeChildData field : specialization.getNode().getChildren()) { @@ -1779,77 +1840,30 @@ builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); - builder.tree(createTemplateMethodCall(builder, currentExecutable, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); + builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); builder.end(); // statement return builder.getRoot(); } - private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) { + private CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) { + + SpecializationData generic = nextSpecialization.getNode().getGenericSpecialization(); CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); - specializeCall.startCall("specializeAndExecute"); + specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); - addInternalValueParameterNames(specializeCall, executable, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, - true); + addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); specializeCall.end().end(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn(); - builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot())); + builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnSignature(), executable, specializeCall.getRoot())); builder.end(); return builder.getRoot(); } - private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) { - NodeData node = specialization.getNode(); - TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType(); - - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute"); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true); - clazz.add(method); - - CodeTreeBuilder builder = method.createBuilder(); - - builder.tree(createDeoptimize(builder)); - emitSpecializationListeners(builder, specialization.getNode()); - - builder.startStatement(); - builder.startCall("replace"); - builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); - addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true); - builder.end(); - builder.end(); // call replace - builder.end(); // statement - - String generatedMethodName; - if (specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { - generatedMethodName = generatedGenericMethodName(null); - } else { - generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization()); - } - ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName); - - CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); - genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName); - genericExecute.string("this"); - addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true); - genericExecute.end(); // call generated generic - - CodeTree genericInvocation = genericExecute.getRoot(); - - if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) { - builder.statement(genericInvocation); - - if (!Utils.isVoid(builder.findMethod().asType())) { - builder.startReturn().defaultValue(returnType.getPrimitiveType()).end(); - } - } else { - builder.startReturn().tree(genericInvocation).end(); - } - } - } } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Sun Apr 28 22:52:12 2013 +0200 @@ -224,8 +224,8 @@ return methods; } - public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) { - List types = findGenericExecutableTypes(context); + public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type, int evaluatedCount) { + List types = findGenericExecutableTypes(context, evaluatedCount); for (ExecutableTypeData availableType : types) { if (Utils.typeEquals(availableType.getType().getBoxedType(), type.getBoxedType())) { return availableType; @@ -234,8 +234,8 @@ return null; } - public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { - List types = findGenericExecutableTypes(context); + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) { + List types = findGenericExecutableTypes(context, evaluatedCount); for (ExecutableTypeData type : types) { if (type.getType().isGeneric()) { return type; @@ -261,13 +261,17 @@ } return typeData; } else { - return executableTypes.get(evaluatedCount); + List types = executableTypes.get(evaluatedCount); + if (types == null) { + return Collections.emptyList(); + } + return types; } } - public List findGenericExecutableTypes(ProcessorContext context) { + public List findGenericExecutableTypes(ProcessorContext context, int evaluatedCount) { List types = new ArrayList<>(); - for (ExecutableTypeData type : getExecutableTypes(0)) { + for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { if (!type.hasUnexpectedValue(context)) { types.add(type); } @@ -275,8 +279,8 @@ return types; } - public ExecutableTypeData findExecutableType(TypeData prmitiveType) { - for (ExecutableTypeData type : getExecutableTypes(0)) { + public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) { + for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { if (Utils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) { return type; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Sun Apr 28 22:52:12 2013 +0200 @@ -42,7 +42,8 @@ return template; } - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { + @SuppressWarnings("unused") + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) { ParameterSpec spec = new ParameterSpec(valueName, nodeTypeMirrors(nodeData)); spec.setSignature(true); return spec; @@ -61,7 +62,7 @@ } protected ParameterSpec createReturnParameterSpec() { - return createValueParameterSpec("returnValue", getNode()); + return createValueParameterSpec("returnValue", getNode(), 0); } @Override @@ -95,7 +96,7 @@ if (getNode().getChildren() != null) { for (NodeChildData child : getNode().getChildren()) { if (child.getExecutionKind() == ExecutionKind.DEFAULT) { - ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData()); + ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData(), child.getExecuteWith().size()); if (child.getCardinality().isMany()) { spec.setCardinality(Cardinality.MANY); spec.setIndexed(true); @@ -110,7 +111,7 @@ if (shortCircuitsEnabled) { methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class))); } - methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData())); + methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData(), child.getExecuteWith().size())); } else { assert false; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Sun Apr 28 22:52:12 2013 +0200 @@ -310,7 +310,7 @@ GenericParser parser = new GenericParser(context, node); MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null); - ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context); + ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context, 0); assert anyGenericReturnType != null; ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType(), 0, false); @@ -322,7 +322,7 @@ if (child == null) { actualType = specializationParameter.getTypeSystemType(); } else { - ExecutableTypeData paramType = child.getNodeData().findAnyGenericExecutableType(context); + ExecutableTypeData paramType = child.findAnyGenericExecutableType(context); assert paramType != null; actualType = paramType.getType(); } @@ -582,11 +582,10 @@ nodeData.setSplitByMethodName(splitByMethodName); nodeData.setTypeSystem(typeSystem); nodeData.setFields(parseFields(elements)); + parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); + // parseChildren invokes cyclic parsing. + nodeData.setChildren(parseChildren(elements, lookupTypes)); nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); - parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); - - // parseChildren invokes cyclic parsing. - nodeData.setChildren(parseChildren(templateType, elements, lookupTypes)); return nodeData; } @@ -723,7 +722,7 @@ return fields; } - private List parseChildren(TypeElement templateType, List elements, final List typeHierarchy) { + private List parseChildren(List elements, final List typeHierarchy) { Set shortCircuits = new HashSet<>(); for (ExecutableElement method : ElementFilter.methodsIn(elements)) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); @@ -766,7 +765,7 @@ kind = ExecutionKind.SHORT_CIRCUIT; } - NodeChildData nodeChild = new NodeChildData(templateType, childMirror, name, childType, getter, cardinality, kind); + NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, getter, cardinality, kind); parsedChildren.add(nodeChild); @@ -779,8 +778,6 @@ nodeChild.setNode(fieldNodeData); if (fieldNodeData == null) { nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType)); - } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) { - nodeChild.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type)); } } } @@ -794,6 +791,53 @@ encounteredNames.add(child.getName()); } } + + for (NodeChildData child : filteredChildren) { + List executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith"); + AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith"); + List executeWith = new ArrayList<>(); + for (String executeWithString : executeWithStrings) { + + if (child.getName().equals(executeWithString)) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString); + continue; + } + + NodeChildData found = null; + boolean before = true; + for (NodeChildData resolveChild : filteredChildren) { + if (resolveChild == child) { + before = false; + continue; + } + if (resolveChild.getName().equals(executeWithString)) { + found = resolveChild; + break; + } + } + + if (found == null) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString); + continue; + } else if (!before) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString, + executeWithString); + continue; + } + executeWith.add(found); + } + child.setExecuteWith(executeWith); + if (child.getNodeData() == null) { + continue; + } + + List types = child.findGenericExecutableTypes(context); + if (types.isEmpty()) { + child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", executeWith.size(), Utils.getSimpleName(child.getNodeType())); + continue; + } + } + return filteredChildren; } @@ -931,7 +975,7 @@ continue; } ExecutableTypeData found = null; - List executableElements = field.getNodeData().findGenericExecutableTypes(context); + List executableElements = field.findGenericExecutableTypes(context); for (ExecutableTypeData executable : executableElements) { if (executable.getType().equalsType(parameter.getTypeSystemType())) { found = executable; diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Sun Apr 28 22:52:12 2013 +0200 @@ -85,14 +85,18 @@ return true; } for (ActualParameter parameter : getParameters()) { - NodeChildData field = getNode().findChild(parameter.getSpecification().getName()); - if (field == null) { + NodeChildData child = getNode().findChild(parameter.getSpecification().getName()); + if (child == null) { continue; } - ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getTypeSystemType()); + ExecutableTypeData type = child.findExecutableType(context, parameter.getTypeSystemType()); if (type.hasUnexpectedValue(context)) { return true; } + if (type.getReturnType().getTypeSystemType().needsCastTo(context, parameter.getTypeSystemType())) { + return true; + } + } return false; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java Sun Apr 28 22:52:12 2013 +0200 @@ -34,11 +34,15 @@ private final List messages = new ArrayList<>(); public final void addWarning(String text, Object... params) { - getMessages().add(new Message(this, String.format(text, params), Kind.WARNING)); + getMessages().add(new Message(null, this, String.format(text, params), Kind.WARNING)); } public final void addError(String text, Object... params) { - getMessages().add(new Message(this, String.format(text, params), Kind.ERROR)); + addError(null, text, params); + } + + public final void addError(AnnotationValue value, String text, Object... params) { + getMessages().add(new Message(value, this, String.format(text, params), Kind.ERROR)); } protected List findChildContainers() { @@ -150,15 +154,21 @@ public static final class Message { private final MessageContainer originalContainer; + private final AnnotationValue annotationValue; private final String text; private final Kind kind; - public Message(MessageContainer originalContainer, String text, Kind kind) { + public Message(AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) { + this.annotationValue = annotationValue; this.originalContainer = originalContainer; this.text = text; this.kind = kind; } + public AnnotationValue getAnnotationValue() { + return annotationValue; + } + public MessageContainer getOriginalContainer() { return originalContainer; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Sun Apr 28 22:52:12 2013 +0200 @@ -206,6 +206,17 @@ return types; } + public List getSignatureParameters() { + List types = new ArrayList<>(); + for (ActualParameter parameter : getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + types.add(parameter); + } + return types; + } + @Override public int compareTo(TemplateMethod o) { if (this == o) { diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Sun Apr 28 22:52:12 2013 +0200 @@ -110,13 +110,15 @@ return Utils.typeEquals(boxedType, actualTypeData.boxedType); } - public boolean needsCastTo(TypeData targetType) { + public boolean needsCastTo(ProcessorContext context, TypeData targetType) { if (this.equals(targetType)) { return false; } else if (targetType.isGeneric()) { return false; } else if (targetType.isVoid()) { return false; + } else if (Utils.isAssignable(context, getPrimitiveType(), targetType.getPrimitiveType())) { + return false; } return true; } diff -r c21b1e5b515c -r 16a10b48e526 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Sun Apr 28 22:34:46 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Sun Apr 28 22:52:12 2013 +0200 @@ -59,7 +59,7 @@ } public TypedNode createLocal(String name) { - return ReadLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, int.class)); + return ReadLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, FrameSlotKind.Int)); } public TypedNode createStringLiteral(String value) { @@ -67,7 +67,7 @@ } public StatementNode createAssignment(String name, TypedNode right) { - return WriteLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, int.class), right); + return WriteLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, FrameSlotKind.Int), right); } public StatementNode createPrint(List expressions) { @@ -123,7 +123,7 @@ } public StatementNode createReturn(TypedNode value) { - FrameSlot slot = frameDescriptor.findOrAddFrameSlot("", int.class); + FrameSlot slot = frameDescriptor.findOrAddFrameSlot("", FrameSlotKind.Int); if (returnValue == null) { returnValue = ReadLocalNodeFactory.create(slot); } diff -r c21b1e5b515c -r 16a10b48e526 mx/commands.py --- a/mx/commands.py Sun Apr 28 22:34:46 2013 +0200 +++ b/mx/commands.py Sun Apr 28 22:52:12 2013 +0200 @@ -749,7 +749,7 @@ excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True).keys() excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True).keys() - includes = ['com.oracle.graal.*', 'com.oracle.max.*'] + includes = ['com.oracle.graal.*'] agentOptions = { 'append' : 'true' if _jacoco == 'append' else 'false', 'bootclasspath' : 'true', @@ -1361,7 +1361,7 @@ mx.add_argument('--' + c, action='store_const', dest='vmbuild', const=c, help='select the ' + c + ' build of the VM') mx.add_argument('--ecl', action='store_true', dest='make_eclipse_launch', help='create launch configuration for running VM execution(s) in Eclipse') mx.add_argument('--native-dbg', action='store', dest='native_dbg', help='Start the vm inside a debugger', metavar='') - mx.add_argument('--gdb', action='store_const', const='/usr/bin/gdb --args', dest='native_dbg', help='alias for --native-dbg /usr/bin/gdb -- args') + mx.add_argument('--gdb', action='store_const', const='/usr/bin/gdb --args', dest='native_dbg', help='alias for --native-dbg /usr/bin/gdb --args') commands.update({ 'export': [export, '[-options] [zipfile]'], diff -r c21b1e5b515c -r 16a10b48e526 mx/sanitycheck.py --- a/mx/sanitycheck.py Sun Apr 28 22:34:46 2013 +0200 +++ b/mx/sanitycheck.py Sun Apr 28 22:52:12 2013 +0200 @@ -47,7 +47,8 @@ } dacapoScalaSanityWarmup = { - 'actors': [0, 0, 2, 8, 10], +# (tw) actors sometimes fails verification; hardly reproducible + 'actors': [0, 0, 0, 0, 0], # (lstadler) apparat was disabled due to a deadlock which I think is the benchmarks fault. 'apparat': [0, 0, 0, 0, 0], 'factorie': [0, 0, 2, 5, 5], diff -r c21b1e5b515c -r 16a10b48e526 src/cpu/x86/vm/graalRuntime_x86.cpp --- a/src/cpu/x86/vm/graalRuntime_x86.cpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/cpu/x86/vm/graalRuntime_x86.cpp Sun Apr 28 22:52:12 2013 +0200 @@ -811,68 +811,6 @@ OopMapSet* oop_maps = NULL; switch (id) { - case new_instance_id: - { - Register klass = rdx; // Incoming - Register obj = rax; // Result - __ set_info("new_instance", dont_gc_arguments); - __ enter(); - OopMap* map = save_live_registers(sasm, 2); - int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance), klass); - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - __ verify_oop(obj); - __ leave(); - __ ret(0); - - // rax,: new instance - } - - break; - - case new_array_id: - { - Register length = rbx; // Incoming - Register klass = rdx; // Incoming - Register obj = rax; // Result - - __ set_info("new_array", dont_gc_arguments); - - __ enter(); - OopMap* map = save_live_registers(sasm, 3); - int call_offset; - call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_array), klass, length); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - - __ verify_oop(obj); - __ leave(); - __ ret(0); - - // rax,: new array - } - break; - - case new_multi_array_id: - { GraalStubFrame f(sasm, "new_multi_array", dont_gc_arguments); - // rax,: klass - // rbx,: rank - // rcx: address of 1st dimension - OopMap* map = save_live_registers(sasm, 4); - int call_offset = __ call_RT(rax, noreg, CAST_FROM_FN_PTR(address, new_multi_array), rax, rbx, rcx); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - - // rax,: new multi array - __ verify_oop(rax); - } - break; - case register_finalizer_id: { __ set_info("register_finalizer", dont_gc_arguments); diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Sun Apr 28 22:52:12 2013 +0200 @@ -183,7 +183,7 @@ do_klass(Long_klass, java_lang_Long, Pre ) \ \ /* Support for Graal */ \ - do_klass(GraalBitMap_klass, java_util_BitSet, Opt) \ + do_klass(BitSet_klass, java_util_BitSet, Opt) \ /* graal.hotspot */ \ do_klass(HotSpotCompilationResult_klass, com_oracle_graal_hotspot_HotSpotCompilationResult, Opt) \ do_klass(HotSpotRuntimeCallTarget_klass, com_oracle_graal_hotspot_HotSpotRuntimeCallTarget, Opt) \ @@ -205,6 +205,7 @@ do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_code_Assumptions_CallSiteTargetValue, Opt) \ do_klass(BytecodePosition_klass, com_oracle_graal_api_code_BytecodePosition, Opt) \ do_klass(DebugInfo_klass, com_oracle_graal_api_code_DebugInfo, Opt) \ + do_klass(RegisterSaveLayout_klass, com_oracle_graal_api_code_RegisterSaveLayout, Opt) \ do_klass(BytecodeFrame_klass, com_oracle_graal_api_code_BytecodeFrame, Opt) \ do_klass(CompilationResult_klass, com_oracle_graal_api_code_CompilationResult, Opt) \ do_klass(CompilationResult_Call_klass, com_oracle_graal_api_code_CompilationResult_Call, Opt) \ diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Sun Apr 28 22:52:12 2013 +0200 @@ -341,6 +341,7 @@ template(com_oracle_graal_api_code_RegisterValue, "com/oracle/graal/api/code/RegisterValue") \ template(com_oracle_graal_api_code_StackSlot, "com/oracle/graal/api/code/StackSlot") \ template(com_oracle_graal_api_code_VirtualObject, "com/oracle/graal/api/code/VirtualObject") \ + template(com_oracle_graal_api_code_RegisterSaveLayout, "com/oracle/graal/api/code/RegisterSaveLayout") \ template(com_oracle_graal_api_code_InvalidInstalledCodeException, "com/oracle/graal/api/code/InvalidInstalledCodeException") \ template(startCompiler_name, "startCompiler") \ template(bootstrap_name, "bootstrap") \ diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Sun Apr 28 22:52:12 2013 +0200 @@ -68,16 +68,16 @@ const int MapWordBits = 64; -static bool is_bit_set(oop bit_map, int i) { - jint extra_idx = i / MapWordBits; - arrayOop extra = (arrayOop) GraalBitMap::words(bit_map); - assert(extra_idx >= 0 && extra_idx < extra->length(), "unexpected index"); - jlong word = ((jlong*) extra->base(T_LONG))[extra_idx]; +static bool is_bit_set(oop bitset, int i) { + jint words_idx = i / MapWordBits; + arrayOop words = (arrayOop) BitSet::words(bitset); + assert(words_idx >= 0 && words_idx < words->length(), "unexpected index"); + jlong word = ((jlong*) words->base(T_LONG))[words_idx]; return (word & (1LL << (i % MapWordBits))) != 0; } -static int bitmap_size(oop bit_map) { - arrayOop arr = (arrayOop) GraalBitMap::words(bit_map); +static int bitset_size(oop bitset) { + arrayOop arr = (arrayOop) BitSet::words(bitset); return arr->length() * MapWordBits; } @@ -86,23 +86,24 @@ OopMap* map = new OopMap(total_frame_size, parameter_count); oop register_map = (oop) DebugInfo::registerRefMap(debug_info); oop frame_map = (oop) DebugInfo::frameRefMap(debug_info); + oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info); if (register_map != NULL) { for (jint i = 0; i < RegisterImpl::number_of_registers; i++) { bool is_oop = is_bit_set(register_map, i); - VMReg reg = get_hotspot_reg(i); + VMReg hotspot_reg = get_hotspot_reg(i); if (is_oop) { - map->set_oop(reg); + map->set_oop(hotspot_reg); } else { - map->set_value(reg); + map->set_value(hotspot_reg); } } } - for (jint i = 0; i < bitmap_size(frame_map); i++) { + for (jint i = 0; i < bitset_size(frame_map); i++) { bool is_oop = is_bit_set(frame_map, i); // HotSpot stack slots are 4 bytes - VMReg reg = VMRegImpl::stack2reg(i * 2); + VMReg reg = VMRegImpl::stack2reg(i * VMRegImpl::slots_per_word); if (is_oop) { map->set_oop(reg); } else { @@ -110,6 +111,26 @@ } } + if (callee_save_info != NULL) { + objArrayOop registers = (objArrayOop) RegisterSaveLayout::registers(callee_save_info); + arrayOop slots = (arrayOop) RegisterSaveLayout::slots(callee_save_info); + for (jint i = 0; i < slots->length(); i++) { + oop graal_reg = registers->obj_at(i); + jint graal_reg_number = code_Register::number(graal_reg); + VMReg hotspot_reg = get_hotspot_reg(graal_reg_number); + // HotSpot stack slots are 4 bytes + jint graal_slot = ((jint*) slots->base(T_INT))[i]; + jint hotspot_slot = graal_slot * VMRegImpl::slots_per_word; + VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot); + map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg); +#ifdef _LP64 + // (copied from generate_oop_map() in c1_Runtime1_x86.cpp) + VMReg hotspot_slot_hi_as_reg = VMRegImpl::stack2reg(hotspot_slot + 1); + map->set_callee_saved(hotspot_slot_hi_as_reg, hotspot_reg->next()); +#endif + } + } + return map; } @@ -330,7 +351,7 @@ } // constructor used to create a method -CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations) { +CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations) { GraalCompiler::initialize_buffer_blob(); CodeBuffer buffer(JavaThread::current()->get_buffer_blob()); jobject comp_result_obj = JNIHandles::make_local(comp_result()); @@ -347,8 +368,21 @@ int stack_slots = _total_frame_size / HeapWordSize; // conversion to words GrowableArray* leaf_graph_ids = get_leaf_graph_ids(comp_result); - result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, - GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations); + if (_stubName != NULL) { + char* name = strdup(java_lang_String::as_utf8_string(_stubName)); + cb = RuntimeStub::new_runtime_stub(name, + &buffer, + CodeOffsets::frame_never_safe, + stack_slots, + _debug_recorder->_oopmaps, + false); + result = GraalEnv::ok; + } else { + nmethod* nm = NULL; + result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, + GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations); + cb = nm; + } } void CodeInstaller::initialize_fields(oop comp_result, methodHandle method) { @@ -357,7 +391,7 @@ _parameter_count = method->size_of_parameters(); TRACE_graal_1("installing code for %s", method->name_and_sig_as_C_string()); } - _name = HotSpotCompilationResult::name(comp_result); + _stubName = HotSpotCompilationResult::stubName(comp_result); _sites = (arrayOop) HotSpotCompilationResult::sites(comp_result); _exception_handlers = (arrayOop) HotSpotCompilationResult::exceptionHandlers(comp_result); @@ -640,8 +674,14 @@ if (target->is_a(SystemDictionary::HotSpotInstalledCode_klass())) { assert(inst->is_jump(), "jump expected"); - nmethod* nm = (nmethod*) HotSpotInstalledCode::nmethod(target); - nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point()); + CodeBlob* cb = (CodeBlob*) (address) HotSpotInstalledCode::codeBlob(target); + assert(cb != NULL, "npe"); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point()); + } else { + nativeJump_at((address)inst)->set_jump_destination(cb->code_begin()); + } _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand); return; diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/graal/graalCodeInstaller.hpp --- a/src/share/vm/graal/graalCodeInstaller.hpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.hpp Sun Apr 28 22:52:12 2013 +0200 @@ -51,7 +51,7 @@ Arena _arena; oop _comp_result; - oop _name; + oop _stubName; arrayOop _sites; arrayOop _exception_handlers; CodeOffsets _offsets; @@ -76,11 +76,7 @@ public: - // constructor used to create a method - CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations); - - // constructor used to create a stub - CodeInstaller(Handle& target_method, BufferBlob*& blob, jlong& id); + CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations); static address runtime_call_target_address(oop runtime_call); diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Sun Apr 28 22:52:12 2013 +0200 @@ -620,7 +620,7 @@ #define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0) #define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0) #define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0) -#define set_stub(name, value) do { set_long(name, (jlong) value); } while (0) +#define set_address(name, value) do { set_long(name, (jlong) value); } while (0) #define set_object(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "Ljava/lang/Object;"), value); } while (0) #define set_int_array(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "[I"), value); } while (0) @@ -699,6 +699,7 @@ set_int("arrayKlassComponentMirrorOffset", in_bytes(ArrayKlass::component_mirror_offset())); + set_int("pendingExceptionOffset", in_bytes(ThreadShadow::pending_exception_offset())); set_int("pendingDeoptimizationOffset", in_bytes(ThreadShadow::pending_deoptimization_offset())); set_int("metaspaceArrayLengthOffset", Array::length_offset_in_bytes()); @@ -721,6 +722,10 @@ set_int("threadTlabStartOffset", in_bytes(JavaThread::tlab_start_offset())); set_int("threadTlabSizeOffset", in_bytes(JavaThread::tlab_size_offset())); set_int("threadAllocatedBytesOffset", in_bytes(JavaThread::allocated_bytes_offset())); + set_int("threadLastJavaSpOffset", in_bytes(JavaThread::last_Java_sp_offset())); + set_int("threadLastJavaFpOffset", in_bytes(JavaThread::last_Java_fp_offset())); + set_int("threadLastJavaPcOffset", in_bytes(JavaThread::last_Java_pc_offset())); + set_int("threadObjectResultOffset", in_bytes(JavaThread::vm_result_offset())); set_int("tlabSlowAllocationsOffset", in_bytes(JavaThread::tlab_slow_allocations_offset())); set_int("tlabFastRefillWasteOffset", in_bytes(JavaThread::tlab_fast_refill_waste_offset())); set_int("tlabNumberOfRefillsOffset", in_bytes(JavaThread::tlab_number_of_refills_offset())); @@ -742,42 +747,43 @@ set_int("layoutHelperOffset", in_bytes(Klass::layout_helper_offset())); - set_stub("wbPreCallStub", GraalRuntime::entry_for(GraalRuntime::wb_pre_call_id)); - set_stub("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id)); + set_address("wbPreCallStub", GraalRuntime::entry_for(GraalRuntime::wb_pre_call_id)); + set_address("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id)); - set_stub("newInstanceStub", GraalRuntime::entry_for(GraalRuntime::new_instance_id)); - set_stub("newArrayStub", GraalRuntime::entry_for(GraalRuntime::new_array_id)); - set_stub("newMultiArrayStub", GraalRuntime::entry_for(GraalRuntime::new_multi_array_id)); - set_stub("identityHashCodeStub", GraalRuntime::entry_for(GraalRuntime::identity_hash_code_id)); - set_stub("threadIsInterruptedStub", GraalRuntime::entry_for(GraalRuntime::thread_is_interrupted_id)); - set_stub("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub()); - set_stub("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id)); - set_stub("handleDeoptStub", SharedRuntime::deopt_blob()->unpack()); - set_stub("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id)); - set_stub("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id)); - set_stub("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id)); - set_stub("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id)); - set_stub("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap()); - set_stub("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id)); - set_stub("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id)); - set_stub("registerFinalizerStub", GraalRuntime::entry_for(GraalRuntime::register_finalizer_id)); - set_stub("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id)); - set_stub("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id)); - set_stub("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis)); - set_stub("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos)); - set_stub("arithmeticFremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_frem_id)); - set_stub("arithmeticDremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_drem_id)); - set_stub("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin)); - set_stub("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos)); - set_stub("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); - set_stub("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id)); - set_stub("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id)); - set_stub("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id)); - set_stub("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id)); - set_stub("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock()); - set_stub("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock()); - set_stub("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt()); - set_stub("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt()); + set_address("identityHashCodeStub", GraalRuntime::entry_for(GraalRuntime::identity_hash_code_id)); + set_address("threadIsInterruptedStub", GraalRuntime::entry_for(GraalRuntime::thread_is_interrupted_id)); + set_address("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub()); + set_address("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id)); + set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack()); + set_address("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id)); + set_address("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id)); + set_address("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id)); + set_address("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id)); + set_address("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap()); + set_address("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id)); + set_address("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id)); + set_address("registerFinalizerStub", GraalRuntime::entry_for(GraalRuntime::register_finalizer_id)); + set_address("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id)); + set_address("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id)); + set_address("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis)); + set_address("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos)); + set_address("arithmeticFremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_frem_id)); + set_address("arithmeticDremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_drem_id)); + set_address("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin)); + set_address("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos)); + set_address("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); + set_address("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id)); + set_address("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id)); + set_address("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id)); + set_address("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id)); + set_address("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock()); + set_address("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock()); + set_address("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt()); + set_address("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt()); + + set_address("newInstanceAddress", GraalRuntime::new_instance); + set_address("newArrayAddress", GraalRuntime::new_array); + set_address("newMultiArrayAddress", GraalRuntime::new_multi_array); set_int("deoptReasonNone", Deoptimization::Reason_none); set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check); @@ -849,12 +855,13 @@ ResourceMark rm; HandleMark hm; Handle compResultHandle = JNIHandles::resolve(compResult); - nmethod* nm = NULL; + CodeBlob* cb = NULL; methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(compResult)); Handle installed_code_handle = JNIHandles::resolve(installed_code); Handle triggered_deoptimizations_handle = JNIHandles::resolve(triggered_deoptimizations); GraalEnv::CodeInstallResult result; - CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle, triggered_deoptimizations_handle); + + CodeInstaller installer(compResultHandle, method, result, cb, installed_code_handle, triggered_deoptimizations_handle); if (PrintCodeCacheOnCompilation) { stringStream s; @@ -868,13 +875,15 @@ } if (result != GraalEnv::ok) { - assert(nm == NULL, "should be"); + assert(cb == NULL, "should be"); } else { if (!installed_code_handle.is_null()) { assert(installed_code_handle->is_a(HotSpotInstalledCode::klass()), "wrong type"); - HotSpotInstalledCode::set_nmethod(installed_code_handle, (jlong) nm); + HotSpotInstalledCode::set_codeBlob(installed_code_handle, (jlong) cb); HotSpotInstalledCode::set_method(installed_code_handle, HotSpotCompilationResult::method(compResult)); - HotSpotInstalledCode::set_start(installed_code_handle, (jlong) nm->code_begin()); + HotSpotInstalledCode::set_start(installed_code_handle, (jlong) cb->code_begin()); + HotSpotInstalledCode::set_isNmethod(installed_code_handle, cb->is_nmethod()); + nmethod* nm = cb->as_nmethod_or_null(); assert(nm == NULL || !installed_code_handle->is_scavengable() || nm->on_scavenge_root_list(), "nm should be scavengable if installed_code is scavengable"); } } @@ -886,30 +895,53 @@ method->clear_queued_for_compilation(); C2V_END -C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod)) +C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject, jlong codeBlob)) + ResourceMark rm; + HandleMark hm; + + CodeBlob* cb = (CodeBlob*) (address) codeBlob; + if (cb == NULL) { + return NULL; + } + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + if (!nm->is_alive()) { + return NULL; + } + } + int length = cb->code_size(); + arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0); + memcpy(codeCopy->base(T_BYTE), cb->code_begin(), length); + return JNIHandles::make_local(codeCopy); +C2V_END + +C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob)) ResourceMark rm; HandleMark hm; - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { + CodeBlob* cb = (CodeBlob*) (address) codeBlob; + if (cb == NULL) { return NULL; } - int length = nm->code_size(); - arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0); - memcpy(codeCopy->base(T_BYTE), nm->code_begin(), length); - return JNIHandles::make_local(codeCopy); -C2V_END -C2V_VMENTRY(jobject, disassembleNMethod, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod)) - ResourceMark rm; - HandleMark hm; - - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { - return NULL; + // We don't want the stringStream buffer to resize during disassembly as it + // uses scoped resource memory. If a nested function called during disassembly uses + // a ResourceMark and the buffer expands within the scope of the mark, + // the buffer becomes garbage when that scope is exited. Experience shows that + // the disassembled code is typically about 10x the code size so a fixed buffer + // sized to 20x code size should be sufficient. + int bufferSize = cb->code_size() * 20; + char* buffer = NEW_RESOURCE_ARRAY(char, bufferSize); + stringStream st(buffer, bufferSize); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + if (!nm->is_alive()) { + return NULL; + } + Disassembler::decode(nm, &st); + } else { + Disassembler::decode(cb, &st); } - stringStream(st); - Disassembler::decode(nm, &st); Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); return JNIHandles::make_local(result()); @@ -924,11 +956,11 @@ return JNIHandles::make_local(element); C2V_END -C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nativeMethod)) +C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nmethodValue)) ResourceMark rm; HandleMark hm; - nmethod* nm = (nmethod*) (address) nativeMethod; + nmethod* nm = (nmethod*) (address) nmethodValue; methodHandle mh = nm->method(); Symbol* signature = mh->signature(); JavaCallArguments jca(mh->size_of_parameters()); @@ -1150,7 +1182,7 @@ {CC"initializeConfiguration", CC"("HS_CONFIG")V", FN_PTR(initializeConfiguration)}, {CC"installCode0", CC"("HS_COMP_RESULT HS_INSTALLED_CODE"[Z)I", FN_PTR(installCode0)}, {CC"getCode", CC"(J)[B", FN_PTR(getCode)}, - {CC"disassembleNMethod", CC"(J)"STRING, FN_PTR(disassembleNMethod)}, + {CC"disassembleCodeBlob", CC"(J)"STRING, FN_PTR(disassembleCodeBlob)}, {CC"executeCompiledMethodVarargs", CC"(["OBJECT NMETHOD")"OBJECT, FN_PTR(executeCompiledMethodVarargs)}, {CC"getDeoptedLeafGraphIds", CC"()[J", FN_PTR(getDeoptedLeafGraphIds)}, {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/graal/graalJavaAccess.cpp --- a/src/share/vm/graal/graalJavaAccess.cpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/graal/graalJavaAccess.cpp Sun Apr 28 22:52:12 2013 +0200 @@ -32,7 +32,7 @@ Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); #ifndef PRODUCT - if (name_symbol == NULL) { + if (name_symbol == NULL || signature_symbol == NULL) { tty->print_cr("symbol with name %s was not found in symbol table (klass=%s)", name, klass->name()->as_C_string()); } #endif diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Sun Apr 28 22:52:12 2013 +0200 @@ -73,15 +73,16 @@ int_field(HotSpotResolvedJavaField, flags) \ end_class \ start_class(HotSpotInstalledCode) \ - long_field(HotSpotInstalledCode, nmethod) \ + long_field(HotSpotInstalledCode, codeBlob) \ oop_field(HotSpotInstalledCode, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;") \ long_field(HotSpotInstalledCode, start) \ boolean_field(HotSpotInstalledCode, isDefault) \ + boolean_field(HotSpotInstalledCode, isNmethod) \ end_class \ start_class(HotSpotCompilationResult) \ oop_field(HotSpotCompilationResult, comp, "Lcom/oracle/graal/api/code/CompilationResult;") \ oop_field(HotSpotCompilationResult, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;") \ - oop_field(HotSpotCompilationResult, name, "Ljava/lang/String;") \ + oop_field(HotSpotCompilationResult, stubName, "Ljava/lang/String;") \ int_field(HotSpotCompilationResult, entryBCI) \ oop_field(HotSpotCompilationResult, sites, "[Lcom/oracle/graal/api/code/CompilationResult$Site;") \ oop_field(HotSpotCompilationResult, exceptionHandlers, "[Lcom/oracle/graal/api/code/CompilationResult$ExceptionHandler;") \ @@ -162,9 +163,14 @@ oop_field(DebugInfo, bytecodePosition, "Lcom/oracle/graal/api/code/BytecodePosition;") \ oop_field(DebugInfo, registerRefMap, "Ljava/util/BitSet;") \ oop_field(DebugInfo, frameRefMap, "Ljava/util/BitSet;") \ + oop_field(DebugInfo, calleeSaveInfo, "Lcom/oracle/graal/api/code/RegisterSaveLayout;") \ end_class \ - start_class(GraalBitMap) \ - oop_field(GraalBitMap, words, "[J") \ + start_class(RegisterSaveLayout) \ + oop_field(RegisterSaveLayout, registers, "[Lcom/oracle/graal/api/code/Register;") \ + oop_field(RegisterSaveLayout, slots, "[I") \ + end_class \ + start_class(BitSet) \ + oop_field(BitSet, words, "[J") \ end_class \ start_class(BytecodeFrame) \ oop_field(BytecodeFrame, values, "[Lcom/oracle/graal/api/meta/Value;") \ @@ -197,7 +203,7 @@ end_class \ start_class(Value) \ oop_field(Value, kind, "Lcom/oracle/graal/api/meta/Kind;") \ - static_oop_field(Value, ILLEGAL, "Lcom/oracle/graal/api/meta/Value;"); \ + static_oop_field(Value, ILLEGAL, "Lcom/oracle/graal/api/meta/AllocatableValue;"); \ end_class \ start_class(RegisterValue) \ oop_field(RegisterValue, reg, "Lcom/oracle/graal/api/code/Register;") \ diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.cpp Sun Apr 28 22:52:12 2013 +0200 @@ -260,11 +260,16 @@ // This is pretty rare but this runtime patch is stressful to deoptimization // if we deoptimize here so force a deopt to stress the path. if (DeoptimizeALot) { - deopt_caller(); + static int deopts = 0; + // Alternate between deoptimizing and raising an error (which will also cause a deopt) + if (deopts++ % 2 == 0) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_OutOfMemoryError()); + } else { + deopt_caller(); + } } - JRT_END - - +JRT_END JRT_ENTRY(void, GraalRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) assert(klass->is_klass(), "not a class"); diff -r c21b1e5b515c -r 16a10b48e526 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Sun Apr 28 22:34:46 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.hpp Sun Apr 28 22:52:12 2013 +0200 @@ -82,9 +82,6 @@ // by Graal. #define GRAAL_STUBS(stub, last_entry) \ stub(register_finalizer) \ - stub(new_instance) \ - stub(new_array) \ - stub(new_multi_array) \ stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \ stub(unwind_exception_call) \ stub(OSR_migration_end) \ @@ -133,10 +130,6 @@ Register arg1 = noreg, Register arg2 = noreg, Register arg3 = noreg); // runtime entry points - static void new_instance(JavaThread* thread, Klass* klass); - static void new_array(JavaThread* thread, Klass* klass, jint length); - static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); - static void unimplemented_entry(JavaThread* thread, StubID id); static address exception_handler_for_pc(JavaThread* thread); @@ -164,6 +157,9 @@ static void log_object(JavaThread* thread, oop msg, jint flags); public: + static void new_instance(JavaThread* thread, Klass* klass); + static void new_array(JavaThread* thread, Klass* klass, jint length); + static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); // initialization static void initialize(BufferBlob* blob);